#![allow(unused_unsafe)]
use crate::libusb::device_handle::DeviceHandle;
use crate::libusb::error::Error;
use core::convert::TryInto;
use std::convert::TryFrom;
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum Status {
Completed = 0,
Error = 1,
TimedOut = 2,
Cancelled = 3,
Stall = 4,
NoDevice = 5,
Overflow = 6,
}
impl Status {
pub fn from_i32(i: i32) -> Option<Status> {
match i {
0 => Some(Status::Completed),
1 => Some(Status::Error),
2 => Some(Status::TimedOut),
3 => Some(Status::Cancelled),
4 => Some(Status::Stall),
5 => Some(Status::NoDevice),
6 => Some(Status::Overflow),
_ => None,
}
}
}
impl Status {
pub fn as_error(self) -> Result<(), Error> {
match self {
Status::Completed => Ok(()),
Status::Error | Status::Cancelled => Err(Error::Io),
Status::TimedOut => Err(Error::Timeout),
Status::Stall => Err(Error::Pipe),
Status::NoDevice => Err(Error::NoDevice),
Status::Overflow => Err(Error::Overflow),
}
}
}
impl From<Status> for i32 {
fn from(s: Status) -> Self {
s as i32
}
}
impl TryFrom<i32> for Status {
type Error = ();
fn try_from(value: i32) -> Result<Self, ()> {
Self::from_i32(value).ok_or(())
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum TransferType {
Control = 0,
Isochronous = 1,
Bulk = 2,
Interrupt = 3,
Stream = 4,
}
impl From<TransferType> for u8 {
fn from(t: TransferType) -> Self {
t as u8
}
}
impl TryFrom<u8> for TransferType {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(TransferType::Control),
1 => Ok(TransferType::Isochronous),
2 => Ok(TransferType::Bulk),
3 => Ok(TransferType::Interrupt),
4 => Ok(TransferType::Stream),
_ => Err(()),
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub enum Flag {
ShortNotOk = 0,
FreeBuffer = 1,
FreeTransfer = 2,
AddZeroPacket = 3,
}
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Hash)]
pub struct Flags(u8);
impl Flags {
pub const fn new(flags: u8) -> Flags {
Flags(flags)
}
pub const fn inner(self) -> u8 {
self.0
}
pub fn get(self, flag: Flag) -> bool {
self.0 & (1_u8 << (flag as u8)) != 0
}
pub fn set(&mut self, flag: Flag) {
self.0 |= 1_u8 << (flag as u8)
}
pub fn clear(&mut self, flag: Flag) {
self.0 &= !(1_u8 << (flag as u8))
}
}
impl From<Flags> for u8 {
fn from(f: Flags) -> Self {
f.inner()
}
}
impl From<u8> for Flags {
fn from(u: u8) -> Self {
Flags::new(u)
}
}
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct ControlSetup {
pub request_type: u8,
pub request: u8,
pub value: u16,
pub index: u16,
pub len: u16,
}
impl ControlSetup {
pub const SIZE: usize = core::mem::size_of::<Self>();
pub fn serialize(self, buf: &mut [u8]) {
assert!(buf.len() >= Self::SIZE, "ControlSetup buf too small");
let le = ControlSetup {
request_type: self.request_type,
request: self.request,
value: self.value.to_le(),
index: self.index.to_le(),
len: self.len.to_le(),
};
unsafe { core::ptr::write_unaligned(buf.as_mut_ptr() as *mut Self, le) }
}
pub fn deserialize(buf: &[u8]) -> ControlSetup {
assert!(buf.len() >= Self::SIZE, "ControlSetup buf too small");
let le = unsafe { core::ptr::read_unaligned(buf.as_ptr() as *const Self) };
ControlSetup {
request_type: le.request_type,
request: le.request,
value: u16::from_le(le.value),
index: u16::from_le(le.index),
len: u16::from_le(le.len),
}
}
}
#[derive(Debug)]
pub struct Transfer(core::ptr::NonNull<libusb1_sys::libusb_transfer>);
impl Transfer {
pub fn new(iso_packets: usize) -> Transfer {
Transfer(
core::ptr::NonNull::new(unsafe {
libusb1_sys::libusb_alloc_transfer(iso_packets as i32)
})
.expect("null libusb transfer ptr"),
)
}
pub fn libusb_inner(&self) -> core::ptr::NonNull<libusb1_sys::libusb_transfer> {
self.0
}
pub fn libusb_ref(&self) -> &libusb1_sys::libusb_transfer {
unsafe { self.0.as_ref() }
}
pub fn clear_flags(&mut self) {
self.libusb_mut().flags = 0;
}
pub fn set_device(&mut self, device: &DeviceHandle) {
self.libusb_mut().dev_handle = device.inner().as_ptr();
}
pub fn fill_control(&mut self, device: &DeviceHandle) {
let inner = self.libusb_mut();
inner.transfer_type = TransferType::Control.into();
inner.endpoint = 0;
inner.num_iso_packets = 0;
inner.dev_handle = device.inner().as_ptr();
}
pub fn set_num_iso_packets(&mut self, num: usize) {
self.libusb_mut().num_iso_packets = num as i32;
}
pub fn get_num_iso_packets(&self) -> usize {
self.libusb_ref().num_iso_packets as usize
}
pub fn set_callback(&mut self, new_callback: libusb1_sys::libusb_transfer_cb_fn) {
self.libusb_mut().callback = new_callback
}
pub fn get_type(&self) -> TransferType {
self.libusb_ref()
.transfer_type
.try_into()
.expect("invalid transfer type")
}
pub fn set_type(&mut self, transfer_type: TransferType) {
self.libusb_mut().transfer_type = transfer_type.into();
}
pub fn get_callback(&self) -> libusb1_sys::libusb_transfer_cb_fn {
self.libusb_ref().callback
}
pub fn set_endpoint(&mut self, new_endpoint: u8) {
self.libusb_mut().endpoint = new_endpoint;
}
pub fn get_endpoint(&self) -> u8 {
self.libusb_ref().endpoint
}
pub fn try_actual_length(&self) -> Result<i32, Error> {
match self.status() {
Some(status) => match status {
Status::Completed => Ok(self.actual_length()),
Status::Error | Status::Cancelled => Err(Error::Io),
Status::TimedOut => Err(Error::Timeout),
Status::Stall => Err(Error::Pipe),
Status::NoDevice => Err(Error::NoDevice),
Status::Overflow => Err(Error::Overflow),
},
None => Err(Error::Other),
}
}
pub fn actual_length(&self) -> i32 {
self.libusb_ref().actual_length
}
pub fn libusb_mut(&mut self) -> &mut libusb1_sys::libusb_transfer {
unsafe { self.0.as_mut() }
}
pub fn set_buffer(&mut self, buffer: *mut u8, len: usize) {
self.libusb_mut().buffer = buffer;
self.libusb_mut().length = len as i32;
}
pub unsafe fn submit(&self) -> Result<(), Error> {
try_unsafe!(libusb1_sys::libusb_submit_transfer(self.0.as_ptr()));
Ok(())
}
pub unsafe fn cancel(&self) -> Result<(), Error> {
try_unsafe!(libusb1_sys::libusb_cancel_transfer(self.0.as_ptr()));
Ok(())
}
pub fn get_flags(&self) -> Flags {
self.libusb_ref().flags.into()
}
pub fn set_flags(&mut self, new_flags: Flags) {
self.libusb_mut().flags = new_flags.inner()
}
pub fn set_stream_id(&mut self, id: u32) {
unsafe { libusb1_sys::libusb_transfer_set_stream_id(self.0.as_ptr(), id) }
}
pub fn get_stream_id(&self) -> u32 {
unsafe { libusb1_sys::libusb_transfer_get_stream_id(self.0.as_ptr()) }
}
pub unsafe fn from_libusb(ptr: core::ptr::NonNull<libusb1_sys::libusb_transfer>) -> Transfer {
Transfer(ptr)
}
pub fn set_timeout(&mut self, timeout: core::time::Duration) {
self.libusb_mut().timeout = timeout.as_millis().try_into().unwrap_or(u32::MAX)
}
pub fn status(&self) -> Option<Status> {
self.libusb_ref().status.try_into().ok()
}
pub fn set_user_data<T>(&mut self, user_data: *mut T) {
self.libusb_mut().user_data = user_data as *mut _
}
pub unsafe fn cast_userdata_ref<T>(&self) -> &T {
unsafe { &*(self.libusb_ref().user_data as *const T) }
}
pub unsafe fn cast_userdata_mut<T>(&mut self) -> &mut T {
unsafe { &mut *(self.libusb_ref().user_data as *mut T) }
}
}
impl Drop for Transfer {
fn drop(&mut self) {
unsafe { libusb1_sys::libusb_free_transfer(self.0.as_ptr()) }
}
}
pub struct TransferWithBuf<'a> {
transfer_buf: &'a mut [u8],
transfer: Transfer,
}
impl<'a> TransferWithBuf<'a> {
pub fn new(mut transfer: Transfer, transfer_buf: &'a mut [u8]) -> Self {
transfer.set_buffer(transfer_buf.as_mut_ptr(), transfer_buf.len());
Self {
transfer_buf,
transfer,
}
}
pub fn set_buf(&mut self, new_buf: &'a mut [u8]) -> &'a mut [u8] {
self.transfer
.set_buffer(new_buf.as_mut_ptr(), new_buf.len());
core::mem::replace(&mut self.transfer_buf, new_buf)
}
pub fn buf_mut(&mut self) -> &mut [u8] {
self.transfer_buf
}
pub fn buf_ref(&self) -> &[u8] {
self.transfer_buf
}
pub fn transfer_ref(&self) -> &Transfer {
&self.transfer
}
pub fn transfer_mut(&mut self) -> &mut Transfer {
&mut self.transfer
}
pub fn control_data_ref(&self) -> &[u8] {
&self.transfer_buf[ControlSetup::SIZE..]
}
pub fn control_data_mut(&mut self) -> &mut [u8] {
&mut self.transfer_buf[ControlSetup::SIZE..]
}
pub fn set_control_setup(&mut self, handle: &DeviceHandle, control_setup: ControlSetup) {
assert!(
self.transfer_buf.len() >= ControlSetup::SIZE,
"buf smaller than a ControlSetup, maybe missing it?"
);
control_setup.serialize(self.transfer_buf);
self.transfer.fill_control(handle);
}
}