diff --git a/Cargo.toml b/Cargo.toml index 1a3283e..8cae9a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,17 @@ name = "cross_usb" version = "0.1.0" authors = ["G2-Games "] +repository = "https://github.com/G2-Games/cross-usb" +documentation = "https://docs.rs/cross_usb" + +description = """ +A a Rust USB library which works seamlessly across both native and WASM targets +""" + +keywords = ["usb", "wasm", "web-usb"] +categories = ["wasm", "web-programming", "hardware-support"] +readme = "README.md" +license = "AGPL-3.0" edition = "2021" [lib] @@ -28,6 +39,7 @@ features = [ "UsbControlTransferParameters", "UsbDeviceRequestOptions", "UsbInTransferResult", + "UsbOutTransferResult", "Storage" ] diff --git a/src/backend/native.rs b/src/backend/native.rs index 266c005..13460a5 100644 --- a/src/backend/native.rs +++ b/src/backend/native.rs @@ -12,7 +12,6 @@ pub struct UsbInterface { interface: nusb::Interface, } -/// Gets a single device from the VendorID and ProductID pub async fn get_device(vendor_id: u16, product_id: u16) -> Result> { let devices = nusb::list_devices().unwrap(); @@ -100,8 +99,8 @@ impl<'a> Interface<'a> for UsbInterface { Ok(self.interface.bulk_in(endpoint, request_buffer).await.into_result()?) } - async fn bulk_out(&self, endpoint: u8, data: Vec) -> Result> { - match self.interface.bulk_out(endpoint, data).await.into_result() { + async fn bulk_out(&self, endpoint: u8, data: &[u8]) -> Result> { + match self.interface.bulk_out(endpoint, data.to_vec()).await.into_result() { Ok(len) => Ok(len.actual_length()), Err(e) => Err(e.into()) } diff --git a/src/backend/wasm.rs b/src/backend/wasm.rs index 16f2279..1a8c1a0 100644 --- a/src/backend/wasm.rs +++ b/src/backend/wasm.rs @@ -10,6 +10,7 @@ use web_sys::{ UsbInterface as WasmUsbInterface, UsbControlTransferParameters, UsbInTransferResult, + UsbOutTransferResult, UsbRecipient, UsbRequestType, UsbDeviceRequestOptions, @@ -30,7 +31,6 @@ pub struct UsbInterface { device: WasmUsbDevice, } -/// Gets a single device from the VendorID and ProductID #[wasm_bindgen] pub async fn get_device(vendor_id: u16, product_id: u16) -> Result { let window = web_sys::window().unwrap(); @@ -136,9 +136,8 @@ impl<'a> Interface<'a> for UsbInterface { let length = data.length; let params: UsbControlTransferParameters = data.into(); - let result = JsFuture::from(Promise::resolve( - &self.device.control_transfer_in(¶ms, length) - )).await; + let promise = Promise::resolve(&self.device.control_transfer_in(¶ms, length)); + let result = JsFuture::from(promise).await; let transfer_result: UsbInTransferResult = match result { Ok(res) => res.into(), @@ -169,12 +168,40 @@ impl<'a> Interface<'a> for UsbInterface { } } - async fn bulk_in(&self, _endpoint: u8, _length: usize) -> Result, Box> { - todo!() + async fn bulk_in(&self, endpoint: u8, length: usize) -> Result, Box> { + let promise = Promise::resolve(&self.device.transfer_in(endpoint, length as u32)); + + let result = JsFuture::from(promise).await; + + let transfer_result: UsbInTransferResult = match result { + Ok(res) => res.into(), + Err(err) => return Err(format!("Error {:?}", err).into()), + }; + + let data = match transfer_result.data() { + Some(res) => res.buffer(), + None => return Err("No data returned".into()), + }; + + let array = Uint8Array::new(&data); + + Ok(array.to_vec()) } - async fn bulk_out(&self, _endpoint: u8, _data: Vec) -> Result> { - todo!() + async fn bulk_out(&self, endpoint: u8, data: &[u8]) -> Result> { + let array = Uint8Array::from(data); + let array_obj = Object::try_from(&array).unwrap(); + + let promise = Promise::resolve(&self.device.transfer_out_with_buffer_source(endpoint, array_obj)); + + let result = JsFuture::from(promise).await; + + let transfer_result: UsbOutTransferResult = match result { + Ok(res) => res.into(), + Err(err) => return Err(format!("Error {:?}", err).into()), + }; + + Ok(transfer_result.bytes_written() as usize) } } diff --git a/src/lib.rs b/src/lib.rs index d9f7e2f..6bc343a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,3 +7,7 @@ pub mod context; #[cfg(target_family = "wasm")] #[path = "./backend/wasm.rs"] pub mod context; + +/// Gets a single device from the VendorID and ProductID +#[doc(inline)] +pub use crate::context::get_device; diff --git a/src/usb.rs b/src/usb.rs index 9bdb820..826960f 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -37,16 +37,19 @@ pub trait Device { /// A specific interface of a USB device pub trait Interface<'a> { /// A USB control in transfer (device to host) + /// Returns a [Result] with the bytes in a `Vec` async fn control_in(&self, data: ControlIn) -> Result, Box>; /// A USB control out transfer (host to device) async fn control_out(&self, data: ControlOut<'a>) -> Result<(), Box>; /// A USB bulk in transfer (device to host) + /// Returns a [Result] with the bytes in a `Vec` async fn bulk_in(&self, endpoint: u8, length: usize) -> Result, Box>; - /// A USB bulk out transfer (host to device) - async fn bulk_out(&self, endpoint: u8, data: Vec) -> Result>; + /// A USB bulk out transfer (host to device). + /// Returns a [Result] with the number of bytes transferred + async fn bulk_out(&self, endpoint: u8, data: &[u8]) -> Result>; async fn interrupt_in(&self, _endpoint: u8, _buf: Vec) { unimplemented!()