eusb 1.0.5

Rust library for accessing USB devices.
use std::collections::HashSet;
use std::ffi::CStr;
use std::future::Future;
use std::pin::Pin;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex, RwLock};
use std::task::{Context, Poll, Waker};
use std::time::Duration;
use log::{debug, trace};
use libusb_src::*;
use crate::manager::Manager;
use crate::platform::libusb::device::Device;
use crate::platform::libusb::transfer::Transfer;
use super::errors::*;
pub(crate) use super::transfer::TransferDirection;

pub(crate) struct DeviceHandle {
    pub(crate) ptr: *mut libusb_device_handle,
    claimed: RwLock<HashSet<u8>>,
}

unsafe impl Send for DeviceHandle {}

unsafe impl Sync for DeviceHandle {}

impl From<*mut libusb_device_handle> for DeviceHandle {
    fn from(value: *mut libusb_device_handle) -> Self {
        Manager::get().platform.open_device();
        Self { ptr: value, claimed: RwLock::new(HashSet::new()) }
    }
}

impl Drop for DeviceHandle {
    fn drop(&mut self) {
        unsafe {
            if !self.ptr.is_null() {
                Manager::get().platform.close_device();
                let g = self.claimed.read().unwrap();
                for one in g.iter() {
                    let _ = self.release_interface(*one);
                }
                debug!("device close");
                libusb_close(self.ptr);
            }
        }
    }
}

#[allow(unused)]
impl DeviceHandle {
    pub fn claim_interface(&self, interface_number: u8) -> Result {
        unsafe {
            {
                let g = self.claimed.read().unwrap();
                if g.contains(&interface_number){
                    return Ok(())
                }
            }

            trace!("claim interface [{:3}] begin", interface_number);
            check_err(libusb_claim_interface(self.ptr, interface_number as _))?;
            let mut g = self.claimed.write().unwrap();
            g.insert(interface_number);
            debug!("claim interface [{:3}]", interface_number);
            Ok(())
        }
    }
    pub fn release_interface(&self, interface_number: u8) -> Result {
        unsafe {
            check_err(libusb_release_interface(self.ptr, interface_number as _))?;
            debug!("release interface [{:3}]", interface_number);
            Ok(())
        }
    }
    pub fn get_configuration(&self) -> Result<u8> {
        unsafe {
            let mut c = 0;
            check_err(libusb_get_configuration(self.ptr, &mut c))?;
            Ok(c as _)
        }
    }

    pub fn set_configuration(&self, config_value: u8) -> Result {
        unsafe {
            check_err(libusb_set_configuration(self.ptr, config_value as _))?;
            Ok(())
        }
    }
    pub fn clear_halt(&self, endpoint: u8) -> Result {
        unsafe {
            check_err(libusb_clear_halt(self.ptr, endpoint as _))?;
            Ok(())
        }
    }

    pub fn get_string_descriptor_ascii(&self, index: u8) -> Result<String> {
        unsafe {
            let mut buff = [0u8; 1024];
            let _ = check_err(libusb_get_string_descriptor_ascii(self.ptr, index, buff.as_mut_ptr(), 1024))?;
            let c = CStr::from_ptr(buff.as_ptr() as _);
            let out = c.to_string_lossy().to_string();
            Ok(out)
        }
    }

    pub fn set_auto_detach_kernel_driver(&self, enable: bool)->Result{
        unsafe {
            check_err( libusb_set_auto_detach_kernel_driver(self.ptr,if enable { 1 } else { 0 }))?;
        }
        Ok(())
    }
    pub fn set_auto_detach_kernel_driver_with_guard(&self, enable: bool)->Result<AutoDetachKernelDriverGuard>{
        unsafe {
            check_err( libusb_set_auto_detach_kernel_driver(self.ptr,if enable { 1 } else { 0 }))?;
        }
        Ok(AutoDetachKernelDriverGuard{dev: self.ptr})
    }

