mirror of
https://github.com/G2-Games/cross-usb.git
synced 2025-04-19 21:32:53 -05:00
First code commit
This commit is contained in:
commit
f3f58f9ab5
9 changed files with 543 additions and 0 deletions
11
.appveyor.yml
Normal file
11
.appveyor.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
install:
|
||||||
|
- appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
|
||||||
|
- if not defined RUSTFLAGS rustup-init.exe -y --default-host x86_64-pc-windows-msvc --default-toolchain nightly
|
||||||
|
- set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
|
||||||
|
- rustc -V
|
||||||
|
- cargo -V
|
||||||
|
|
||||||
|
build: false
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- cargo test --locked
|
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
[target.'cfg(target_family = "wasm")']
|
||||||
|
rustflags = ["--cfg=web_sys_unstable_apis"]
|
8
.gitignore
vendored
Normal file
8
.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
/target
|
||||||
|
**/*.rs.bk
|
||||||
|
Cargo.lock
|
||||||
|
bin/
|
||||||
|
pkg/
|
||||||
|
wasm-pack.log
|
||||||
|
|
||||||
|
www
|
69
.travis.yml
Normal file
69
.travis.yml
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
language: rust
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
cache: cargo
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
|
||||||
|
# Builds with wasm-pack.
|
||||||
|
- rust: beta
|
||||||
|
env: RUST_BACKTRACE=1
|
||||||
|
addons:
|
||||||
|
firefox: latest
|
||||||
|
chrome: stable
|
||||||
|
before_script:
|
||||||
|
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
||||||
|
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
||||||
|
- cargo install-update -a
|
||||||
|
- curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh -s -- -f
|
||||||
|
script:
|
||||||
|
- cargo generate --git . --name testing
|
||||||
|
# Having a broken Cargo.toml (in that it has curlies in fields) anywhere
|
||||||
|
# in any of our parent dirs is problematic.
|
||||||
|
- mv Cargo.toml Cargo.toml.tmpl
|
||||||
|
- cd testing
|
||||||
|
- wasm-pack build
|
||||||
|
- wasm-pack test --chrome --firefox --headless
|
||||||
|
|
||||||
|
# Builds on nightly.
|
||||||
|
- rust: nightly
|
||||||
|
env: RUST_BACKTRACE=1
|
||||||
|
before_script:
|
||||||
|
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
||||||
|
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
||||||
|
- cargo install-update -a
|
||||||
|
- rustup target add wasm32-unknown-unknown
|
||||||
|
script:
|
||||||
|
- cargo generate --git . --name testing
|
||||||
|
- mv Cargo.toml Cargo.toml.tmpl
|
||||||
|
- cd testing
|
||||||
|
- cargo check
|
||||||
|
- cargo check --target wasm32-unknown-unknown
|
||||||
|
- cargo check --no-default-features
|
||||||
|
- cargo check --target wasm32-unknown-unknown --no-default-features
|
||||||
|
- cargo check --no-default-features --features console_error_panic_hook
|
||||||
|
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
|
||||||
|
- cargo check --no-default-features --features "console_error_panic_hook wee_alloc"
|
||||||
|
- cargo check --target wasm32-unknown-unknown --no-default-features --features "console_error_panic_hook wee_alloc"
|
||||||
|
|
||||||
|
# Builds on beta.
|
||||||
|
- rust: beta
|
||||||
|
env: RUST_BACKTRACE=1
|
||||||
|
before_script:
|
||||||
|
- (test -x $HOME/.cargo/bin/cargo-install-update || cargo install cargo-update)
|
||||||
|
- (test -x $HOME/.cargo/bin/cargo-generate || cargo install --vers "^0.2" cargo-generate)
|
||||||
|
- cargo install-update -a
|
||||||
|
- rustup target add wasm32-unknown-unknown
|
||||||
|
script:
|
||||||
|
- cargo generate --git . --name testing
|
||||||
|
- mv Cargo.toml Cargo.toml.tmpl
|
||||||
|
- cd testing
|
||||||
|
- cargo check
|
||||||
|
- cargo check --target wasm32-unknown-unknown
|
||||||
|
- cargo check --no-default-features
|
||||||
|
- cargo check --target wasm32-unknown-unknown --no-default-features
|
||||||
|
- cargo check --no-default-features --features console_error_panic_hook
|
||||||
|
- cargo check --target wasm32-unknown-unknown --no-default-features --features console_error_panic_hook
|
||||||
|
# Note: no enabling the `wee_alloc` feature here because it requires
|
||||||
|
# nightly for now.
|
38
Cargo.toml
Normal file
38
Cargo.toml
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
[package]
|
||||||
|
name = "cross-usb"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["G2-Games <ke0bhogsg@gmail.com>"]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["cdylib", "rlib"]
|
||||||
|
|
||||||
|
[target.'cfg(target_family = "wasm")'.dependencies]
|
||||||
|
wasm-bindgen = "0.2.84"
|
||||||
|
wasm-bindgen-futures = "0.4.39"
|
||||||
|
js-sys = "0.3.67"
|
||||||
|
|
||||||
|
[target.'cfg(target_family = "wasm")'.dependencies.web-sys]
|
||||||
|
version = "0.3"
|
||||||
|
features = [
|
||||||
|
"Window",
|
||||||
|
"Navigator",
|
||||||
|
"console",
|
||||||
|
"Usb",
|
||||||
|
"UsbDevice",
|
||||||
|
"UsbInterface",
|
||||||
|
"UsbRecipient",
|
||||||
|
"UsbRequestType",
|
||||||
|
"UsbControlTransferParameters",
|
||||||
|
"UsbDeviceRequestOptions",
|
||||||
|
"Storage"
|
||||||
|
]
|
||||||
|
|
||||||
|
[target.'cfg(not(target_family = "wasm"))'.dependencies]
|
||||||
|
nusb = "0.1.2"
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
opt-level = "s"
|
||||||
|
|
||||||
|
[package.metadata.wasm-pack.profile.dev.wasm-bindgen]
|
||||||
|
dwarf-debug-info = true
|
130
src/backend/native.rs
Normal file
130
src/backend/native.rs
Normal file
|
@ -0,0 +1,130 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use nusb;
|
||||||
|
|
||||||
|
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient};
|
||||||
|
|
||||||
|
pub struct UsbDevice {
|
||||||
|
device: nusb::Device,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct UsbInterface {
|
||||||
|
interface: nusb::Interface,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a single device from the VendorID and ProductID
|
||||||
|
pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, Box<dyn Error>> {
|
||||||
|
let devices = nusb::list_devices().unwrap();
|
||||||
|
|
||||||
|
let mut device_info = None;
|
||||||
|
for device in devices {
|
||||||
|
if device.vendor_id() == vendor_id && device.product_id() == product_id {
|
||||||
|
device_info = Some(device);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let device_info = match device_info {
|
||||||
|
Some(dev) => dev,
|
||||||
|
None => return Err("Device not found".into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let device = device_info.open()?;
|
||||||
|
|
||||||
|
Ok(UsbDevice { device })
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for UsbDevice {
|
||||||
|
type UsbDevice = UsbDevice;
|
||||||
|
type UsbInterface = UsbInterface;
|
||||||
|
|
||||||
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, Box<dyn Error>> {
|
||||||
|
let interface = match self.device.claim_interface(number) {
|
||||||
|
Ok(inter) => inter,
|
||||||
|
Err(e) => return Err(e.into()),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(UsbInterface { interface })
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn reset(&self) -> Result<(), Box<dyn Error>> {
|
||||||
|
match self.device.reset() {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Interface<'a> for UsbInterface {
|
||||||
|
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
Ok(self.interface.control_in(data.into()).await.into_result()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn control_out(&self, data: ControlOut<'a>) -> Result<(), Box<dyn Error>> {
|
||||||
|
match self.interface.control_out(data.into()).await.into_result() {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bulk_in(&self, endpoint: u8, buf: Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
let buf_len = buf.len();
|
||||||
|
let request_buffer = nusb::transfer::RequestBuffer::reuse(buf, buf_len);
|
||||||
|
|
||||||
|
Ok(self.interface.bulk_in(endpoint, request_buffer).await.into_result()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bulk_out(&self, endpoint: u8, buf: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||||
|
match self.interface.bulk_out(endpoint, buf).await.into_result() {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(e) => Err(e.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlIn> for nusb::transfer::ControlIn {
|
||||||
|
fn from(val: ControlIn) -> Self {
|
||||||
|
nusb::transfer::ControlIn {
|
||||||
|
control_type: val.control_type.into(),
|
||||||
|
recipient: val.recipient.into(),
|
||||||
|
request: val.request,
|
||||||
|
value: val.value,
|
||||||
|
index: val.index,
|
||||||
|
length: val.length,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<ControlOut<'a>> for nusb::transfer::ControlOut<'a> {
|
||||||
|
fn from(val: ControlOut<'a>) -> Self {
|
||||||
|
nusb::transfer::ControlOut {
|
||||||
|
control_type: val.control_type.into(),
|
||||||
|
recipient: val.recipient.into(),
|
||||||
|
request: val.request,
|
||||||
|
value: val.value,
|
||||||
|
index: val.index,
|
||||||
|
data: val.data,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlType> for nusb::transfer::ControlType {
|
||||||
|
fn from(val: ControlType) -> Self {
|
||||||
|
match val {
|
||||||
|
ControlType::Standard => nusb::transfer::ControlType::Standard,
|
||||||
|
ControlType::Class => nusb::transfer::ControlType::Class,
|
||||||
|
ControlType::Vendor => nusb::transfer::ControlType::Vendor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Recipient> for nusb::transfer::Recipient {
|
||||||
|
fn from(val: Recipient) -> Self {
|
||||||
|
match val {
|
||||||
|
|
||||||
|
Recipient::Device => nusb::transfer::Recipient::Device,
|
||||||
|
Recipient::Interface => nusb::transfer::Recipient::Interface,
|
||||||
|
Recipient::Endpoint => nusb::transfer::Recipient::Endpoint,
|
||||||
|
Recipient::Other => nusb::transfer::Recipient::Other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
196
src/backend/wasm.rs
Normal file
196
src/backend/wasm.rs
Normal file
|
@ -0,0 +1,196 @@
|
||||||
|
#![cfg_attr(debug_assertions, allow(dead_code, unused_imports))]
|
||||||
|
use std::error::Error;
|
||||||
|
use wasm_bindgen::prelude::*;
|
||||||
|
use js_sys::JSON;
|
||||||
|
|
||||||
|
use web_sys::{
|
||||||
|
console,
|
||||||
|
Usb,
|
||||||
|
UsbDevice as WasmUsbDevice,
|
||||||
|
UsbInterface as WasmUsbInterface,
|
||||||
|
UsbControlTransferParameters,
|
||||||
|
UsbRecipient,
|
||||||
|
UsbRequestType,
|
||||||
|
UsbDeviceRequestOptions,
|
||||||
|
};
|
||||||
|
use js_sys::{Array, Uint8Array, Promise};
|
||||||
|
use wasm_bindgen_futures::JsFuture;
|
||||||
|
|
||||||
|
// Crate stuff
|
||||||
|
use crate::usb::{ControlIn, ControlOut, ControlType, Device, Interface, Recipient};
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct UsbDevice {
|
||||||
|
device: WasmUsbDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub struct UsbInterface {
|
||||||
|
device: WasmUsbDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a single device from the VendorID and ProductID
|
||||||
|
#[wasm_bindgen]
|
||||||
|
pub async fn get_device(vendor_id: u16, product_id: u16) -> Result<UsbDevice, js_sys::Error> {
|
||||||
|
let window = web_sys::window().unwrap();
|
||||||
|
|
||||||
|
let navigator = window.navigator();
|
||||||
|
let usb = navigator.usb();
|
||||||
|
|
||||||
|
let arr = Array::new();
|
||||||
|
let filter1 = js_sys::Object::new();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&filter1,
|
||||||
|
&JsValue::from_str("vendorId"),
|
||||||
|
&JsValue::from(vendor_id),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
js_sys::Reflect::set(
|
||||||
|
&filter1,
|
||||||
|
&JsValue::from_str("productId"),
|
||||||
|
&JsValue::from(product_id),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
arr.push(&filter1);
|
||||||
|
let filters = JsValue::from(&arr);
|
||||||
|
|
||||||
|
let filters2 = UsbDeviceRequestOptions::new(&filters);
|
||||||
|
|
||||||
|
let device_promise = JsFuture::from(Promise::resolve(&usb.request_device(&filters2))).await;
|
||||||
|
|
||||||
|
let device: WasmUsbDevice = match device_promise {
|
||||||
|
Ok(res) => res.into(),
|
||||||
|
Err(err) => {
|
||||||
|
console::log_1(&err.clone().into());
|
||||||
|
return Err(err.into())
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let _open_promise = JsFuture::from(Promise::resolve(&device.open()));
|
||||||
|
|
||||||
|
console::log_1(&"got device".into());
|
||||||
|
|
||||||
|
Ok(UsbDevice {
|
||||||
|
device
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Device for UsbDevice {
|
||||||
|
type UsbDevice = UsbDevice;
|
||||||
|
type UsbInterface = UsbInterface;
|
||||||
|
|
||||||
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, Box<dyn Error>> {
|
||||||
|
let dev_promise = JsFuture::from(Promise::resolve(&self.device.claim_interface(number)));
|
||||||
|
|
||||||
|
// Wait for the interface to be claimed
|
||||||
|
let result = dev_promise;
|
||||||
|
|
||||||
|
Ok(UsbInterface {
|
||||||
|
device: self.device.clone()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn reset(&self) -> Result<(), Box<dyn Error>> {
|
||||||
|
let promise = Promise::resolve(&self.device.reset());
|
||||||
|
|
||||||
|
let result = JsFuture::from(promise).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => {
|
||||||
|
console::log_1(&"Cancelled".into());
|
||||||
|
return Err("cancelled".into())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Interface<'a> for UsbInterface {
|
||||||
|
async fn control_in(&self, data: crate::usb::ControlIn) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
let length = data.length;
|
||||||
|
let params = data.into();
|
||||||
|
let promise = Promise::resolve(&self.device.control_transfer_in(¶ms, length));
|
||||||
|
|
||||||
|
let mut result = JsFuture::from(promise).await;
|
||||||
|
|
||||||
|
let data = match result {
|
||||||
|
Ok(res) => res.into(),
|
||||||
|
Err(_) => {
|
||||||
|
console::log_1(&"Cancelled".into());
|
||||||
|
return Err("cancelled".into())
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
let unitarray = Uint8Array::new(&data);
|
||||||
|
|
||||||
|
Ok(unitarray.to_vec())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn control_out(&self, data: crate::usb::ControlOut<'a>) -> Result<(), Box<dyn Error>> {
|
||||||
|
let params = data.into();
|
||||||
|
let promise = Promise::resolve(&self.device.control_transfer_out(¶ms));
|
||||||
|
|
||||||
|
let mut result = JsFuture::from(promise).await;
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(err) => {
|
||||||
|
console::log_1(&"Cancelled".into());
|
||||||
|
Err(format!("{:?}", err).into())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bulk_in(&self, _endpoint: u8, _buf: Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn bulk_out(&self, _endpoint: u8, _buf: Vec<u8>) -> Result<(), Box<dyn Error>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlIn> for UsbControlTransferParameters {
|
||||||
|
fn from(value: ControlIn) -> Self {
|
||||||
|
UsbControlTransferParameters::new(
|
||||||
|
value.index,
|
||||||
|
value.recipient.into(),
|
||||||
|
value.request.into(),
|
||||||
|
value.control_type.into(),
|
||||||
|
value.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlOut<'_>> for UsbControlTransferParameters {
|
||||||
|
fn from(value: ControlOut) -> Self {
|
||||||
|
UsbControlTransferParameters::new(
|
||||||
|
value.index,
|
||||||
|
value.recipient.into(),
|
||||||
|
value.request.into(),
|
||||||
|
value.control_type.into(),
|
||||||
|
value.value
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Recipient> for UsbRecipient {
|
||||||
|
fn from(value: Recipient) -> Self {
|
||||||
|
match value {
|
||||||
|
Recipient::Device => UsbRecipient::Device,
|
||||||
|
Recipient::Interface => UsbRecipient::Interface,
|
||||||
|
Recipient::Endpoint => UsbRecipient::Endpoint,
|
||||||
|
Recipient::Other => UsbRecipient::Other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ControlType> for UsbRequestType {
|
||||||
|
fn from(value: ControlType) -> Self {
|
||||||
|
match value {
|
||||||
|
ControlType::Standard => UsbRequestType::Standard,
|
||||||
|
ControlType::Class => UsbRequestType::Class,
|
||||||
|
ControlType::Vendor => UsbRequestType::Vendor,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
9
src/lib.rs
Normal file
9
src/lib.rs
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
pub mod usb;
|
||||||
|
|
||||||
|
#[cfg(not(target_family = "wasm"))]
|
||||||
|
#[path = "./backend/native.rs"]
|
||||||
|
pub mod context;
|
||||||
|
|
||||||
|
#[cfg(target_family = "wasm")]
|
||||||
|
#[path = "./backend/wasm.rs"]
|
||||||
|
pub mod context;
|
80
src/usb.rs
Normal file
80
src/usb.rs
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
|
use crate::context::UsbInterface;
|
||||||
|
|
||||||
|
/// A unique USB device
|
||||||
|
pub trait Device {
|
||||||
|
type UsbDevice;
|
||||||
|
type UsbInterface;
|
||||||
|
|
||||||
|
async fn open_interface(&self, number: u8) -> Result<UsbInterface, Box<dyn Error>>;
|
||||||
|
async fn reset(&self) -> Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
|
//TODO: Implement these placeholders
|
||||||
|
async fn product_id(&self) -> u16 {
|
||||||
|
0x00
|
||||||
|
}
|
||||||
|
async fn vendor_id(&self) -> u16 {
|
||||||
|
0x00
|
||||||
|
}
|
||||||
|
async fn class(&self) -> u16 {
|
||||||
|
0x00
|
||||||
|
}
|
||||||
|
async fn subclass(&self) -> u16 {
|
||||||
|
0x00
|
||||||
|
}
|
||||||
|
async fn manufacturer_string(&self) -> Option<&str> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
async fn product_string(&self) -> Option<&str> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A specific interface of a USB device
|
||||||
|
pub trait Interface<'a> {
|
||||||
|
async fn control_in(&self, data: ControlIn) -> Result<Vec<u8>, Box<dyn Error>>;
|
||||||
|
async fn control_out(&self, data: ControlOut<'a>) -> Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
|
async fn bulk_in(&self, endpoint: u8, buf: Vec<u8>) -> Result<Vec<u8>, Box<dyn Error>>;
|
||||||
|
async fn bulk_out(&self, endpoint: u8, buf: Vec<u8>) -> Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
|
async fn interrupt_in(&self, _endpoint: u8, _buf: Vec<u8>) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn interrupt_out(&self, _endpoint: u8, _buf: Vec<u8>) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ControlType {
|
||||||
|
Standard = 0,
|
||||||
|
Class = 1,
|
||||||
|
Vendor = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Recipient {
|
||||||
|
Device = 0,
|
||||||
|
Interface = 1,
|
||||||
|
Endpoint = 2,
|
||||||
|
Other = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ControlIn {
|
||||||
|
pub control_type: ControlType,
|
||||||
|
pub recipient: Recipient,
|
||||||
|
pub request: u8,
|
||||||
|
pub value: u16,
|
||||||
|
pub index: u16,
|
||||||
|
pub length: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ControlOut<'a> {
|
||||||
|
pub control_type: ControlType,
|
||||||
|
pub recipient: Recipient,
|
||||||
|
pub request: u8,
|
||||||
|
pub value: u16,
|
||||||
|
pub index: u16,
|
||||||
|
pub data: &'a[u8],
|
||||||
|
}
|
Loading…
Reference in a new issue