eusb 0.4.2

Rust library for accessing USB devices.
Documentation
use std::ptr::{null_mut};
use std::sync::Arc;
use std::time::Duration;
use log::trace;
use libusb_src::*;
use crate::adaptor::{EndpointDirection, IRequest, RequestParamControlTransfer};
use crate::define::*;
use crate::error::*;
use super::device::CtxDeviceImpl;

pub struct Request {
    pub(crate) ptr: Transfer,
    pub(crate) buff: Vec<u8>,
}

#[derive(Copy, Clone)]
pub(crate) struct Transfer(pub(crate) *mut libusb_transfer);

unsafe impl Sync for Transfer {}

unsafe impl Send for Transfer {}


pub trait ToLib: Sized {
    fn to_lib(self) -> u32;
}


impl ToLib for EndpointDirection<'_> {
    fn to_lib(self) -> u32 {
        (match self {
            EndpointDirection::In { .. } => LIBUSB_ENDPOINT_IN,
            EndpointDirection::Out { .. } => LIBUSB_ENDPOINT_OUT,
        }) as u32
    }
}

impl ToLib for UsbControlTransferType {
    fn to_lib(self) -> u32 {
        let t: u8 = match self {
            UsbControlTransferType::Standard => LIBUSB_REQUEST_TYPE_STANDARD,
            UsbControlTransferType::Class => LIBUSB_REQUEST_TYPE_CLASS,
            UsbControlTransferType::Vendor => LIBUSB_REQUEST_TYPE_VENDOR,
            UsbControlTransferType::Reserved => LIBUSB_REQUEST_TYPE_RESERVED,
        };
        t as _
    }
}

impl ToLib for UsbControlRecipient {
    fn to_lib(self) -> u32 {
        let t: u8 = match self {
            UsbControlRecipient::Device => LIBUSB_RECIPIENT_DEVICE,
            UsbControlRecipient::Endpoint => LIBUSB_RECIPIENT_ENDPOINT,
            UsbControlRecipient::Other => LIBUSB_RECIPIENT_OTHER,
            UsbControlRecipient::DefaultInterface
            | UsbControlRecipient::SpecifiedInterface => LIBUSB_RECIPIENT_INTERFACE,
        };
        t as _
    }
}
impl ToLib for EndpointDescriptor {
    fn to_lib(self) -> u32 {
        match self.direction {
            Direction::In  => (LIBUSB_ENDPOINT_IN as u32 ) | (self.num as u32),
            Direction::Out => (LIBUSB_ENDPOINT_OUT as u32) | (self.num as u32),
        }
    }
}

impl Request {
    pub(crate) fn new(
        iso_packets: u32,
        data:Vec<u8>,
    ) -> Result<Self> {
        let ptr = unsafe {
            let t = libusb_alloc_transfer(iso_packets as _);
            if t.is_null() {
                return Err(Error::Other("Alloc transfer fail".to_string()));
            }
            Ok(t)
        }?;

        Ok(Self {
            ptr: Transfer(ptr),
            buff: data,
        })
    }

    pub(crate) fn control(
        device: &Arc<CtxDeviceImpl>,
        request: RequestParamControlTransfer,
        direction: EndpointDirection,
    ) -> Result<Self> {
        let data_len = match direction {
            EndpointDirection::In { capacity } => capacity,
            EndpointDirection::Out { src } => { src.len() as _ }
        };
        let data = vec![0; LIBUSB_CONTROL_SETUP_SIZE + (data_len)];
        let mut s = Self::new(0, data)?;

        if let EndpointDirection::Out { src } = direction {
            for i in 0..src.len() {
                s.buff[i + LIBUSB_CONTROL_SETUP_SIZE] = src[i];
            }
        }

        unsafe {
            let buf_ptr = s.buff.as_mut_ptr();
            let rt: u32 = direction.to_lib() | request.transfer_type.to_lib() | request.recipient.to_lib();

            libusb_fill_control_setup(
                buf_ptr,
                rt as u8,
                request.request,
                request.value,
                request.index,
                data_len as u16);
            let handle = device.get_handle()?;


            libusb_fill_control_transfer(
                s.ptr.0,
                handle.0,
                buf_ptr,
                Self::empty_cb,
                null_mut(),
                request.timeout.as_millis() as _,
            );
        }

        Ok(s)
    }


    pub(crate) fn bulk(
        device: &Arc<CtxDeviceImpl>,
        endpoint: EndpointDescriptor,
        data:Vec<u8>,
        timeout: Duration
    ) -> Result<Self> {

        let mut s = Self::new(0, data)?;
        let handle = device.get_handle()?.0;
        unsafe {
            let buf_ptr = s.buff.as_mut_ptr();

            libusb_fill_bulk_transfer(
                s.ptr.0,
                handle,
                endpoint.to_lib() as _,
                buf_ptr,
                s.buff.len() as _,
                Self::empty_cb,
                null_mut(),
                timeout.as_millis() as _,
            );
        }
        Ok(s)
    }
    pub(crate) fn interrupt(
        device: &Arc<CtxDeviceImpl>,
        endpoint: EndpointDescriptor,
        data:Vec<u8>,
        timeout: Duration
    ) -> Result<Self> {

        let mut s = Self::new(0, data)?;
        let handle = device.get_handle()?.0;
        unsafe {
            let buf_ptr = s.buff.as_mut_ptr();

            libusb_fill_interrupt_transfer(
                s.ptr.0,
                handle,
                endpoint.to_lib() as _,
                buf_ptr,
                s.buff.len() as _,
                Self::empty_cb,
                null_mut(),
                timeout.as_millis() as _,
            );
        }
        Ok(s)
    }

    extern "system" fn empty_cb(_: *mut libusb_transfer) {}
}

impl IRequest for Request {
    fn data(&mut self) -> &mut [u8] {
        unsafe {
            let len = (*self.ptr.0).actual_length as usize;

            if (*self.ptr.0).transfer_type == LIBUSB_TRANSFER_TYPE_CONTROL {
                let s = self.buff.as_mut_slice();
                return &mut s[LIBUSB_CONTROL_SETUP_SIZE..LIBUSB_CONTROL_SETUP_SIZE + len];
            }

            return &mut self.buff.as_mut_slice()[0..len];
        }
    }
}

impl Drop for Request {
    fn drop(&mut self) {
        unsafe {
            libusb_free_transfer(self.ptr.0);
            trace!("Transfer release");
        }
    }
}