use std::future::Future;
use std::ptr::{null, null_mut, slice_from_raw_parts, slice_from_raw_parts_mut};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use futures::future::BoxFuture;
use futures::FutureExt;
use libusb_src::*;
use crate::define::{ConfigDescriptor, ControlTransferRequest, DeviceClass, DeviceDescriptor, Direction, PipConfig, Speed};
use crate::platform::{AsyncResult, DeviceCtx};
use crate::platform::libusb::{class_from_lib, config_descriptor_convert, status_to_result, ToLib};
use crate::platform::libusb::device_handle::{DeviceHandle, sync_cb, TransferDirection};
use crate::platform::libusb::endpoint::EndpointPipInImpl;
use crate::platform::libusb::errors::*;
use crate::platform::libusb::transfer::Transfer;
pub(crate) struct DeviceCtxImpl {
dev: Arc<Device>,
opened: Arc<Mutex<Option<OpenedDevice>>>,
}
struct OpenedDevice {
handle: Arc<DeviceHandle>,
}
impl OpenedDevice {
fn new(handle: DeviceHandle) -> Self {
Self {
handle: Arc::new(handle),
}
}
}
impl From<Device> for DeviceCtxImpl {
fn from(value: Device) -> Self {
Self {
dev: Arc::new(value),
opened: Arc::new(Mutex::new(None)),
}
}
}
impl From<DeviceHandle> for DeviceCtxImpl {
fn from(value: DeviceHandle) -> Self {
let dev = value.get_device();
Self {
dev: Arc::new(dev),
opened: Arc::new(Mutex::new(Some(OpenedDevice::new(value)))),
}
}
}
#[allow(unused)]
impl DeviceCtxImpl {
fn open(&self) -> Result {
open(&self.dev, &self.opened)?;
Ok(())
}
fn use_opened<F, O>(&self, f: F) -> Result<O>
where F: FnOnce(&mut OpenedDevice) -> Result<O> {
self.open()?;
let mut g = self.opened.lock().unwrap();
let h = g.as_mut().unwrap();
f(h)
}
fn open_endpoint(&self, endpoint: u8) -> Result {
let cfg = self.dev.get_active_config_descriptor(None)?;
let interface_num = endpoint_get_interface_num(&cfg, endpoint);
self.use_opened(|h| {
h.handle.claim_interface(interface_num)?;
Ok(())
})?;
Ok(())
}
fn async_handle<'a, T, F, O>(&self, f: F) -> impl Future<Output=Result<T>>
where F: FnOnce(Arc<Device>, Arc<DeviceHandle>) -> O + 'a + Send,
O: Future<Output=Result<T>> + Send + 'a
{
let opened = self.opened.clone();
let dev = self.dev.clone();
async move {
let handle = open(&dev, &opened)?;
f(dev, handle).await
}
}
fn async_handle2<'a, T, F, O>(&self, f: F) -> BoxFuture<'a, Result<T>>
where F: FnOnce(Arc<Device>, Arc<DeviceHandle>) -> O + 'a + Send,
O: Future<Output=Result<T>> + Send + 'a
{
let opened = self.opened.clone();
let dev = self.dev.clone();
async move {
let handle = open(&dev, &opened)?;
f(dev, handle).await
}.boxed()
}
fn get_configuration_descriptor(&self, index: u8) -> Result<ConfigDescriptor> {
let g = self.opened.lock().unwrap();
let handle = g.as_ref().map(|o| o.handle.as_ref());
self.dev.get_config_descriptor(index, handle)
}
}
fn open(dev: &Arc<Device>, opened: &Arc<Mutex<Option<OpenedDevice>>>) -> Result<Arc<DeviceHandle>> {
let g = opened.lock().unwrap();
if let Some(o) = g.as_ref() {
return Ok(o.handle.clone());
}
drop(g);
let h = dev.open()?;
let mut g = opened.lock().unwrap();
let o = OpenedDevice::new(h);
let h = o.handle.clone();
*g = Some(o);
Ok(h)
}
fn endpoint_get_interface_num(cfg: &ConfigDescriptor, endpoint: u8) -> u8 {
for alt in &cfg.interfaces {
for interface in &alt.alt_settings {
for ep in &interface.endpoints {
if ep.num == endpoint {
return interface.num;
}
}
}
}
0
}
fn open_endpoint(endpoint: u8, dev: &Arc<Device>, handle: &Arc<DeviceHandle>) -> Result {
let cfg = dev.get_active_config_descriptor(None)?;
let interface_num = endpoint_get_interface_num(&cfg, endpoint);
handle.claim_interface(interface_num)?;
Ok(())
}
macro_rules! async_opened {
($self:ident, $a: ident, $b: ident, $f: expr) => {
$self.async_handle2(move |$a, $b| {
async move {
$f
}
})
};
}
impl DeviceCtx for DeviceCtxImpl {
fn device_descriptor(&self) -> Result<DeviceDescriptor> {
self.dev.device_descriptor()
}
fn get_string_ascii(&self, index: u8) -> Result<String> {
self.use_opened(move |h| {
h.handle.get_string_descriptor_ascii(index)
})
}
fn device_class(&self) -> Result<DeviceClass> {
Ok(class_from_lib(self.device_descriptor()?.bDeviceClass))
}
fn device_subclass(&self) -> Result<DeviceClass> {
Ok(class_from_lib(self.device_descriptor()?.bDeviceSubClass))
}
fn device_protocol(&self) -> Result<DeviceClass> {
Ok(class_from_lib(self.device_descriptor()?.bDeviceProtocol))
}
fn config_list(&self) -> Result<Vec<ConfigDescriptor>> {
let des = self.device_descriptor()?;
let g = self.opened.lock().unwrap();
let handle = g.as_ref().map(|o| o.handle.as_ref());
let mut out = Vec::with_capacity(des.bNumConfigurations as usize);
for i in 0..des.bNumConfigurations{
let elem = self.dev.get_config_descriptor(i, handle)?;
out.push(elem);
}
Ok(out)
}
fn set_config_by_value(&self, config_value: u8) -> Result {
let cfg_old = self.get_active_configuration()?;
if cfg_old.value == config_value {
return Ok(());
}
self.use_opened(move |opened| {
match opened.handle.set_auto_detach_kernel_driver_with_guard(false) {
Ok(guard) => {
let mut interfaces = vec![];
for atl in &cfg_old.interfaces {
for interface in &atl.alt_settings {
interfaces.push(interface.num);
}
}
for i in interfaces {
match opened.handle.kernel_driver_active(i) {
Ok(active) => {
if active {
opened.handle.detach_kernel_driver(i)?;
}
}
Err(e) => {
match e {
Error::NotSupported => { break; }
_ => { return Err(e); }
}
}
}
let _ = opened.handle.release_interface(i);
}
drop(guard);
}
Err(e) => {
match e {
Error::NotSupported => {}
_ => { return Err(e); }
}
}
};
opened.handle.set_configuration(config_value)?;
Ok(())
})
}
fn serial_number(&self) -> Result<String> {
let des = self.device_descriptor()?;
self.get_string_ascii(des.iSerialNumber)
}
fn bus_number(&self) -> u8 {
unsafe {
libusb_get_bus_number(self.dev.0)
}
}
fn device_address(&self) -> u8 {
unsafe {
libusb_get_device_address(self.dev.0)
}
}
fn get_active_configuration(&self) -> Result<ConfigDescriptor> {
let g = self.opened.lock().unwrap();
let handle = g.as_ref().map(|o| o.handle.as_ref());
self.dev.get_active_config_descriptor(handle)
}
fn control_transfer_in(
&self, control_transfer_request: ControlTransferRequest, capacity: usize) -> BoxFuture<Result<Vec<u8>>> {
let rt: u8 = Direction::In.to_lib() | control_transfer_request.transfer_type.to_lib() | control_transfer_request.recipient.to_lib();
async_opened!(self, _dev, handle, {
let tran = handle.control_transfer(
TransferDirection::In { len: capacity }, rt as _,
control_transfer_request.request,
control_transfer_request.value,
control_transfer_request.index,
control_transfer_request.timeout).await?;
Ok(tran.control_transfer_get_data().to_vec())
})
}
fn control_transfer_out(
&self,
control_transfer_request: ControlTransferRequest, data: &[u8]) -> AsyncResult<usize> {
let rt: u8 = Direction::Out.to_lib() | control_transfer_request.transfer_type.to_lib() | control_transfer_request.recipient.to_lib();
let data = data.to_vec();
async_opened!(self, _dev, handle, {
let tran = handle.control_transfer(
TransferDirection::Out { data }, rt,
control_transfer_request.request,
control_transfer_request.value,
control_transfer_request.index,
control_transfer_request.timeout).await?;
Ok(tran.actual_length())
})
}
fn bulk_transfer_in(&self, endpoint: u8, capacity: usize, timeout: Duration) -> AsyncResult<Vec<u8>> {
async_opened!(self, dev, handle, {
open_endpoint(endpoint, &dev, &handle)?;
let tran = handle.bulk_transfer(
TransferDirection::In { len: capacity },
endpoint, timeout, false).await?;
Ok(tran.data[..tran.actual_length()].to_vec())
})
}
fn bulk_transfer_out(&self, endpoint: u8, data: &[u8], timeout: Duration) -> AsyncResult<usize> {
let data = data.to_vec();
async_opened!(self, dev, handle, {
open_endpoint(endpoint, &dev, &handle)?;
let tran = handle.bulk_transfer(
TransferDirection::Out { data },
endpoint, timeout, false).await?;
Ok(tran.actual_length())
})
}
fn interrupt_transfer_in(&self, endpoint: u8, capacity: usize, timeout: Duration) -> AsyncResult<Vec<u8>> {
async_opened!(self, dev, handle, {
open_endpoint(endpoint, &dev, &handle)?;
let tran = handle.bulk_transfer(
TransferDirection::In { len: capacity },
endpoint, timeout, true).await?;
Ok(tran.data[..tran.actual_length()].to_vec())
})
}
fn interrupt_transfer_out(&self, endpoint: u8, data: &[u8], timeout: Duration) -> AsyncResult<usize> {
let data = data.to_vec();
async_opened!(self, dev, handle, {
open_endpoint(endpoint, &dev, &handle)?;
let tran = handle.bulk_transfer(
TransferDirection::Out { data },
endpoint, timeout, true).await?;
Ok(tran.actual_length())
})
}
fn iso_transfer_in(&self, endpoint: u8, num_iso_packages: usize, package_capacity: usize, timeout: Duration) -> AsyncResult<Vec<Vec<u8>>> {
async_opened!(self, dev, handle, {
open_endpoint(endpoint, &dev, &handle)?;
let tran = handle.iso_transfer(
TransferDirection::In { len: num_iso_packages * package_capacity },
endpoint, num_iso_packages,timeout).await?;
let mut packs = Vec::with_capacity(num_iso_packages);
unsafe{
let packs_raw = &*slice_from_raw_parts((*tran.ptr).iso_packet_desc.as_ptr(), num_iso_packages);
let mut begin = 0;
for raw in packs_raw{
status_to_result(raw.status)?;
packs.push(tran.data[begin.. begin + raw.actual_length as usize].to_vec());
begin += raw.length as usize;
}
}
Ok(packs)
})
}
fn iso_transfer_out(&self, endpoint: u8, mut packs: Vec<Vec<u8>>, timeout: Duration) -> AsyncResult<Vec<usize>> {
async_opened!(self, dev, handle, {
open_endpoint(endpoint, &dev, &handle)?;
let mut out = vec![0usize; packs.len()];
let pack_lens: Vec<_> = packs.iter().map(|o|o.len()).collect();
let num_iso_packets = pack_lens.len();
let mut data = vec![];
while let Some(mut o) = packs.pop(){
data.append(&mut o);
}
unsafe {
let tran = Transfer::iso_transfer(endpoint, num_iso_packets as _, sync_cb, TransferDirection::Out{ data }, timeout);
let mut packs_raw = &mut*slice_from_raw_parts_mut((*tran.ptr).iso_packet_desc.as_mut_ptr(), num_iso_packets);
for (i,raw) in packs_raw.iter_mut().enumerate(){
raw.length = pack_lens[i] as _;
}
let tran_new = handle.do_sync_transfer(tran).await?;
packs_raw = &mut*slice_from_raw_parts_mut((*tran_new.ptr).iso_packet_desc.as_mut_ptr(), num_iso_packets);
for (i,raw) in packs_raw.iter_mut().enumerate(){
out[i] = raw.actual_length as _;
}
}
Ok(out)
})
}
fn bulk_transfer_pip_in(&self, endpoint: u8, pip_config: PipConfig) -> Result<EndpointPipInImpl> {
let handle = open(&self.dev, &self.opened)?;
self.open_endpoint(endpoint)?;
EndpointPipInImpl::new(&handle, endpoint, pip_config)
}
}
pub(crate) struct Device(*mut libusb_device);
unsafe impl Send for Device {}
unsafe impl Sync for Device {}
#[allow(unused)]
impl Device {
pub fn open(&self) -> Result<DeviceHandle> {
unsafe {
let mut ptr = null_mut();
check_err(libusb_open(self.0, &mut ptr))?;
let h = DeviceHandle::from(ptr);
Ok(h)
}
}
fn speed(&self) -> Result<Speed> {
unsafe {
let r = check_err(libusb_get_device_speed(self.0))?;
Ok(match r {
LIBUSB_SPEED_LOW => Speed::Low,
LIBUSB_SPEED_FULL => Speed::Full,
LIBUSB_SPEED_HIGH => Speed::High,
LIBUSB_SPEED_SUPER => Speed::Super,
LIBUSB_SPEED_SUPER_PLUS => Speed::SuperPlus,
_ => Speed::Unknown
})
}
}
pub fn get_max_packet_size(&self, endpoint: usize) -> Result<usize> {
unsafe {
let r = check_err(libusb_get_max_packet_size(self.0, endpoint as _))?;
Ok(r as _)
}
}
fn device_descriptor(&self) -> Result<DeviceDescriptor> {
let out = unsafe {
let mut des = libusb_device_descriptor::default();
libusb_get_device_descriptor(self.0, &mut des);
DeviceDescriptor {
bLength: des.bLength,
bDescriptorType: des.bDescriptorType,
bcdUSB: des.bcdUSB,
bDeviceClass: des.bDeviceClass,
bDeviceSubClass: des.bDeviceSubClass,
bDeviceProtocol: des.bDeviceProtocol,
bMaxPacketSize0: des.bMaxPacketSize0,
idVendor: des.idVendor,
idProduct: des.idProduct,
bcdDevice: des.bcdDevice,
iManufacturer: des.iManufacturer,
iProduct: des.iProduct,
iSerialNumber: des.iSerialNumber,
bNumConfigurations: des.bNumConfigurations,
}
};
Ok(out)
}
pub fn get_active_config_descriptor(&self, handle: Option<&DeviceHandle>) -> Result<ConfigDescriptor> {
let speed = self.speed()?;
unsafe {
let mut raw = null();
check_err(libusb_get_active_config_descriptor(self.0, &mut raw))?;
let cfg = config_descriptor_convert(raw, handle, speed);
libusb_free_config_descriptor(raw);
Ok(cfg)
}
}
pub fn get_config_descriptor(&self, index: u8, handle: Option<&DeviceHandle>) -> Result<ConfigDescriptor> {
let speed = self.speed()?;
unsafe {
let mut raw = null();
check_err(libusb_get_config_descriptor(self.0, index, &mut raw))?;
let cfg = config_descriptor_convert(raw, handle, speed);
libusb_free_config_descriptor(raw);
Ok(cfg)
}
}
}
impl From<*mut libusb_device> for Device {
fn from(value: *mut libusb_device) -> Self {
Self(value)
}
}
impl Drop for Device {
fn drop(&mut self) {
unsafe {
libusb_unref_device(self.0)
}
}
}