mirror of
https://github.com/G2-Games/cross-usb.git
synced 2025-04-20 13:52:53 -05:00
Compare commits
No commits in common. "bbdb47add7892d3f1cce6433fb7e1a7631c547d1" and "092cb0583adea570d6f662cd6b7acf616dac6239" have entirely different histories.
bbdb47add7
...
092cb0583a
5 changed files with 46 additions and 104 deletions
|
@ -1,6 +1,6 @@
|
||||||
[package]
|
[package]
|
||||||
name = "cross_usb"
|
name = "cross_usb"
|
||||||
version = "0.3.1"
|
version = "0.2.3"
|
||||||
authors = ["G2-Games <ke0bhogsg@gmail.com>"]
|
authors = ["G2-Games <ke0bhogsg@gmail.com>"]
|
||||||
repository = "https://github.com/G2-Games/cross-usb"
|
repository = "https://github.com/G2-Games/cross-usb"
|
||||||
documentation = "https://docs.rs/cross_usb"
|
documentation = "https://docs.rs/cross_usb"
|
||||||
|
|
|
@ -1,34 +1,18 @@
|
||||||
use crate::usb::{
|
use crate::usb::{
|
||||||
ControlIn, ControlOut, ControlType, UsbDescriptor, UsbDevice, UsbInterface, Recipient, UsbError,
|
ControlIn, ControlOut, ControlType, Descriptor, Device, Interface, Recipient, UsbError,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
pub struct UsbDescriptor {
|
||||||
pub struct Descriptor {
|
|
||||||
device_info: nusb::DeviceInfo,
|
device_info: nusb::DeviceInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
pub struct UsbDevice {
|
||||||
pub struct Device {
|
device_info: UsbDescriptor,
|
||||||
device_info: Descriptor,
|
|
||||||
device: nusb::Device,
|
device: nusb::Device,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for Device {
|
pub struct UsbInterface {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:?}", self.device_info)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct Interface {
|
|
||||||
interface: nusb::Interface,
|
interface: nusb::Interface,
|
||||||
number: u8,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for Interface {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "Interface {:?}", self.number)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Clone, Default)]
|
#[derive(PartialEq, Clone, Default)]
|
||||||
|
@ -58,9 +42,7 @@ impl DeviceFilter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_device(
|
pub async fn get_device(device_filters: Vec<DeviceFilter>) -> Result<UsbDescriptor, UsbError> {
|
||||||
device_filters: Vec<DeviceFilter>
|
|
||||||
) -> Result<Descriptor, UsbError> {
|
|
||||||
let devices = nusb::list_devices().unwrap();
|
let devices = nusb::list_devices().unwrap();
|
||||||
|
|
||||||
let mut device_info = None;
|
let mut device_info = None;
|
||||||
|
@ -101,12 +83,12 @@ pub async fn get_device(
|
||||||
None => return Err(UsbError::DeviceNotFound),
|
None => return Err(UsbError::DeviceNotFound),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Descriptor { device_info })
|
Ok(UsbDescriptor { device_info })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_device_list(
|
pub async fn get_device_list(
|
||||||
device_filters: Vec<DeviceFilter>,
|
device_filters: Vec<DeviceFilter>,
|
||||||
) -> Result<impl Iterator<Item = Descriptor>, UsbError> {
|
) -> Result<Vec<UsbDescriptor>, UsbError> {
|
||||||
let devices_info = nusb::list_devices().unwrap();
|
let devices_info = nusb::list_devices().unwrap();
|
||||||
|
|
||||||
let mut devices = Vec::new();
|
let mut devices = Vec::new();
|
||||||
|
@ -145,16 +127,16 @@ pub async fn get_device_list(
|
||||||
return Err(UsbError::DeviceNotFound);
|
return Err(UsbError::DeviceNotFound);
|
||||||
}
|
}
|
||||||
|
|
||||||
let devices_opened: Vec<Descriptor> = devices
|
let devices_opened: Vec<UsbDescriptor> = devices
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|d| Descriptor { device_info: d })
|
.map(|d| UsbDescriptor { device_info: d })
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
Ok(devices_opened.into_iter())
|
Ok(devices_opened)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsbDescriptor for Descriptor {
|
impl Descriptor for UsbDescriptor {
|
||||||
type Device = Device;
|
type Device = UsbDevice;
|
||||||
|
|
||||||
async fn open(self) -> Result<Self::Device, UsbError> {
|
async fn open(self) -> Result<Self::Device, UsbError> {
|
||||||
match self.device_info.open() {
|
match self.device_info.open() {
|
||||||
|
@ -191,8 +173,8 @@ impl UsbDescriptor for Descriptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UsbDevice for Device {
|
impl Device for UsbDevice {
|
||||||
type Interface = Interface;
|
type Interface = UsbInterface;
|
||||||
|
|
||||||
async fn open_interface(&self, number: u8) -> Result<Self::Interface, UsbError> {
|
async fn open_interface(&self, number: u8) -> Result<Self::Interface, UsbError> {
|
||||||
let interface = match self.device.claim_interface(number) {
|
let interface = match self.device.claim_interface(number) {
|
||||||
|
@ -200,10 +182,7 @@ impl UsbDevice for Device {
|
||||||
Err(err) => return Err(UsbError::CommunicationError(err.to_string())),
|
Err(err) => return Err(UsbError::CommunicationError(err.to_string())),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Interface {
|
Ok(UsbInterface { interface })
|
||||||
interface,
|
|
||||||
number
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn detach_and_open_interface(&self, number: u8) -> Result<Self::Interface, UsbError> {
|
async fn detach_and_open_interface(&self, number: u8) -> Result<Self::Interface, UsbError> {
|
||||||
|
@ -212,10 +191,7 @@ impl UsbDevice for Device {
|
||||||
Err(err) => return Err(UsbError::CommunicationError(err.to_string())),
|
Err(err) => return Err(UsbError::CommunicationError(err.to_string())),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Interface {
|
Ok(UsbInterface { interface })
|
||||||
interface,
|
|
||||||
number
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn reset(&self) -> Result<(), UsbError> {
|
async fn reset(&self) -> Result<(), UsbError> {
|
||||||
|
@ -254,13 +230,13 @@ impl UsbDevice for Device {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Device {
|
impl Drop for UsbDevice {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let _ = self.device.reset();
|
let _ = self.device.reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> UsbInterface<'a> for Interface {
|
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() {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
|
|
|
@ -14,19 +14,16 @@ use crate::usb::{
|
||||||
};
|
};
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UsbDescriptor {
|
pub struct UsbDescriptor {
|
||||||
device: WasmUsbDevice,
|
device: WasmUsbDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UsbDevice {
|
pub struct UsbDevice {
|
||||||
device: WasmUsbDevice,
|
device: WasmUsbDevice,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[wasm_bindgen]
|
#[wasm_bindgen]
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UsbInterface {
|
pub struct UsbInterface {
|
||||||
device: WasmUsbDevice,
|
device: WasmUsbDevice,
|
||||||
_number: u8,
|
_number: u8,
|
||||||
|
|
73
src/lib.rs
73
src/lib.rs
|
@ -7,7 +7,7 @@
|
||||||
//! and comparable to the very popular `libusb` C library. Web Assembly support is provided by [web-sys](https://docs.rs/web-sys/latest/web_sys/)
|
//! and comparable to the very popular `libusb` C library. Web Assembly support is provided by [web-sys](https://docs.rs/web-sys/latest/web_sys/)
|
||||||
//! with the [Web USB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
|
//! with the [Web USB API](https://developer.mozilla.org/en-US/docs/Web/API/WebUSB_API).
|
||||||
//!
|
//!
|
||||||
//! When an [`Interface`] is dropped, it is automatically released.
|
//! When a [UsbInterface] is dropped, it is automatically released.
|
||||||
//!
|
//!
|
||||||
//! ### CURRENT LIMITATIONS:
|
//! ### CURRENT LIMITATIONS:
|
||||||
//! * Hotplug support is not implemented. Waiting on [hotplug support in nusb](https://github.com/kevinmehall/nusb/pull/20).
|
//! * Hotplug support is not implemented. Waiting on [hotplug support in nusb](https://github.com/kevinmehall/nusb/pull/20).
|
||||||
|
@ -19,11 +19,10 @@
|
||||||
//! ## Example:
|
//! ## Example:
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! # tokio_test::block_on(async {
|
//! # tokio_test::block_on(async {
|
||||||
//! use cross_usb::prelude::*;
|
//! use cross_usb::usb::{Descriptor, Device, Interface, Recipient, ControlType, ControlIn};
|
||||||
//! use cross_usb::usb::{Recipient, ControlType, ControlIn};
|
|
||||||
//! use cross_usb::device_filter;
|
//! use cross_usb::device_filter;
|
||||||
//!
|
//!
|
||||||
//! // Obtain a device descriptor using a DeviceFilter,
|
//! // Obtain a device descriptor (UsbDescriptor) using a DeviceFilter,
|
||||||
//! // in this case with its VendorID and ProductID
|
//! // in this case with its VendorID and ProductID
|
||||||
//! let filters = vec![
|
//! let filters = vec![
|
||||||
//! device_filter!{vendor_id: 0x054c, product_id: 0x00c9}
|
//! device_filter!{vendor_id: 0x054c, product_id: 0x00c9}
|
||||||
|
@ -52,18 +51,6 @@
|
||||||
//! ```
|
//! ```
|
||||||
pub mod usb;
|
pub mod usb;
|
||||||
|
|
||||||
/// This prelude imports all the necessary traits needed to actually use USB
|
|
||||||
/// devices and interfaces.
|
|
||||||
///
|
|
||||||
/// ```
|
|
||||||
/// use cross_usb::prelude::*;
|
|
||||||
/// ```
|
|
||||||
pub mod prelude {
|
|
||||||
pub use crate::usb::UsbDescriptor;
|
|
||||||
pub use crate::usb::UsbDevice;
|
|
||||||
pub use crate::usb::UsbInterface;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The context contains the platform specific implementation of the USB transfers
|
/// 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"]
|
||||||
|
@ -74,25 +61,23 @@ mod context;
|
||||||
mod context;
|
mod context;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
/// A descriptor of a USB device, containing information about a device
|
/// An implementation of a USB device descriptor
|
||||||
/// without claiming it
|
pub use crate::context::UsbDescriptor;
|
||||||
pub use crate::context::Descriptor;
|
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
/// A USB device, you must open an [`Interface`] to perform transfers
|
/// An implementation of a USB device
|
||||||
pub use crate::context::Device;
|
pub use crate::context::UsbDevice;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
/// A USB interface with which to perform transfers on
|
/// An implementation of a USB interface
|
||||||
pub use crate::context::Interface;
|
pub use crate::context::UsbInterface;
|
||||||
|
|
||||||
/// Information about a USB device for use in [`get_device`]
|
/// Information about a USB device for finding it while trying
|
||||||
/// or [`get_device_list`]
|
/// to look for new USB devices using [get_device]
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::DeviceFilter;
|
pub use crate::context::DeviceFilter;
|
||||||
|
|
||||||
/// Gets a single (the first found) device as a [`Descriptor`] from a list of VendorID
|
/// Gets a single device descriptor ([UsbDescriptor]) from a list of VendorID and ProductIDs
|
||||||
/// and ProductIDs
|
|
||||||
///
|
///
|
||||||
/// ## Example
|
/// ## Example
|
||||||
/// ```no_run
|
/// ```no_run
|
||||||
|
@ -104,38 +89,22 @@ pub use crate::context::DeviceFilter;
|
||||||
/// device_filter!{vendor_id: 0x054c},
|
/// device_filter!{vendor_id: 0x054c},
|
||||||
/// ];
|
/// ];
|
||||||
///
|
///
|
||||||
/// let device = get_device(filter).await.expect("Could not find device matching filters");
|
/// let device = get_device(filter).await.expect("Could not find device in list");
|
||||||
/// # })
|
/// # })
|
||||||
/// ```
|
/// ```
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::get_device;
|
pub use crate::context::get_device;
|
||||||
|
|
||||||
/// Gets a list of [`Descriptor`]s from a list of VendorID and ProductIDs
|
/// Gets a list of devices from a list of VendorID and ProductIDs
|
||||||
///
|
|
||||||
/// ## Example
|
|
||||||
/// ```no_run
|
|
||||||
/// # tokio_test::block_on(async {
|
|
||||||
/// use cross_usb::{get_device_list, DeviceFilter, device_filter};
|
|
||||||
///
|
|
||||||
/// let filter = vec![
|
|
||||||
/// device_filter!{vendor_id: 0x054c, product_id: 0x00c9},
|
|
||||||
/// device_filter!{vendor_id: 0x054c},
|
|
||||||
/// ];
|
|
||||||
///
|
|
||||||
/// let device_list = get_device_list(filter).await.expect("Could not find device matching filters");
|
|
||||||
///
|
|
||||||
/// /* Do something with the list of devices... */
|
|
||||||
/// # })
|
|
||||||
/// ```
|
|
||||||
#[cfg(not(target_family = "wasm"))]
|
#[cfg(not(target_family = "wasm"))]
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::context::get_device_list;
|
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.
|
||||||
/// You may use as many or as few of them as you need, the rest
|
/// You may use as many or as few of them as you need, the rest
|
||||||
/// of the values will be filled with [`None`].
|
/// of the values will be filled with [None].
|
||||||
///
|
///
|
||||||
/// ## Usage
|
/// ## Usage
|
||||||
/// ```
|
/// ```
|
||||||
|
@ -143,11 +112,11 @@ pub use crate::context::get_device_list;
|
||||||
///
|
///
|
||||||
/// // Example with all fields filled
|
/// // Example with all fields filled
|
||||||
/// device_filter!{
|
/// device_filter!{
|
||||||
/// vendor_id: 0x054c, // u16
|
/// vendor_id: 0x054c,
|
||||||
/// product_id: 0x0186, // u16
|
/// product_id: 0x0186,
|
||||||
/// class: 0xFF, // u8
|
/// class: 0xFF,
|
||||||
/// subclass: 0x02, // u8
|
/// subclass: 0x02,
|
||||||
/// protocol: 0x15, // u8
|
/// protocol: 0x15,
|
||||||
/// };
|
/// };
|
||||||
/// ```
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
|
10
src/usb.rs
10
src/usb.rs
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub trait UsbDescriptor {
|
pub trait Descriptor {
|
||||||
/// A unique USB Device
|
/// A unique USB Device
|
||||||
type Device;
|
type Device;
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ pub trait UsbDescriptor {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A unique USB device
|
/// A unique USB device
|
||||||
pub trait UsbDevice {
|
pub trait Device {
|
||||||
/// A unique Interface on a USB Device
|
/// A unique Interface on a USB Device
|
||||||
type Interface;
|
type Interface;
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ pub trait UsbDevice {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specific interface of a USB device
|
/// A specific interface of a USB device
|
||||||
pub trait UsbInterface<'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>, UsbError>;
|
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, UsbError>;
|
||||||
|
@ -141,7 +141,7 @@ pub enum Recipient {
|
||||||
Other = 3,
|
Other = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parameters for [UsbInterface::control_in]
|
/// Parameters for [Interface::control_in]
|
||||||
pub struct ControlIn {
|
pub struct ControlIn {
|
||||||
pub control_type: ControlType,
|
pub control_type: ControlType,
|
||||||
pub recipient: Recipient,
|
pub recipient: Recipient,
|
||||||
|
@ -151,7 +151,7 @@ pub struct ControlIn {
|
||||||
pub length: u16,
|
pub length: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parameters for [UsbInterface::control_out]
|
/// Parameters for [Interface::control_out]
|
||||||
pub struct ControlOut<'a> {
|
pub struct ControlOut<'a> {
|
||||||
pub control_type: ControlType,
|
pub control_type: ControlType,
|
||||||
pub recipient: Recipient,
|
pub recipient: Recipient,
|
||||||
|
|
Loading…
Reference in a new issue