mirror of
https://github.com/G2-Games/cross-usb.git
synced 2025-04-19 21:32:53 -05:00
Added UsbDescriptor
, added get_device_list()
on native, updated deps
This commit is contained in:
parent
54154d54c3
commit
202d2d1fbd
4 changed files with 393 additions and 104 deletions
|
@ -1,7 +1,13 @@
|
||||||
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError};
|
use crate::usb::{
|
||||||
|
ControlIn, ControlOut, ControlType, Descriptor, Device, Interface, Recipient, UsbError,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct UsbDescriptor {
|
||||||
|
device_info: nusb::DeviceInfo,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct UsbDevice {
|
pub struct UsbDevice {
|
||||||
device_info: nusb::DeviceInfo,
|
device_info: UsbDescriptor,
|
||||||
device: nusb::Device,
|
device: nusb::Device,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,42 +42,39 @@ impl DeviceFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_device(device_filter: Vec<DeviceFilter>) -> Result<UsbDevice, UsbError> {
|
pub async fn get_device(device_filters: Vec<DeviceFilter>) -> Result<UsbDescriptor, 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_filter
|
if device_filters.iter().any(|info| {
|
||||||
.iter()
|
let mut result = false;
|
||||||
.any(|info| {
|
|
||||||
let mut result = false;
|
|
||||||
|
|
||||||
if info.vendor_id.is_some() {
|
if info.vendor_id.is_some() {
|
||||||
result = info.vendor_id.unwrap() == prelim_dev_inf.vendor_id();
|
result = info.vendor_id.unwrap() == prelim_dev_inf.vendor_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.product_id.is_some() {
|
if info.product_id.is_some() {
|
||||||
result = info.product_id.unwrap() == prelim_dev_inf.product_id();
|
result = info.product_id.unwrap() == prelim_dev_inf.product_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.class.is_some() {
|
if info.class.is_some() {
|
||||||
result = info.class.unwrap() == prelim_dev_inf.class();
|
result = info.class.unwrap() == prelim_dev_inf.class();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.subclass.is_some() {
|
if info.subclass.is_some() {
|
||||||
result = info.subclass.unwrap() == prelim_dev_inf.subclass();
|
result = info.subclass.unwrap() == prelim_dev_inf.subclass();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.protocol.is_some() {
|
if info.protocol.is_some() {
|
||||||
result = info.protocol.unwrap() == prelim_dev_inf.protocol();
|
result = info.protocol.unwrap() == prelim_dev_inf.protocol();
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
})
|
}) {
|
||||||
{
|
|
||||||
device_info = Some(prelim_dev_inf);
|
device_info = Some(prelim_dev_inf);
|
||||||
break
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,39 +83,69 @@ pub async fn get_device(device_filter: Vec<DeviceFilter>) -> Result<UsbDevice, U
|
||||||
None => return Err(UsbError::DeviceNotFound),
|
None => return Err(UsbError::DeviceNotFound),
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = match device_info.open() {
|
Ok(UsbDescriptor { device_info })
|
||||||
Ok(dev) => dev,
|
|
||||||
Err(_) => return Err(UsbError::CommunicationError),
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(UsbDevice {
|
|
||||||
device_info,
|
|
||||||
device,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for UsbDevice {
|
pub async fn get_device_list(
|
||||||
type UsbDevice = UsbDevice;
|
device_filters: Vec<DeviceFilter>,
|
||||||
type UsbInterface = UsbInterface;
|
) -> Result<Vec<UsbDescriptor>, UsbError> {
|
||||||
|
let devices_info = nusb::list_devices().unwrap();
|
||||||
|
|
||||||
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError> {
|
let mut devices = Vec::new();
|
||||||
let interface = match self.device.claim_interface(number) {
|
for prelim_dev_inf in devices_info {
|
||||||
Ok(inter) => inter,
|
// See if the device exists in the list
|
||||||
Err(_) => return Err(UsbError::CommunicationError),
|
if device_filters.iter().any(|info| {
|
||||||
};
|
let mut result = false;
|
||||||
|
|
||||||
Ok(UsbInterface { interface })
|
if info.vendor_id.is_some() {
|
||||||
}
|
result = info.vendor_id.unwrap() == prelim_dev_inf.vendor_id();
|
||||||
|
}
|
||||||
|
|
||||||
async fn reset(&self) -> Result<(), UsbError> {
|
if info.product_id.is_some() {
|
||||||
match self.device.reset() {
|
result = info.product_id.unwrap() == prelim_dev_inf.product_id();
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn forget(&self) -> Result<(), UsbError> {
|
if devices.is_empty() {
|
||||||
self.reset().await
|
return Err(UsbError::DeviceNotFound);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
@ -140,6 +173,69 @@ impl Device for UsbDevice {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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,7 +9,12 @@ use web_sys::{
|
||||||
};
|
};
|
||||||
|
|
||||||
// Crate stuff
|
// Crate stuff
|
||||||
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError};
|
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError, Descriptor};
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct UsbDescriptor {
|
||||||
|
device: WasmUsbDevice,
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct UsbDevice {
|
pub struct UsbDevice {
|
||||||
|
@ -51,9 +56,7 @@ impl DeviceFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn get_device(
|
pub async fn get_device(device_filter: Vec<DeviceFilter>) -> Result<UsbDescriptor, js_sys::Error> {
|
||||||
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();
|
||||||
|
@ -68,36 +71,33 @@ pub async fn get_device(
|
||||||
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
|
if device_filter.iter().any(|info| {
|
||||||
.iter()
|
let mut result = false;
|
||||||
.any(|info| {
|
|
||||||
let mut result = false;
|
|
||||||
|
|
||||||
if info.vendor_id.is_some() {
|
if info.vendor_id.is_some() {
|
||||||
result = info.vendor_id.unwrap() == device.vendor_id();
|
result = info.vendor_id.unwrap() == device.vendor_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.product_id.is_some() {
|
if info.product_id.is_some() {
|
||||||
result = info.product_id.unwrap() == device.product_id();
|
result = info.product_id.unwrap() == device.product_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.class.is_some() {
|
if info.class.is_some() {
|
||||||
result = info.class.unwrap() == device.device_class();
|
result = info.class.unwrap() == device.device_class();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.subclass.is_some() {
|
if info.subclass.is_some() {
|
||||||
result = info.subclass.unwrap() == device.device_subclass();
|
result = info.subclass.unwrap() == device.device_subclass();
|
||||||
}
|
}
|
||||||
|
|
||||||
if info.protocol.is_some() {
|
if info.protocol.is_some() {
|
||||||
result = info.protocol.unwrap() == device.device_protocol();
|
result = info.protocol.unwrap() == device.device_protocol();
|
||||||
}
|
}
|
||||||
|
|
||||||
result
|
result
|
||||||
})
|
}) {
|
||||||
{
|
|
||||||
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
||||||
return Ok(UsbDevice { device });
|
return Ok(UsbDescriptor { device });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,12 +156,154 @@ pub async fn get_device(
|
||||||
|
|
||||||
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
||||||
|
|
||||||
Ok(UsbDevice { device })
|
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
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn product_id(&self) -> u16 {
|
||||||
|
self.device.vendor_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn vendor_id(&self) -> u16 {
|
||||||
|
self.device.product_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn class(&self) -> u8 {
|
||||||
|
self.device.device_class()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn subclass(&self) -> u8 {
|
||||||
|
self.device.device_subclass()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn manufacturer_string(&self) -> Option<String> {
|
||||||
|
self.device.manufacturer_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn product_string(&self) -> Option<String> {
|
||||||
|
self.device.product_name()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for UsbDevice {
|
impl Device for UsbDevice {
|
||||||
type UsbDevice = UsbDevice;
|
type Interface = UsbInterface;
|
||||||
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 =
|
||||||
|
@ -170,8 +312,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()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -181,12 +323,16 @@ 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(UsbError::CommunicationError),
|
Err(err) => Err(UsbError::CommunicationError(err.as_string().unwrap_or_default())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,7 +341,7 @@ impl Device for UsbDevice {
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(_) => Err(UsbError::CommunicationError),
|
Err(err) => Err(UsbError::CommunicationError(err.as_string().unwrap_or_default())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
37
src/lib.rs
37
src/lib.rs
|
@ -9,24 +9,34 @@
|
||||||
//!
|
//!
|
||||||
//! 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::{Device, Interface, Recipient, ControlType, ControlIn};
|
//! use cross_usb::usb::{Descriptor, Device, Interface, Recipient, ControlType, ControlIn};
|
||||||
//! use cross_usb::device_filter;
|
//! use cross_usb::device_filter;
|
||||||
//!
|
//!
|
||||||
//! // Obtain a device using its VendorID and ProductID
|
//! // Obtain a device descriptor (UsbDescriptor) using a DeviceFilter,
|
||||||
//! let filter = vec![
|
//! // in this case with its VendorID and ProductID
|
||||||
|
//! 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");
|
||||||
//!
|
//!
|
||||||
//! let device = cross_usb::get_device(filter).await.expect("Failed to get device");
|
//! // Open the device that the descriptor is describing
|
||||||
|
//! 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 = device.open_interface(0).await.expect("Failed to open interface");
|
//! let interface = dev.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`
|
||||||
//! 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,
|
||||||
|
@ -41,16 +51,19 @@
|
||||||
//! ```
|
//! ```
|
||||||
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;
|
||||||
|
@ -64,14 +77,13 @@ pub use crate::context::UsbInterface;
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::DeviceFilter;
|
pub use crate::context::DeviceFilter;
|
||||||
|
|
||||||
/// Gets a single device from a list of VendorID and ProductIDs
|
/// Gets a single device descriptor ([UsbDescriptor]) 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},
|
||||||
|
@ -83,6 +95,11 @@ 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,19 +2,49 @@
|
||||||
//! 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 UsbInterface;
|
type Interface;
|
||||||
|
|
||||||
/// Open a specific interface of the device
|
/// Open a specific interface of the device
|
||||||
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError>;
|
async fn open_interface(&self, number: u8) -> Result<Self::Interface, 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]
|
||||||
|
@ -22,7 +52,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 with `nusb` this simply resets the device**
|
/// **Note:** On Native 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
|
||||||
|
@ -87,7 +117,7 @@ pub enum UsbError {
|
||||||
TransferError,
|
TransferError,
|
||||||
|
|
||||||
#[error("device communication failed")]
|
#[error("device communication failed")]
|
||||||
CommunicationError,
|
CommunicationError(String),
|
||||||
|
|
||||||
#[error("device disconnected")]
|
#[error("device disconnected")]
|
||||||
Disconnected,
|
Disconnected,
|
||||||
|
|
Loading…
Reference in a new issue