mirror of
https://github.com/G2-Games/cross-usb.git
synced 2025-06-23 10:22:53 -05:00
Compare commits
No commits in common. "092cb0583adea570d6f662cd6b7acf616dac6239" and "54154d54c3ed9a0a4682c39707a7ba42ad800086" have entirely different histories.
092cb0583a
...
54154d54c3
4 changed files with 104 additions and 401 deletions
|
@ -1,13 +1,7 @@
|
||||||
use crate::usb::{
|
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError};
|
||||||
ControlIn, ControlOut, ControlType, Descriptor, Device, Interface, Recipient, UsbError,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub struct UsbDescriptor {
|
|
||||||
device_info: nusb::DeviceInfo,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct UsbDevice {
|
pub struct UsbDevice {
|
||||||
device_info: UsbDescriptor,
|
device_info: nusb::DeviceInfo,
|
||||||
device: nusb::Device,
|
device: nusb::Device,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,13 +36,15 @@ impl DeviceFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_device(device_filters: Vec<DeviceFilter>) -> Result<UsbDescriptor, UsbError> {
|
pub async fn get_device(device_filter: Vec<DeviceFilter>) -> Result<UsbDevice, UsbError> {
|
||||||
let devices = nusb::list_devices().unwrap();
|
let devices = nusb::list_devices().unwrap();
|
||||||
|
|
||||||
let mut device_info = None;
|
let mut device_info = None;
|
||||||
for prelim_dev_inf in devices {
|
for prelim_dev_inf in devices {
|
||||||
// See if the device exists in the list
|
// See if the device exists in the list
|
||||||
if device_filters.iter().any(|info| {
|
if device_filter
|
||||||
|
.iter()
|
||||||
|
.any(|info| {
|
||||||
let mut result = false;
|
let mut result = false;
|
||||||
|
|
||||||
if info.vendor_id.is_some() {
|
if info.vendor_id.is_some() {
|
||||||
|
@ -72,9 +68,10 @@ pub async fn get_device(device_filters: Vec<DeviceFilter>) -> Result<UsbDescript
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}) {
|
})
|
||||||
|
{
|
||||||
device_info = Some(prelim_dev_inf);
|
device_info = Some(prelim_dev_inf);
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,69 +80,39 @@ pub async fn get_device(device_filters: Vec<DeviceFilter>) -> Result<UsbDescript
|
||||||
None => return Err(UsbError::DeviceNotFound),
|
None => return Err(UsbError::DeviceNotFound),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(UsbDescriptor { device_info })
|
let device = match device_info.open() {
|
||||||
|
Ok(dev) => dev,
|
||||||
|
Err(_) => return Err(UsbError::CommunicationError),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(UsbDevice {
|
||||||
|
device_info,
|
||||||
|
device,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_device_list(
|
impl Device for UsbDevice {
|
||||||
device_filters: Vec<DeviceFilter>,
|
type UsbDevice = UsbDevice;
|
||||||
) -> Result<Vec<UsbDescriptor>, UsbError> {
|
type UsbInterface = UsbInterface;
|
||||||
let devices_info = nusb::list_devices().unwrap();
|
|
||||||
|
|
||||||
let mut devices = Vec::new();
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError> {
|
||||||
for prelim_dev_inf in devices_info {
|
let interface = match self.device.claim_interface(number) {
|
||||||
// See if the device exists in the list
|
Ok(inter) => inter,
|
||||||
if device_filters.iter().any(|info| {
|
Err(_) => return Err(UsbError::CommunicationError),
|
||||||
let mut result = false;
|
};
|
||||||
|
|
||||||
if info.vendor_id.is_some() {
|
Ok(UsbInterface { interface })
|
||||||
result = info.vendor_id.unwrap() == prelim_dev_inf.vendor_id();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.product_id.is_some() {
|
async fn reset(&self) -> Result<(), UsbError> {
|
||||||
result = info.product_id.unwrap() == prelim_dev_inf.product_id();
|
match self.device.reset() {
|
||||||
}
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => Err(UsbError::CommunicationError),
|
||||||
if info.class.is_some() {
|
|
||||||
result = info.class.unwrap() == prelim_dev_inf.class();
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.subclass.is_some() {
|
|
||||||
result = info.subclass.unwrap() == prelim_dev_inf.subclass();
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.protocol.is_some() {
|
|
||||||
result = info.protocol.unwrap() == prelim_dev_inf.protocol();
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}) {
|
|
||||||
devices.push(prelim_dev_inf);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if devices.is_empty() {
|
async fn forget(&self) -> Result<(), UsbError> {
|
||||||
return Err(UsbError::DeviceNotFound);
|
self.reset().await
|
||||||
}
|
|
||||||
|
|
||||||
let devices_opened: Vec<UsbDescriptor> = devices
|
|
||||||
.into_iter()
|
|
||||||
.map(|d| UsbDescriptor { device_info: d })
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
Ok(devices_opened)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Descriptor for UsbDescriptor {
|
|
||||||
type Device = UsbDevice;
|
|
||||||
|
|
||||||
async fn open(self) -> Result<Self::Device, UsbError> {
|
|
||||||
match self.device_info.open() {
|
|
||||||
Ok(dev) => Ok(Self::Device {
|
|
||||||
device_info: self,
|
|
||||||
device: dev,
|
|
||||||
}),
|
|
||||||
Err(err) => Err(UsbError::CommunicationError(err.to_string())),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn vendor_id(&self) -> u16 {
|
async fn vendor_id(&self) -> u16 {
|
||||||
|
@ -173,69 +140,6 @@ impl Descriptor for UsbDescriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for UsbDevice {
|
|
||||||
type Interface = UsbInterface;
|
|
||||||
|
|
||||||
async fn open_interface(&self, number: u8) -> Result<Self::Interface, UsbError> {
|
|
||||||
let interface = match self.device.claim_interface(number) {
|
|
||||||
Ok(inter) => inter,
|
|
||||||
Err(err) => return Err(UsbError::CommunicationError(err.to_string())),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(UsbInterface { interface })
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn detach_and_open_interface(&self, number: u8) -> Result<Self::Interface, UsbError> {
|
|
||||||
let interface = match self.device.detach_and_claim_interface(number) {
|
|
||||||
Ok(inter) => inter,
|
|
||||||
Err(err) => return Err(UsbError::CommunicationError(err.to_string())),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(UsbInterface { interface })
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn reset(&self) -> Result<(), UsbError> {
|
|
||||||
match self.device.reset() {
|
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(err) => Err(UsbError::CommunicationError(err.to_string())),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn forget(&self) -> Result<(), UsbError> {
|
|
||||||
self.reset().await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn product_id(&self) -> u16 {
|
|
||||||
self.device_info.product_id().await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn vendor_id(&self) -> u16 {
|
|
||||||
self.device_info.vendor_id().await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn class(&self) -> u8 {
|
|
||||||
self.device_info.class().await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn subclass(&self) -> u8 {
|
|
||||||
self.device_info.subclass().await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn manufacturer_string(&self) -> Option<String> {
|
|
||||||
self.device_info.manufacturer_string().await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn product_string(&self) -> Option<String> {
|
|
||||||
self.device_info.product_string().await
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for UsbDevice {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
let _ = self.device.reset();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> Interface<'a> for UsbInterface {
|
impl<'a> Interface<'a> for UsbInterface {
|
||||||
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, UsbError> {
|
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, UsbError> {
|
||||||
let result = match self.interface.control_in(data.into()).await.into_result() {
|
let result = match self.interface.control_in(data.into()).await.into_result() {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//#![cfg_attr(debug_assertions, allow(dead_code, unused_imports))]
|
#![cfg_attr(debug_assertions, allow(dead_code, unused_imports))]
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use js_sys::{Array, Object, Promise, Uint8Array};
|
use js_sys::{Array, Object, Promise, Uint8Array};
|
||||||
|
@ -9,14 +9,7 @@ use web_sys::{
|
||||||
};
|
};
|
||||||
|
|
||||||
// Crate stuff
|
// Crate stuff
|
||||||
use crate::usb::{
|
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError};
|
||||||
ControlIn, ControlOut, ControlType, Descriptor, Device, Interface, Recipient, UsbError,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub struct UsbDescriptor {
|
|
||||||
device: WasmUsbDevice,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct UsbDevice {
|
pub struct UsbDevice {
|
||||||
|
@ -58,7 +51,9 @@ impl DeviceFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn get_device(device_filter: Vec<DeviceFilter>) -> Result<UsbDescriptor, js_sys::Error> {
|
pub async fn get_device(
|
||||||
|
device_filter: Vec<DeviceFilter>,
|
||||||
|
) -> Result<UsbDevice, js_sys::Error> {
|
||||||
let window = web_sys::window().unwrap();
|
let window = web_sys::window().unwrap();
|
||||||
|
|
||||||
let navigator = window.navigator();
|
let navigator = window.navigator();
|
||||||
|
@ -73,7 +68,9 @@ pub async fn get_device(device_filter: Vec<DeviceFilter>) -> Result<UsbDescripto
|
||||||
for js_device in device_list {
|
for js_device in device_list {
|
||||||
let device: WasmUsbDevice = js_device.into();
|
let device: WasmUsbDevice = js_device.into();
|
||||||
|
|
||||||
if device_filter.iter().any(|info| {
|
if device_filter
|
||||||
|
.iter()
|
||||||
|
.any(|info| {
|
||||||
let mut result = false;
|
let mut result = false;
|
||||||
|
|
||||||
if info.vendor_id.is_some() {
|
if info.vendor_id.is_some() {
|
||||||
|
@ -97,215 +94,74 @@ pub async fn get_device(device_filter: Vec<DeviceFilter>) -> Result<UsbDescripto
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
}) {
|
|
||||||
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
|
||||||
return Ok(UsbDescriptor { device });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let arr = Array::new();
|
|
||||||
for filter in device_filter {
|
|
||||||
let js_filter = js_sys::Object::new();
|
|
||||||
if let Some(vid) = filter.vendor_id {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("vendorId"),
|
|
||||||
&JsValue::from(vid),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(pid) = filter.product_id {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("productId"),
|
|
||||||
&JsValue::from(pid),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(class) = filter.class {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("classCode"),
|
|
||||||
&JsValue::from(class),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(subclass) = filter.subclass {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("subclassCode"),
|
|
||||||
&JsValue::from(subclass),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(pro) = filter.protocol {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("protocolCode"),
|
|
||||||
&JsValue::from(pro),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
arr.push(&js_filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
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(UsbDescriptor { device })
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
#[wasm_bindgen]
|
|
||||||
pub async fn get_device_list(device_filter: Vec<DeviceFilter>) -> Result<Vec<UsbDescriptor>, js_sys::Error> {
|
|
||||||
let window = web_sys::window().unwrap();
|
|
||||||
|
|
||||||
let navigator = window.navigator();
|
|
||||||
let usb = navigator.usb();
|
|
||||||
|
|
||||||
let device_list: Array = match JsFuture::from(Promise::resolve(&usb.get_devices())).await {
|
|
||||||
Ok(list) => list.into(),
|
|
||||||
Err(_) => Array::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut devices = Vec::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();
|
|
||||||
|
|
||||||
if device_filter.iter().any(|info| {
|
|
||||||
let mut result = false;
|
|
||||||
|
|
||||||
if info.vendor_id.is_some() {
|
|
||||||
result = info.vendor_id.unwrap() == device.vendor_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.product_id.is_some() {
|
|
||||||
result = info.product_id.unwrap() == device.product_id();
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.class.is_some() {
|
|
||||||
result = info.class.unwrap() == device.device_class();
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.subclass.is_some() {
|
|
||||||
result = info.subclass.unwrap() == device.device_subclass();
|
|
||||||
}
|
|
||||||
|
|
||||||
if info.protocol.is_some() {
|
|
||||||
result = info.protocol.unwrap() == device.device_protocol();
|
|
||||||
}
|
|
||||||
|
|
||||||
result
|
|
||||||
}) {
|
|
||||||
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
|
||||||
devices.push(UsbDescriptor { device });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let arr = Array::new();
|
|
||||||
for filter in device_filter {
|
|
||||||
let js_filter = js_sys::Object::new();
|
|
||||||
if let Some(vid) = filter.vendor_id {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("vendorId"),
|
|
||||||
&JsValue::from(vid),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(pid) = filter.product_id {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("productId"),
|
|
||||||
&JsValue::from(pid),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(class) = filter.class {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("classCode"),
|
|
||||||
&JsValue::from(class),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(subclass) = filter.subclass {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("subclassCode"),
|
|
||||||
&JsValue::from(subclass),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
if let Some(pro) = filter.protocol {
|
|
||||||
js_sys::Reflect::set(
|
|
||||||
&js_filter,
|
|
||||||
&JsValue::from_str("protocolCode"),
|
|
||||||
&JsValue::from(pro),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
arr.push(&js_filter);
|
|
||||||
}
|
|
||||||
|
|
||||||
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?;
|
|
||||||
|
|
||||||
devices.push(UsbDescriptor { device });
|
|
||||||
|
|
||||||
return Ok(devices);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
impl Descriptor for UsbDescriptor {
|
|
||||||
type Device = UsbDevice;
|
|
||||||
|
|
||||||
async fn open(self) -> Result<Self::Device, UsbError> {
|
|
||||||
Ok(Self::Device {
|
|
||||||
device: self.device,
|
|
||||||
})
|
})
|
||||||
|
{
|
||||||
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
||||||
|
return Ok(UsbDevice { device });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn product_id(&self) -> u16 {
|
let arr = Array::new();
|
||||||
self.device.vendor_id()
|
for filter in device_filter {
|
||||||
|
let js_filter = js_sys::Object::new();
|
||||||
|
if let Some(vid) = filter.vendor_id {
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&js_filter,
|
||||||
|
&JsValue::from_str("vendorId"),
|
||||||
|
&JsValue::from(vid),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
if let Some(pid) = filter.product_id {
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&js_filter,
|
||||||
|
&JsValue::from_str("productId"),
|
||||||
|
&JsValue::from(pid),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
if let Some(class) = filter.class {
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&js_filter,
|
||||||
|
&JsValue::from_str("classCode"),
|
||||||
|
&JsValue::from(class),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
if let Some(subclass) = filter.subclass {
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&js_filter,
|
||||||
|
&JsValue::from_str("subclassCode"),
|
||||||
|
&JsValue::from(subclass),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
if let Some(pro) = filter.protocol {
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&js_filter,
|
||||||
|
&JsValue::from_str("protocolCode"),
|
||||||
|
&JsValue::from(pro),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
arr.push(&js_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn vendor_id(&self) -> u16 {
|
let filters = JsValue::from(&arr);
|
||||||
self.device.product_id()
|
let filters2 = UsbDeviceRequestOptions::new(&filters);
|
||||||
}
|
|
||||||
|
|
||||||
async fn class(&self) -> u8 {
|
let device: WasmUsbDevice = JsFuture::from(Promise::resolve(&usb.request_device(&filters2)))
|
||||||
self.device.device_class()
|
.await?
|
||||||
}
|
.into();
|
||||||
|
|
||||||
async fn subclass(&self) -> u8 {
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
||||||
self.device.device_subclass()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn manufacturer_string(&self) -> Option<String> {
|
Ok(UsbDevice { device })
|
||||||
self.device.manufacturer_name()
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn product_string(&self) -> Option<String> {
|
|
||||||
self.device.product_name()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for UsbDevice {
|
impl Device for UsbDevice {
|
||||||
type Interface = UsbInterface;
|
type UsbDevice = UsbDevice;
|
||||||
|
type UsbInterface = UsbInterface;
|
||||||
|
|
||||||
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError> {
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError> {
|
||||||
let dev_promise =
|
let dev_promise =
|
||||||
|
@ -314,10 +170,8 @@ impl Device for UsbDevice {
|
||||||
// Wait for the interface to be claimed
|
// Wait for the interface to be claimed
|
||||||
let _device: WasmUsbDevice = match dev_promise {
|
let _device: WasmUsbDevice = match dev_promise {
|
||||||
Ok(dev) => dev.into(),
|
Ok(dev) => dev.into(),
|
||||||
Err(err) => {
|
Err(_) => {
|
||||||
return Err(UsbError::CommunicationError(
|
return Err(UsbError::CommunicationError);
|
||||||
err.as_string().unwrap_or_default(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -327,18 +181,12 @@ impl Device for UsbDevice {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn detach_and_open_interface(&self, number: u8) -> Result<Self::Interface, UsbError> {
|
|
||||||
self.open_interface(number).await
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn reset(&self) -> Result<(), UsbError> {
|
async fn reset(&self) -> Result<(), UsbError> {
|
||||||
let result = JsFuture::from(Promise::resolve(&self.device.reset())).await;
|
let result = JsFuture::from(Promise::resolve(&self.device.reset())).await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(UsbError::CommunicationError(
|
Err(_) => Err(UsbError::CommunicationError),
|
||||||
err.as_string().unwrap_or_default(),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -347,9 +195,7 @@ impl Device for UsbDevice {
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(err) => Err(UsbError::CommunicationError(
|
Err(_) => Err(UsbError::CommunicationError),
|
||||||
err.as_string().unwrap_or_default(),
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
37
src/lib.rs
37
src/lib.rs
|
@ -9,34 +9,24 @@
|
||||||
//!
|
//!
|
||||||
//! When a [UsbInterface] is dropped, it is automatically released.
|
//! When a [UsbInterface] is dropped, it is automatically released.
|
||||||
//!
|
//!
|
||||||
//! ### CURRENT LIMITATIONS:
|
|
||||||
//! * Hotplug support is not implemented. Waiting on [hotplug support in nusb](https://github.com/kevinmehall/nusb/pull/20).
|
|
||||||
//!
|
|
||||||
//! * Until [this pull request](https://github.com/rustwasm/wasm-bindgen/issues/3155)
|
|
||||||
//! is merged into wasm bindgen, getting a list of USB devices is not possible on WASM
|
|
||||||
//! targets. However, this isn't a huge deal as the user gets a list to select from anyway.
|
|
||||||
//!
|
|
||||||
//! ## Example:
|
//! ## Example:
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! # tokio_test::block_on(async {
|
//! # tokio_test::block_on(async {
|
||||||
//! use cross_usb::usb::{Descriptor, Device, Interface, Recipient, ControlType, ControlIn};
|
//! use cross_usb::usb::{Device, Interface, Recipient, ControlType, ControlIn};
|
||||||
//! use cross_usb::device_filter;
|
//! use cross_usb::device_filter;
|
||||||
//!
|
//!
|
||||||
//! // Obtain a device descriptor (UsbDescriptor) using a DeviceFilter,
|
//! // Obtain a device using its VendorID and ProductID
|
||||||
//! // in this case with its VendorID and ProductID
|
//! let filter = vec![
|
||||||
//! let filters = vec![
|
|
||||||
//! device_filter!{vendor_id: 0x054c, product_id: 0x00c9}
|
//! device_filter!{vendor_id: 0x054c, product_id: 0x00c9}
|
||||||
//! ];
|
//! ];
|
||||||
//! let dev_descriptor = cross_usb::get_device(filters).await.expect("Failed to find device");
|
|
||||||
//!
|
//!
|
||||||
//! // Open the device that the descriptor is describing
|
//! let device = cross_usb::get_device(filter).await.expect("Failed to get device");
|
||||||
//! let dev = dev_descriptor.open().await.expect("Failed to open device");
|
|
||||||
//!
|
//!
|
||||||
//! // Obtain an interface of the device
|
//! // Obtain an interface of the device
|
||||||
//! let interface = dev.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`
|
//! // the result and storing it in `result`, and you're done!
|
||||||
//! let result = interface.control_in(ControlIn {
|
//! let result = interface.control_in(ControlIn {
|
||||||
//! control_type: ControlType::Vendor,
|
//! control_type: ControlType::Vendor,
|
||||||
//! recipient: Recipient::Interface,
|
//! recipient: Recipient::Interface,
|
||||||
|
@ -51,19 +41,16 @@
|
||||||
//! ```
|
//! ```
|
||||||
pub mod usb;
|
pub mod usb;
|
||||||
|
|
||||||
/// The context contains the platform specific implementation of the USB transfers
|
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
#[path = "./backend/native.rs"]
|
#[path = "./backend/native.rs"]
|
||||||
|
/// The context contains the platform specific implementation of the USB transfers
|
||||||
mod context;
|
mod context;
|
||||||
|
|
||||||
#[cfg(target_family = "wasm")]
|
#[cfg(target_family = "wasm")]
|
||||||
#[path = "./backend/wasm.rs"]
|
#[path = "./backend/wasm.rs"]
|
||||||
|
/// The context contains the platform specific implementation of the USB transfers
|
||||||
mod context;
|
mod context;
|
||||||
|
|
||||||
#[doc(inline)]
|
|
||||||
/// An implementation of a USB device descriptor
|
|
||||||
pub use crate::context::UsbDescriptor;
|
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
/// An implementation of a USB device
|
/// An implementation of a USB device
|
||||||
pub use crate::context::UsbDevice;
|
pub use crate::context::UsbDevice;
|
||||||
|
@ -77,13 +64,14 @@ pub use crate::context::UsbInterface;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::DeviceFilter;
|
pub use crate::context::DeviceFilter;
|
||||||
|
|
||||||
/// Gets a single device descriptor ([UsbDescriptor]) from a list of VendorID and ProductIDs
|
/// Gets a single device from a list of VendorID and ProductIDs
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # tokio_test::block_on(async {
|
/// # tokio_test::block_on(async {
|
||||||
/// use cross_usb::{get_device, DeviceFilter, device_filter};
|
/// use cross_usb::{get_device, DeviceFilter, device_filter};
|
||||||
///
|
///
|
||||||
|
///
|
||||||
/// let filter = vec![
|
/// let filter = vec![
|
||||||
/// device_filter!{vendor_id: 0x054c, product_id: 0x00c9},
|
/// device_filter!{vendor_id: 0x054c, product_id: 0x00c9},
|
||||||
/// device_filter!{vendor_id: 0x054c},
|
/// device_filter!{vendor_id: 0x054c},
|
||||||
|
@ -95,11 +83,6 @@ pub use crate::context::DeviceFilter;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::get_device;
|
pub use crate::context::get_device;
|
||||||
|
|
||||||
/// Gets a list of devices from a list of VendorID and ProductIDs
|
|
||||||
#[cfg(not(target_family = "wasm"))]
|
|
||||||
#[doc(inline)]
|
|
||||||
pub use crate::context::get_device_list;
|
|
||||||
|
|
||||||
/// Macro to create a device filter more easily.
|
/// Macro to create a device filter more easily.
|
||||||
///
|
///
|
||||||
/// The only valid keys are fields of the [DeviceFilter] struct.
|
/// The only valid keys are fields of the [DeviceFilter] struct.
|
||||||
|
|
46
src/usb.rs
46
src/usb.rs
|
@ -2,49 +2,19 @@
|
||||||
//! 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 thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub trait Descriptor {
|
|
||||||
/// A unique USB Device
|
|
||||||
type Device;
|
|
||||||
|
|
||||||
/// Opens the USB connection, returning a [Self::Device]
|
|
||||||
async fn open(self) -> Result<Self::Device, UsbError>;
|
|
||||||
|
|
||||||
/// 16 bit device Product ID
|
|
||||||
async fn product_id(&self) -> u16;
|
|
||||||
|
|
||||||
/// 16 bit device Vendor ID
|
|
||||||
async fn vendor_id(&self) -> u16;
|
|
||||||
|
|
||||||
/// Device standard class
|
|
||||||
async fn class(&self) -> u8;
|
|
||||||
|
|
||||||
/// Device standard subclass
|
|
||||||
async fn subclass(&self) -> u8;
|
|
||||||
|
|
||||||
/// Get the manufacturer string string of the device, if available without device IO
|
|
||||||
///
|
|
||||||
/// Not available on Windows
|
|
||||||
async fn manufacturer_string(&self) -> Option<String>;
|
|
||||||
|
|
||||||
/// Get the product string of the device, if available without device IO
|
|
||||||
async fn product_string(&self) -> Option<String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A unique USB device
|
/// A unique USB device
|
||||||
pub trait Device {
|
pub trait Device {
|
||||||
|
/// A unique USB Device
|
||||||
|
type UsbDevice;
|
||||||
|
|
||||||
/// A unique Interface on a USB Device
|
/// A unique Interface on a USB Device
|
||||||
type Interface;
|
type UsbInterface;
|
||||||
|
|
||||||
/// Open a specific interface of the device
|
/// Open a specific interface of the device
|
||||||
async fn open_interface(&self, number: u8) -> Result<Self::Interface, UsbError>;
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError>;
|
||||||
|
|
||||||
/// Open a specific interface of the device, detaching any
|
|
||||||
/// kernel drivers and claiming it.
|
|
||||||
///
|
|
||||||
/// **Note:** This only has an effect on Native, and only on Linux.
|
|
||||||
async fn detach_and_open_interface(&self, number: u8) -> Result<Self::Interface, UsbError>;
|
|
||||||
|
|
||||||
/// Reset the device, which causes it to no longer be usable. You must
|
/// Reset the device, which causes it to no longer be usable. You must
|
||||||
/// request a new device with [crate::get_device]
|
/// request a new device with [crate::get_device]
|
||||||
|
@ -52,7 +22,7 @@ pub trait Device {
|
||||||
|
|
||||||
/// Remove the device from the paired devices list, causing it to no longer be usable. You must request to reconnect using [crate::get_device]
|
/// Remove the device from the paired devices list, causing it to no longer be usable. You must request to reconnect using [crate::get_device]
|
||||||
///
|
///
|
||||||
/// **Note:** On Native this simply resets the device.
|
/// **Note: on Native with `nusb` this simply resets the device**
|
||||||
async fn forget(&self) -> Result<(), UsbError>;
|
async fn forget(&self) -> Result<(), UsbError>;
|
||||||
|
|
||||||
/// 16 bit device Product ID
|
/// 16 bit device Product ID
|
||||||
|
@ -117,7 +87,7 @@ pub enum UsbError {
|
||||||
TransferError,
|
TransferError,
|
||||||
|
|
||||||
#[error("device communication failed")]
|
#[error("device communication failed")]
|
||||||
CommunicationError(String),
|
CommunicationError,
|
||||||
|
|
||||||
#[error("device disconnected")]
|
#[error("device disconnected")]
|
||||||
Disconnected,
|
Disconnected,
|
||||||
|
|
Loading…
Reference in a new issue