mirror of
https://github.com/G2-Games/cross-usb.git
synced 2025-04-19 13:22:53 -05:00
Added get_device_filter
, made WASM check for previously paired devices
This commit is contained in:
parent
b60f5f0eae
commit
d70248cc1d
5 changed files with 138 additions and 17 deletions
|
@ -47,7 +47,7 @@ features = [
|
||||||
nusb = "0.1.5"
|
nusb = "0.1.5"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
futures-lite = "1.13.0"
|
tokio-test = "0.4.3"
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "s"
|
opt-level = "s"
|
||||||
|
|
|
@ -35,6 +35,40 @@ pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, Bo
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
|
pub struct FilterTuple(pub u16, pub u16);
|
||||||
|
|
||||||
|
pub async fn get_device_filter(device_filter: Vec<FilterTuple>) -> Result<UsbDevice, Box<dyn Error>> {
|
||||||
|
let devices = nusb::list_devices().unwrap();
|
||||||
|
|
||||||
|
let mut device_info = None;
|
||||||
|
for device in devices {
|
||||||
|
match device_filter.iter().position(|i| i == &FilterTuple(device.vendor_id(), device.product_id())) {
|
||||||
|
Some(_) => {
|
||||||
|
device_info = Some(device);
|
||||||
|
break;
|
||||||
|
},
|
||||||
|
None => device_info = None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if device_info.is_none() {
|
||||||
|
return Err("No devices from the list found".into())
|
||||||
|
}
|
||||||
|
|
||||||
|
let device_info = match device_info {
|
||||||
|
Some(dev) => dev,
|
||||||
|
None => return Err("Device not found".into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let device = device_info.open()?;
|
||||||
|
|
||||||
|
Ok(UsbDevice {
|
||||||
|
device_info,
|
||||||
|
device,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
impl Device for UsbDevice {
|
impl Device for UsbDevice {
|
||||||
type UsbDevice = UsbDevice;
|
type UsbDevice = UsbDevice;
|
||||||
type UsbInterface = UsbInterface;
|
type UsbInterface = UsbInterface;
|
||||||
|
|
|
@ -29,6 +29,20 @@ pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, js
|
||||||
let navigator = window.navigator();
|
let navigator = window.navigator();
|
||||||
let usb = navigator.usb();
|
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 arr = Array::new();
|
||||||
let filter1 = js_sys::Object::new();
|
let filter1 = js_sys::Object::new();
|
||||||
js_sys::Reflect::set(
|
js_sys::Reflect::set(
|
||||||
|
@ -48,15 +62,62 @@ pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, js
|
||||||
|
|
||||||
let filters2 = UsbDeviceRequestOptions::new(&filters);
|
let filters2 = UsbDeviceRequestOptions::new(&filters);
|
||||||
|
|
||||||
let device_promise = JsFuture::from(Promise::resolve(&usb.request_device(&filters2))).await;
|
let device: WasmUsbDevice = JsFuture::from(Promise::resolve(&usb.request_device(&filters2))).await?.into();
|
||||||
|
|
||||||
let device: WasmUsbDevice = match device_promise {
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
||||||
Ok(dev) => dev.into(),
|
|
||||||
Err(err) => {
|
Ok(UsbDevice { device })
|
||||||
console::log_1(&err.clone());
|
}
|
||||||
return Err(err.into());
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[derive(PartialEq, Eq, Clone)]
|
||||||
|
pub struct FilterTuple(pub u16, pub u16);
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn get_device_filter(device_filter: Vec<FilterTuple>) -> Result<UsbDevice, js_sys::Error> {
|
||||||
|
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();
|
||||||
|
|
||||||
|
for filter_info in &device_filter {
|
||||||
|
if device.vendor_id() == filter_info.0 && device.product_id() == filter_info.1 {
|
||||||
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
||||||
|
|
||||||
|
return Ok(UsbDevice {
|
||||||
|
device
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
let arr = Array::new();
|
||||||
|
for device in device_filter {
|
||||||
|
let filter1 = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&filter1,
|
||||||
|
&JsValue::from_str("vendorId"),
|
||||||
|
&JsValue::from(device.0),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&filter1,
|
||||||
|
&JsValue::from_str("productId"),
|
||||||
|
&JsValue::from(device.1),
|
||||||
|
)
|
||||||
|
.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?;
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
||||||
|
|
||||||
|
|
33
src/lib.rs
33
src/lib.rs
|
@ -5,17 +5,18 @@
|
||||||
//!
|
//!
|
||||||
//! ## Example:
|
//! ## Example:
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! use cross_usb::usb::{Device, Recipient, ControlType, ControlIn};
|
//! # tokio_test::block_on(async {
|
||||||
|
//! use cross_usb::usb::{Device, Interface, Recipient, ControlType, ControlIn};
|
||||||
//!
|
//!
|
||||||
//! // Obtain a device using its VendorID and ProductID
|
//! // Obtain a device using its VendorID and ProductID
|
||||||
//! let device = cross_usb::get_device(0x054c, 0x0186).await.expect("");
|
//! let device = cross_usb::get_device(0x054c, 0x0186).await.expect("Failed to get device");
|
||||||
//!
|
//!
|
||||||
//! // Obtain an interface of the device
|
//! // Obtain an interface of the device
|
||||||
//! let interface = usb_device.open_interface(0).await.expect("Failed to open interface");
|
//! let interface = device.open_interface(0).await.expect("Failed to open interface");
|
||||||
//!
|
//!
|
||||||
//! // Send a Control transfer to the device, obtaining
|
//! // Send a Control transfer to the device, obtaining
|
||||||
//! // the result and storing it in `result`, and you're done!
|
//! // the result and storing it in `result`, and you're done!
|
||||||
//! let result = match interface.control_in(ControlIn {
|
//! let result = interface.control_in(ControlIn {
|
||||||
//! control_type: ControlType::Vendor,
|
//! control_type: ControlType::Vendor,
|
||||||
//! recipient: Recipient::Interface,
|
//! recipient: Recipient::Interface,
|
||||||
//! request: 0x01,
|
//! request: 0x01,
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
//! })
|
//! })
|
||||||
//! .await
|
//! .await
|
||||||
//! .expect("Sending control transfer failed");
|
//! .expect("Sending control transfer failed");
|
||||||
|
//! # })
|
||||||
//! ```
|
//! ```
|
||||||
pub mod usb;
|
pub mod usb;
|
||||||
|
|
||||||
|
@ -46,6 +48,29 @@ pub use crate::context::UsbDevice;
|
||||||
/// An implementation of a USB interface
|
/// An implementation of a USB interface
|
||||||
pub use crate::context::UsbInterface;
|
pub use crate::context::UsbInterface;
|
||||||
|
|
||||||
|
/// A single Device ID and Product ID pair to find when looking
|
||||||
|
/// for new USB devices using [get_device_filter]
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use crate::context::FilterTuple;
|
||||||
|
|
||||||
/// Gets a single device from the VendorID and ProductID
|
/// Gets a single device from the VendorID and ProductID
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::get_device;
|
pub use crate::context::get_device;
|
||||||
|
|
||||||
|
/// Gets a single device from a list of VendorID and ProductIDs
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```no_run
|
||||||
|
/// # tokio_test::block_on(async {
|
||||||
|
/// use cross_usb::{get_device_filter, FilterTuple};
|
||||||
|
///
|
||||||
|
/// let filter = vec![
|
||||||
|
/// FilterTuple(0x054c, 0x00c9),
|
||||||
|
/// FilterTuple(0x054c, 0x0186),
|
||||||
|
/// ];
|
||||||
|
///
|
||||||
|
/// let device = get_device_filter(filter).await.expect("Could not find device in list");
|
||||||
|
/// # })
|
||||||
|
/// ```
|
||||||
|
#[doc(inline)]
|
||||||
|
pub use crate::context::get_device_filter;
|
||||||
|
|
11
src/usb.rs
11
src/usb.rs
|
@ -1,7 +1,6 @@
|
||||||
#![allow(async_fn_in_trait)]
|
#![allow(async_fn_in_trait)]
|
||||||
//! This module contains the traits and associated functions and
|
//! This module contains the traits and associated functions and
|
||||||
//! structs which allow for USB communication.
|
//! structs which allow for USB communication.
|
||||||
//!
|
|
||||||
|
|
||||||
use crate::context::UsbInterface;
|
use crate::context::UsbInterface;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -20,10 +19,10 @@ pub trait Device {
|
||||||
/// Reset the device, which causes it to no longer be usable
|
/// Reset the device, which causes it to no longer be usable
|
||||||
async fn reset(&self) -> Result<(), Box<dyn Error>>;
|
async fn reset(&self) -> Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
/// 16 bit device product ID
|
/// 16 bit device Product ID
|
||||||
async fn product_id(&self) -> u16;
|
async fn product_id(&self) -> u16;
|
||||||
|
|
||||||
/// 16 bit device vendor ID
|
/// 16 bit device Vendor ID
|
||||||
async fn vendor_id(&self) -> u16;
|
async fn vendor_id(&self) -> u16;
|
||||||
|
|
||||||
/// Device standard class
|
/// Device standard class
|
||||||
|
@ -51,11 +50,13 @@ pub trait Interface<'a> {
|
||||||
async fn control_out(&self, data: ControlOut<'a>) -> Result<(), Box<dyn Error>>;
|
async fn control_out(&self, data: ControlOut<'a>) -> Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
/// A USB bulk in transfer (device to host)
|
/// A USB bulk in transfer (device to host)
|
||||||
/// Returns a [Result] with the bytes in a `Vec<u8>`
|
/// It takes in a bulk endpoint to send to along with the length of
|
||||||
|
/// data to read, and returns a [Result] with the bytes
|
||||||
async fn bulk_in(&self, endpoint: u8, length: usize) -> Result<Vec<u8>, Box<dyn Error>>;
|
async fn bulk_in(&self, endpoint: u8, length: usize) -> Result<Vec<u8>, Box<dyn Error>>;
|
||||||
|
|
||||||
/// A USB bulk out transfer (host to device).
|
/// A USB bulk out transfer (host to device).
|
||||||
/// Returns a [Result] with the number of bytes transferred
|
/// It takes in a bulk endpoint to send to along with some data as
|
||||||
|
/// a slice, and returns a [Result] containing the number of bytes transferred
|
||||||
async fn bulk_out(&self, endpoint: u8, data: &[u8]) -> Result<usize, Box<dyn Error>>;
|
async fn bulk_out(&self, endpoint: u8, data: &[u8]) -> Result<usize, Box<dyn Error>>;
|
||||||
|
|
||||||
/* Interrupt transfers are a work in progress
|
/* Interrupt transfers are a work in progress
|
||||||
|
|
Loading…
Reference in a new issue