From 6ac7479879f55d1523e9415070cd45a10afdfacf Mon Sep 17 00:00:00 2001 From: G2-Games Date: Fri, 2 Feb 2024 00:12:05 -0600 Subject: [PATCH] Replaced `get_device` with `get_device_filter`, doc improvements, other improvements --- Cargo.toml | 2 -- src/backend/native.rs | 29 +--------------- src/backend/wasm.rs | 77 ++++++++++++------------------------------- src/lib.rs | 13 +++++++- src/usb.rs | 11 ++++++- 5 files changed, 44 insertions(+), 88 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1b436f2..2e359ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,6 @@ version = "0.3" features = [ "Window", "Navigator", - "console", "Usb", "UsbDevice", "UsbInterface", @@ -39,7 +38,6 @@ features = [ "UsbDeviceRequestOptions", "UsbInTransferResult", "UsbOutTransferResult", - "Storage" ] # Non-wasm deps diff --git a/src/backend/native.rs b/src/backend/native.rs index 0bd40d9..5d25e82 100644 --- a/src/backend/native.rs +++ b/src/backend/native.rs @@ -36,34 +36,7 @@ impl DeviceFilter { } } -pub async fn get_device(vendor_id: u16, product_id: u16) -> Result { - let devices = nusb::list_devices().unwrap(); - - let mut device_info = None; - for device in devices { - if device.vendor_id() == vendor_id && device.product_id() == product_id { - device_info = Some(device); - break; - } - } - - let device_info = match device_info { - Some(dev) => dev, - None => return Err(UsbError::DeviceNotFound), - }; - - let device = match device_info.open() { - Ok(dev) => dev, - Err(_) => return Err(UsbError::CommunicationError), - }; - - Ok(UsbDevice { - device_info, - device, - }) -} - -pub async fn get_device_filter(device_filter: Vec) -> Result { +pub async fn get_device(device_filter: Vec) -> Result { let devices = nusb::list_devices().unwrap(); let mut device_info = None; diff --git a/src/backend/wasm.rs b/src/backend/wasm.rs index a5f323d..0ea3ed3 100644 --- a/src/backend/wasm.rs +++ b/src/backend/wasm.rs @@ -19,6 +19,7 @@ pub struct UsbDevice { #[wasm_bindgen] pub struct UsbInterface { device: WasmUsbDevice, + _number: u8, } #[wasm_bindgen] @@ -50,56 +51,7 @@ impl DeviceFilter { } #[wasm_bindgen] -pub async fn get_device(vendor_id: u16, product_id: u16) -> Result { - let window = web_sys::window().unwrap(); - - let navigator = window.navigator(); - let usb = navigator.usb(); - - let device_list: Array = JsFuture::from(Promise::resolve(&usb.get_devices())) - .await? - .into(); - // Check if the device is already paired, if so, we don't need to request it again - for js_device in device_list { - let device: WasmUsbDevice = js_device.into(); - - if device.vendor_id() == vendor_id && device.product_id() == product_id { - let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?; - - return Ok(UsbDevice { device }); - } - } - - let arr = Array::new(); - let filter1 = js_sys::Object::new(); - js_sys::Reflect::set( - &filter1, - &JsValue::from_str("vendorId"), - &JsValue::from(vendor_id), - ) - .unwrap(); - js_sys::Reflect::set( - &filter1, - &JsValue::from_str("productId"), - &JsValue::from(product_id), - ) - .unwrap(); - arr.push(&filter1); - let filters = JsValue::from(&arr); - - let filters2 = UsbDeviceRequestOptions::new(&filters); - - let device: WasmUsbDevice = JsFuture::from(Promise::resolve(&usb.request_device(&filters2))) - .await? - .into(); - - let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?; - - Ok(UsbDevice { device }) -} - -#[wasm_bindgen] -pub async fn get_device_filter( +pub async fn get_device( device_filter: Vec, ) -> Result { let window = web_sys::window().unwrap(); @@ -107,9 +59,11 @@ pub async fn get_device_filter( let navigator = window.navigator(); let usb = navigator.usb(); - let device_list: Array = JsFuture::from(Promise::resolve(&usb.get_devices())) - .await? - .into(); + let device_list: Array = match JsFuture::from(Promise::resolve(&usb.get_devices())).await { + Ok(list) => list.into(), + Err(_) => Array::new(), + }; + // Check if the device is already paired, if so, we don't need to request it again for js_device in device_list { let device: WasmUsbDevice = js_device.into(); @@ -142,6 +96,7 @@ pub async fn get_device_filter( result }) { + let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?; return Ok(UsbDevice { device }); } } @@ -222,13 +177,12 @@ impl Device for UsbDevice { Ok(UsbInterface { device: self.device.clone(), + _number: number, }) } async fn reset(&self) -> Result<(), UsbError> { - let promise = Promise::resolve(&self.device.reset()); - - let result = JsFuture::from(promise).await; + let result = JsFuture::from(Promise::resolve(&self.device.reset())).await; match result { Ok(_) => Ok(()), @@ -236,6 +190,17 @@ impl Device for UsbDevice { } } + /* + async fn forget(&self) -> Result<(), UsbError> { + let result = JsFuture::from(Promise::resolve(&self.device.forget())).await; + + match result { + Ok(_) => Ok(()), + Err(_) => Err(UsbError::CommunicationError), + } + } + */ + async fn vendor_id(&self) -> u16 { self.device.vendor_id() } diff --git a/src/lib.rs b/src/lib.rs index 198c8f9..6924b9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,24 @@ //! The idea is the user only has to write one way to access USB devices, which can be compiled //! to both WASM and native targets without any conditional compilation or configuration. //! +//! For native device support, this library uses [nusb](https://docs.rs/nusb/latest/nusb/), a cross platform USB library written in Rust +//! and comparable to the very popular `libusb` C library. Web Assembly support is provided by [web-sys](https://docs.rs/web-sys/latest/web_sys/) +//! with the [Web USB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API) +//! +//! When a [UsbInterface] is dropped, it is automatically released. +//! //! ## Example: //! ```no_run //! # tokio_test::block_on(async { //! use cross_usb::usb::{Device, Interface, Recipient, ControlType, ControlIn}; +//! use cross_usb::device_filter; //! //! // Obtain a device using its VendorID and ProductID -//! let device = cross_usb::get_device(0x054c, 0x0186).await.expect("Failed to get device"); +//! let filter = vec![ +//! device_filter!{vendor_id: 0x054c, product_id: 0x00c9} +//! ]; +//! +//! let device = cross_usb::get_device_filter(filter).await.expect("Failed to get device"); //! //! // Obtain an interface of the device //! let interface = device.open_interface(0).await.expect("Failed to open interface"); diff --git a/src/usb.rs b/src/usb.rs index e85725d..0014abd 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -16,9 +16,18 @@ pub trait Device { /// Open a specific interface of the device async fn open_interface(&self, number: u8) -> Result; - /// Reset the device, which causes it to no longer be usable + /// Reset the device, which causes it to no longer be usable. You must + /// request a new device with [crate::get_device] or [crate::get_device_filter] async fn reset(&self) -> Result<(), UsbError>; + /* + /// Remove the device from the paired devices list, causing it to no longer be usable. + /// You must request to reconnect using [crate::get_device] or [crate::get_device_filter] + /// + /// **Note: Only does anything on WASM, on Native it simply resets the device** + async fn forget(&self) -> Result<(), UsbError>; + */ + /// 16 bit device Product ID async fn product_id(&self) -> u16;