mirror of
https://github.com/G2-Games/cross-usb.git
synced 2025-04-19 13:22:53 -05:00
Implemented error type, changed how get_device_filter()
works to be more useful
This commit is contained in:
parent
319fae96ad
commit
2ea7fd68c8
5 changed files with 259 additions and 97 deletions
|
@ -52,6 +52,9 @@ tokio-test = "0.4.3"
|
||||||
[profile.release]
|
[profile.release]
|
||||||
opt-level = "s"
|
opt-level = "s"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror = "1.0.56"
|
||||||
|
|
||||||
[package.metadata.wasm-pack.profile.dev.wasm-bindgen]
|
[package.metadata.wasm-pack.profile.dev.wasm-bindgen]
|
||||||
dwarf-debug-info = true
|
dwarf-debug-info = true
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use std::error::Error;
|
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError};
|
||||||
|
|
||||||
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient};
|
|
||||||
|
|
||||||
pub struct UsbDevice {
|
pub struct UsbDevice {
|
||||||
device_info: nusb::DeviceInfo,
|
device_info: nusb::DeviceInfo,
|
||||||
|
@ -11,7 +9,7 @@ pub struct UsbInterface {
|
||||||
interface: nusb::Interface,
|
interface: nusb::Interface,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, Box<dyn Error>> {
|
pub async fn get_device(vendor_id: u16, product_id: u16) -> 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;
|
||||||
|
@ -24,10 +22,13 @@ pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, Bo
|
||||||
|
|
||||||
let device_info = match device_info {
|
let device_info = match device_info {
|
||||||
Some(dev) => dev,
|
Some(dev) => dev,
|
||||||
None => return Err("Device not found".into()),
|
None => return Err(UsbError::DeviceNotFound),
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = device_info.open()?;
|
let device = match device_info.open() {
|
||||||
|
Ok(dev) => dev,
|
||||||
|
Err(_) => return Err(UsbError::CommunicationError)
|
||||||
|
};
|
||||||
|
|
||||||
Ok(UsbDevice {
|
Ok(UsbDevice {
|
||||||
device_info,
|
device_info,
|
||||||
|
@ -35,38 +36,87 @@ pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, Bo
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Clone)]
|
#[derive(PartialEq, Clone)]
|
||||||
pub struct FilterTuple(pub u16, pub u16);
|
pub struct DeviceFilter {
|
||||||
|
pub vendor_id: Option<u16>,
|
||||||
|
pub product_id: Option<u16>,
|
||||||
|
pub class: Option<u8>,
|
||||||
|
pub subclass: Option<u8>,
|
||||||
|
pub protocol: Option<u8>,
|
||||||
|
serial_number: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceFilter {
|
||||||
|
pub fn serial_number(&self) -> &Option<String> {
|
||||||
|
&self.serial_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DeviceFilter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
vendor_id: None,
|
||||||
|
product_id: None,
|
||||||
|
class: None,
|
||||||
|
subclass: None,
|
||||||
|
protocol: None,
|
||||||
|
serial_number: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_device_filter(
|
pub async fn get_device_filter(
|
||||||
device_filter: Vec<FilterTuple>,
|
device_filter: Vec<DeviceFilter>,
|
||||||
) -> Result<UsbDevice, Box<dyn Error>> {
|
) -> 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 device in devices {
|
for prelim_dev_inf in devices {
|
||||||
match device_filter
|
// See if the device exists in the list
|
||||||
.iter()
|
if device_filter.iter().position(|info|
|
||||||
.position(|i| i == &FilterTuple(device.vendor_id(), device.product_id()))
|
{
|
||||||
{
|
let mut result = false;
|
||||||
Some(_) => {
|
|
||||||
device_info = Some(device);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
None => device_info = None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if device_info.is_none() {
|
if info.vendor_id.is_some() {
|
||||||
return Err("No devices from the list found".into());
|
result = info.vendor_id.unwrap() == prelim_dev_inf.vendor_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.product_id.is_some() {
|
||||||
|
result = info.product_id.unwrap() == prelim_dev_inf.product_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.serial_number().is_some() && prelim_dev_inf.serial_number().is_some() {
|
||||||
|
result = info.serial_number().as_ref().unwrap() == &prelim_dev_inf.serial_number().unwrap().to_owned();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
|
).is_some() {
|
||||||
|
device_info = Some(prelim_dev_inf)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let device_info = match device_info {
|
let device_info = match device_info {
|
||||||
Some(dev) => dev,
|
Some(dev) => dev,
|
||||||
None => return Err("Device not found".into()),
|
None => return Err(UsbError::DeviceNotFound),
|
||||||
};
|
};
|
||||||
|
|
||||||
let device = device_info.open()?;
|
let device = match device_info.open() {
|
||||||
|
Ok(dev) => dev,
|
||||||
|
Err(_) => return Err(UsbError::CommunicationError),
|
||||||
|
};
|
||||||
|
|
||||||
Ok(UsbDevice {
|
Ok(UsbDevice {
|
||||||
device_info,
|
device_info,
|
||||||
|
@ -78,19 +128,19 @@ impl Device for UsbDevice {
|
||||||
type UsbDevice = UsbDevice;
|
type UsbDevice = UsbDevice;
|
||||||
type UsbInterface = UsbInterface;
|
type UsbInterface = UsbInterface;
|
||||||
|
|
||||||
async fn open_interface(&self, number: u8) -> Result<UsbInterface, Box<dyn Error>> {
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError> {
|
||||||
let interface = match self.device.claim_interface(number) {
|
let interface = match self.device.claim_interface(number) {
|
||||||
Ok(inter) => inter,
|
Ok(inter) => inter,
|
||||||
Err(e) => return Err(e.into()),
|
Err(_) => return Err(UsbError::CommunicationError),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(UsbInterface { interface })
|
Ok(UsbInterface { interface })
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reset(&self) -> Result<(), Box<dyn Error>> {
|
async fn reset(&self) -> Result<(), UsbError> {
|
||||||
match self.device.reset() {
|
match self.device.reset() {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(e) => Err(e.into()),
|
Err(_) => Err(UsbError::CommunicationError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,28 +170,36 @@ impl Device for UsbDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Interface<'a> for UsbInterface {
|
impl<'a> Interface<'a> for UsbInterface {
|
||||||
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, Box<dyn Error>> {
|
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, UsbError> {
|
||||||
Ok(self.interface.control_in(data.into()).await.into_result()?)
|
let result = match self.interface.control_in(data.into()).await.into_result() {
|
||||||
|
Ok(res) => res,
|
||||||
|
Err(_) => return Err(UsbError::TransferError),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn control_out(&self, data: ControlOut<'a>) -> Result<(), Box<dyn Error>> {
|
async fn control_out(&self, data: ControlOut<'a>) -> Result<usize, UsbError> {
|
||||||
match self.interface.control_out(data.into()).await.into_result() {
|
match self.interface.control_out(data.into()).await.into_result() {
|
||||||
Ok(_) => Ok(()),
|
Ok(bytes) => Ok(bytes.actual_length()),
|
||||||
Err(e) => Err(e.into()),
|
Err(_) => Err(UsbError::TransferError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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>, UsbError> {
|
||||||
let request_buffer = nusb::transfer::RequestBuffer::new(length);
|
let request_buffer = nusb::transfer::RequestBuffer::new(length);
|
||||||
|
|
||||||
Ok(self
|
match self
|
||||||
.interface
|
.interface
|
||||||
.bulk_in(endpoint, request_buffer)
|
.bulk_in(endpoint, request_buffer)
|
||||||
.await
|
.await
|
||||||
.into_result()?)
|
.into_result() {
|
||||||
|
Ok(res) => Ok(res),
|
||||||
|
Err(_) => Err(UsbError::TransferError),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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, UsbError> {
|
||||||
match self
|
match self
|
||||||
.interface
|
.interface
|
||||||
.bulk_out(endpoint, data.to_vec())
|
.bulk_out(endpoint, data.to_vec())
|
||||||
|
@ -149,7 +207,7 @@ impl<'a> Interface<'a> for UsbInterface {
|
||||||
.into_result()
|
.into_result()
|
||||||
{
|
{
|
||||||
Ok(len) => Ok(len.actual_length()),
|
Ok(len) => Ok(len.actual_length()),
|
||||||
Err(e) => Err(e.into()),
|
Err(_) => Err(UsbError::TransferError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
#![cfg_attr(debug_assertions, allow(dead_code, unused_imports))]
|
#![cfg_attr(debug_assertions, allow(dead_code, unused_imports))]
|
||||||
use std::error::Error;
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
|
||||||
use js_sys::{Array, Object, Promise, Uint8Array};
|
use js_sys::{Array, Object, Promise, Uint8Array};
|
||||||
use wasm_bindgen_futures::JsFuture;
|
use wasm_bindgen_futures::JsFuture;
|
||||||
use web_sys::{
|
use web_sys::{
|
||||||
console, UsbControlTransferParameters, UsbDevice as WasmUsbDevice, UsbDeviceRequestOptions,
|
UsbControlTransferParameters, UsbDevice as WasmUsbDevice, UsbDeviceRequestOptions,
|
||||||
UsbInTransferResult, UsbOutTransferResult, UsbRecipient, UsbRequestType,
|
UsbInTransferResult, UsbOutTransferResult, UsbRecipient, UsbRequestType,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Crate stuff
|
// Crate stuff
|
||||||
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient};
|
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient, UsbError};
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub struct UsbDevice {
|
pub struct UsbDevice {
|
||||||
|
@ -22,6 +21,36 @@ pub struct UsbInterface {
|
||||||
device: WasmUsbDevice,
|
device: WasmUsbDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
#[derive(PartialEq, Clone)]
|
||||||
|
pub struct DeviceFilter {
|
||||||
|
pub vendor_id: Option<u16>,
|
||||||
|
pub product_id: Option<u16>,
|
||||||
|
pub class: Option<u8>,
|
||||||
|
pub subclass: Option<u8>,
|
||||||
|
pub protocol: Option<u8>,
|
||||||
|
serial_number: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeviceFilter {
|
||||||
|
pub fn serial_number(&self) -> &Option<String> {
|
||||||
|
&self.serial_number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DeviceFilter {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
vendor_id: None,
|
||||||
|
product_id: None,
|
||||||
|
class: None,
|
||||||
|
subclass: None,
|
||||||
|
protocol: None,
|
||||||
|
serial_number: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, js_sys::Error> {
|
pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, js_sys::Error> {
|
||||||
let window = web_sys::window().unwrap();
|
let window = web_sys::window().unwrap();
|
||||||
|
@ -71,13 +100,9 @@ pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, js
|
||||||
Ok(UsbDevice { device })
|
Ok(UsbDevice { device })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
|
||||||
#[derive(PartialEq, Eq, Clone)]
|
|
||||||
pub struct FilterTuple(pub u16, pub u16);
|
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
pub async fn get_device_filter(
|
pub async fn get_device_filter(
|
||||||
device_filter: Vec<FilterTuple>,
|
device_filter: Vec<DeviceFilter>,
|
||||||
) -> Result<UsbDevice, js_sys::Error> {
|
) -> Result<UsbDevice, js_sys::Error> {
|
||||||
let window = web_sys::window().unwrap();
|
let window = web_sys::window().unwrap();
|
||||||
|
|
||||||
|
@ -91,31 +116,93 @@ pub async fn get_device_filter(
|
||||||
for js_device in device_list {
|
for js_device in device_list {
|
||||||
let device: WasmUsbDevice = js_device.into();
|
let device: WasmUsbDevice = js_device.into();
|
||||||
|
|
||||||
for filter_info in &device_filter {
|
if device_filter.iter().position(|info|
|
||||||
if device.vendor_id() == filter_info.0 && device.product_id() == filter_info.1 {
|
{
|
||||||
let _open_promise = JsFuture::from(Promise::resolve(&device.open())).await?;
|
let mut result = false;
|
||||||
|
|
||||||
return Ok(UsbDevice { device });
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
if info.serial_number().is_some() && device.serial_number().is_some() {
|
||||||
|
result = info.serial_number().as_ref().unwrap() == &device.serial_number().unwrap().to_owned();
|
||||||
|
}
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
).is_some() {
|
||||||
|
return Ok(UsbDevice { device });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let arr = Array::new();
|
let arr = Array::new();
|
||||||
for device in device_filter {
|
for filter in device_filter {
|
||||||
let filter1 = js_sys::Object::new();
|
let js_filter = js_sys::Object::new();
|
||||||
js_sys::Reflect::set(
|
if let Some(vid) = filter.vendor_id {
|
||||||
&filter1,
|
js_sys::Reflect::set(
|
||||||
&JsValue::from_str("vendorId"),
|
&js_filter,
|
||||||
&JsValue::from(device.0),
|
&JsValue::from_str("vendorId"),
|
||||||
)
|
&JsValue::from(vid),
|
||||||
.unwrap();
|
)
|
||||||
js_sys::Reflect::set(
|
.unwrap();
|
||||||
&filter1,
|
}
|
||||||
&JsValue::from_str("productId"),
|
if let Some(pid) = filter.product_id {
|
||||||
&JsValue::from(device.1),
|
js_sys::Reflect::set(
|
||||||
)
|
&js_filter,
|
||||||
.unwrap();
|
&JsValue::from_str("productId"),
|
||||||
arr.push(&filter1);
|
&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();
|
||||||
|
}
|
||||||
|
if let Some(serial) = filter.serial_number {
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&js_filter,
|
||||||
|
&JsValue::from_str("serialNumber"),
|
||||||
|
&JsValue::from(serial),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
arr.push(&js_filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
let filters = JsValue::from(&arr);
|
let filters = JsValue::from(&arr);
|
||||||
|
@ -134,16 +221,15 @@ impl Device for UsbDevice {
|
||||||
type UsbDevice = UsbDevice;
|
type UsbDevice = UsbDevice;
|
||||||
type UsbInterface = UsbInterface;
|
type UsbInterface = UsbInterface;
|
||||||
|
|
||||||
async fn open_interface(&self, number: u8) -> Result<UsbInterface, Box<dyn Error>> {
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError> {
|
||||||
let dev_promise =
|
let dev_promise =
|
||||||
JsFuture::from(Promise::resolve(&self.device.claim_interface(number))).await;
|
JsFuture::from(Promise::resolve(&self.device.claim_interface(number))).await;
|
||||||
|
|
||||||
// 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(_) => {
|
||||||
console::log_1(&err.clone());
|
return Err(UsbError::CommunicationError);
|
||||||
return Err(format!("{:?}", err).into());
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -152,14 +238,14 @@ impl Device for UsbDevice {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reset(&self) -> Result<(), Box<dyn Error>> {
|
async fn reset(&self) -> Result<(), UsbError> {
|
||||||
let promise = Promise::resolve(&self.device.reset());
|
let promise = Promise::resolve(&self.device.reset());
|
||||||
|
|
||||||
let result = JsFuture::from(promise).await;
|
let result = JsFuture::from(promise).await;
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
Ok(_) => Ok(()),
|
Ok(_) => Ok(()),
|
||||||
Err(_) => Err("cancelled".into()),
|
Err(_) => Err(UsbError::CommunicationError),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,7 +275,7 @@ impl Device for UsbDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Interface<'a> for UsbInterface {
|
impl<'a> Interface<'a> for UsbInterface {
|
||||||
async fn control_in(&self, data: crate::usb::ControlIn) -> Result<Vec<u8>, Box<dyn Error>> {
|
async fn control_in(&self, data: crate::usb::ControlIn) -> Result<Vec<u8>, UsbError> {
|
||||||
let length = data.length;
|
let length = data.length;
|
||||||
let params: UsbControlTransferParameters = data.into();
|
let params: UsbControlTransferParameters = data.into();
|
||||||
|
|
||||||
|
@ -198,12 +284,12 @@ impl<'a> Interface<'a> for UsbInterface {
|
||||||
|
|
||||||
let transfer_result: UsbInTransferResult = match result {
|
let transfer_result: UsbInTransferResult = match result {
|
||||||
Ok(res) => res.into(),
|
Ok(res) => res.into(),
|
||||||
Err(err) => return Err(format!("Error {:?}", err).into()),
|
Err(_) => return Err(UsbError::TransferError),
|
||||||
};
|
};
|
||||||
|
|
||||||
let data = match transfer_result.data() {
|
let data = match transfer_result.data() {
|
||||||
Some(res) => res.buffer(),
|
Some(res) => res.buffer(),
|
||||||
None => return Err("No data returned".into()),
|
None => return Err(UsbError::TransferError),
|
||||||
};
|
};
|
||||||
|
|
||||||
let array = Uint8Array::new(&data);
|
let array = Uint8Array::new(&data);
|
||||||
|
@ -211,37 +297,36 @@ impl<'a> Interface<'a> for UsbInterface {
|
||||||
Ok(array.to_vec())
|
Ok(array.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn control_out(&self, data: crate::usb::ControlOut<'a>) -> Result<(), Box<dyn Error>> {
|
async fn control_out(&self, data: crate::usb::ControlOut<'a>) -> Result<usize, UsbError> {
|
||||||
let array = Uint8Array::from(data.data);
|
let array = Uint8Array::from(data.data);
|
||||||
let array_obj = Object::try_from(&array).unwrap();
|
let array_obj = Object::try_from(&array).unwrap();
|
||||||
let params: UsbControlTransferParameters = data.into();
|
let params: UsbControlTransferParameters = data.into();
|
||||||
|
|
||||||
let promise = Promise::resolve(
|
let result: UsbOutTransferResult = match JsFuture::from(Promise::resolve(
|
||||||
&self
|
&self
|
||||||
.device
|
.device
|
||||||
.control_transfer_out_with_buffer_source(¶ms, array_obj),
|
.control_transfer_out_with_buffer_source(¶ms, array_obj),
|
||||||
);
|
)).await {
|
||||||
let result = JsFuture::from(promise).await;
|
Ok(res) => res.into(),
|
||||||
|
Err(_) => return Err(UsbError::TransferError)
|
||||||
|
};
|
||||||
|
|
||||||
match result {
|
Ok(result.bytes_written() as usize)
|
||||||
Ok(_) => Ok(()),
|
|
||||||
Err(err) => Err(format!("{:?}", err).into()),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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>, UsbError> {
|
||||||
let promise = Promise::resolve(&self.device.transfer_in(endpoint, length as u32));
|
let promise = Promise::resolve(&self.device.transfer_in(endpoint, length as u32));
|
||||||
|
|
||||||
let result = JsFuture::from(promise).await;
|
let result = JsFuture::from(promise).await;
|
||||||
|
|
||||||
let transfer_result: UsbInTransferResult = match result {
|
let transfer_result: UsbInTransferResult = match result {
|
||||||
Ok(res) => res.into(),
|
Ok(res) => res.into(),
|
||||||
Err(err) => return Err(format!("Error {:?}", err).into()),
|
Err(_) => return Err(UsbError::TransferError),
|
||||||
};
|
};
|
||||||
|
|
||||||
let data = match transfer_result.data() {
|
let data = match transfer_result.data() {
|
||||||
Some(res) => res.buffer(),
|
Some(res) => res.buffer(),
|
||||||
None => return Err("No data returned".into()),
|
None => return Err(UsbError::TransferError),
|
||||||
};
|
};
|
||||||
|
|
||||||
let array = Uint8Array::new(&data);
|
let array = Uint8Array::new(&data);
|
||||||
|
@ -249,7 +334,7 @@ impl<'a> Interface<'a> for UsbInterface {
|
||||||
Ok(array.to_vec())
|
Ok(array.to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
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, UsbError> {
|
||||||
let array = Uint8Array::from(data);
|
let array = Uint8Array::from(data);
|
||||||
let array_obj = Object::try_from(&array).unwrap();
|
let array_obj = Object::try_from(&array).unwrap();
|
||||||
|
|
||||||
|
@ -263,7 +348,7 @@ impl<'a> Interface<'a> for UsbInterface {
|
||||||
|
|
||||||
let transfer_result: UsbOutTransferResult = match result {
|
let transfer_result: UsbOutTransferResult = match result {
|
||||||
Ok(res) => res.into(),
|
Ok(res) => res.into(),
|
||||||
Err(err) => return Err(format!("Error {:?}", err).into()),
|
Err(_) => return Err(UsbError::TransferError),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(transfer_result.bytes_written() as usize)
|
Ok(transfer_result.bytes_written() as usize)
|
||||||
|
|
|
@ -51,7 +51,7 @@ pub use crate::context::UsbInterface;
|
||||||
/// A single Device ID and Product ID pair to find when looking
|
/// A single Device ID and Product ID pair to find when looking
|
||||||
/// for new USB devices using [get_device_filter]
|
/// for new USB devices using [get_device_filter]
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::FilterTuple;
|
pub use crate::context::DeviceFilter;
|
||||||
|
|
||||||
/// Gets a single device from the VendorID and ProductID
|
/// Gets a single device from the VendorID and ProductID
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
|
30
src/usb.rs
30
src/usb.rs
|
@ -3,7 +3,7 @@
|
||||||
//! 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 thiserror::Error;
|
||||||
|
|
||||||
/// A unique USB device
|
/// A unique USB device
|
||||||
pub trait Device {
|
pub trait Device {
|
||||||
|
@ -14,10 +14,10 @@ pub trait Device {
|
||||||
type UsbInterface;
|
type UsbInterface;
|
||||||
|
|
||||||
/// Open a specific interface of the device
|
/// Open a specific interface of the device
|
||||||
async fn open_interface(&self, number: u8) -> Result<UsbInterface, Box<dyn Error>>;
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, UsbError>;
|
||||||
|
|
||||||
/// 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<(), UsbError>;
|
||||||
|
|
||||||
/// 16 bit device Product ID
|
/// 16 bit device Product ID
|
||||||
async fn product_id(&self) -> u16;
|
async fn product_id(&self) -> u16;
|
||||||
|
@ -44,20 +44,20 @@ pub trait Device {
|
||||||
pub trait Interface<'a> {
|
pub trait Interface<'a> {
|
||||||
/// A USB control in transfer (device to host)
|
/// A USB control in transfer (device to host)
|
||||||
/// Returns a [Result] with the bytes in a `Vec<u8>`
|
/// Returns a [Result] with the bytes in a `Vec<u8>`
|
||||||
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, Box<dyn Error>>;
|
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, UsbError>;
|
||||||
|
|
||||||
/// A USB control out transfer (host to device)
|
/// A USB control out transfer (host to device)
|
||||||
async fn control_out(&self, data: ControlOut<'a>) -> Result<(), Box<dyn Error>>;
|
async fn control_out(&self, data: ControlOut<'a>) -> Result<usize, UsbError>;
|
||||||
|
|
||||||
/// A USB bulk in transfer (device to host)
|
/// A USB bulk in transfer (device to host)
|
||||||
/// It takes in a bulk endpoint to send to along with the length of
|
/// It takes in a bulk endpoint to send to along with the length of
|
||||||
/// data to read, and returns a [Result] with the bytes
|
/// 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>, UsbError>;
|
||||||
|
|
||||||
/// A USB bulk out transfer (host to device).
|
/// A USB bulk out transfer (host to device).
|
||||||
/// It takes in a bulk endpoint to send to along with some data as
|
/// 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
|
/// 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, UsbError>;
|
||||||
|
|
||||||
/* Interrupt transfers are a work in progress
|
/* Interrupt transfers are a work in progress
|
||||||
async fn interrupt_in(&self, _endpoint: u8, _buf: Vec<u8>) {
|
async fn interrupt_in(&self, _endpoint: u8, _buf: Vec<u8>) {
|
||||||
|
@ -70,6 +70,22 @@ pub trait Interface<'a> {
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// An error from a USB interface
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum UsbError {
|
||||||
|
#[error("device not found")]
|
||||||
|
DeviceNotFound,
|
||||||
|
|
||||||
|
#[error("device transfer failed")]
|
||||||
|
TransferError,
|
||||||
|
|
||||||
|
#[error("device communication failed")]
|
||||||
|
CommunicationError,
|
||||||
|
|
||||||
|
#[error("device disconnected")]
|
||||||
|
Disconnected,
|
||||||
|
}
|
||||||
|
|
||||||
/// The type of USB transfer
|
/// The type of USB transfer
|
||||||
pub enum ControlType {
|
pub enum ControlType {
|
||||||
Standard = 0,
|
Standard = 0,
|
||||||
|
|
Loading…
Reference in a new issue