    pub fn kernel_driver_active(&self, interface_number: u8)->Result<bool>{
        let r = unsafe {
            check_err(libusb_kernel_driver_active(self.ptr,interface_number as _))?
        };
        Ok(r == 1)
    }

    pub fn detach_kernel_driver(&self, interface_number: u8)->Result{
        unsafe {
            check_err(libusb_detach_kernel_driver(self.ptr,interface_number as _))?;
        }
        Ok(())
    }

    pub fn get_device(&self) -> Device {
        unsafe {
            let mut dev = libusb_get_device(self.ptr);
            dev = libusb_ref_device(dev);
            dev
        }.into()
    }

    pub async fn do_sync_transfer(&self, mut transfer: Transfer) -> Result<Transfer> {
        unsafe {
            transfer.set_handle(self.ptr);
            let future = SyncTransfer::new();
            let b = Arc::into_raw(future.inner.clone());
            transfer.set_user_data(b as _);
            let wp = SyncTransferInnerWrapper(b);
            transfer.submit()?;
            future.await;
            Arc::from_raw(wp.0);
            transfer.result()?;
            Ok(transfer)
        }
    }

    pub async fn control_transfer(&self, direction: TransferDirection, request_type: u8, request: u8, value: u16, index: u16, timeout: Duration) -> Result<Transfer> {
        unsafe {
            let transfer = Transfer::control_transfer(
                sync_cb, direction, request_type, request, value, index, timeout);

            self.do_sync_transfer(transfer).await
        }
    }
    pub async fn bulk_transfer(&self, direction: TransferDirection, endpoint: u8, timeout: Duration, is_interrupt: bool) -> Result<Transfer> {
        unsafe {
            let transfer = Transfer::bulk_transfer(endpoint, sync_cb, direction, timeout);
            (*transfer.ptr).transfer_type = if is_interrupt {
                LIBUSB_TRANSFER_TYPE_INTERRUPT
            } else {
                LIBUSB_TRANSFER_TYPE_BULK
            };
            self.do_sync_transfer(transfer).await
        }
    }
    pub async fn iso_transfer(&self,direction: TransferDirection, endpoint: u8, num_iso_packets: usize, timeout: Duration) -> Result<Transfer> {
        unsafe {
            let transfer = Transfer::iso_transfer(endpoint, num_iso_packets as _, sync_cb, direction, timeout);
            self.do_sync_transfer(transfer).await
        }
    }
}

pub(crate) extern "system" fn sync_cb(transfer: *mut libusb_transfer) {
    unsafe {
        let sync = (*transfer).user_data as *const SyncTransferInner;
        (*sync).is_ok.store(true, Ordering::SeqCst);
        let wake = {
            let g = (*sync).waker.lock().unwrap();
            g.as_ref().cloned()
        };
        if let Some(w) = wake {
            w.wake();
        }
    }
}

pub(crate) struct AutoDetachKernelDriverGuard{
    dev: *mut libusb_device_handle
}

impl Drop for AutoDetachKernelDriverGuard {
    fn drop(&mut self) {
        unsafe {
            libusb_set_auto_detach_kernel_driver(self.dev, 1);
        }
    }
}


struct SyncTransfer {
    inner: Arc<SyncTransferInner>,
}


struct SyncTransferInner {
    is_ok: AtomicBool,
    waker: Mutex<Option<Waker>>,
}
struct SyncTransferInnerWrapper(*const SyncTransferInner);
unsafe impl Send for SyncTransferInnerWrapper{}


impl SyncTransfer {
    fn new() -> Self {
        Self {
            inner: Arc::new(SyncTransferInner {
                is_ok: AtomicBool::new(false),
                waker: Mutex::new(None),
            })
        }
    }
}

impl Future for SyncTransfer {
    type Output = ();

    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
        if self.inner.is_ok.load(Ordering::SeqCst) {
            Poll::Ready(())
        } else {
            {
                let mut g = self.inner.waker.lock().unwrap();
                *g = Some(cx.waker().clone());
            }
            Poll::Pending
        }
    }
}