Pre-release docs tweaks
This commit is contained in:
parent
efd9c3484f
commit
99dec9729d
9 changed files with 107 additions and 40 deletions
|
|
@ -1,7 +1,9 @@
|
|||
[package]
|
||||
name = "nusb"
|
||||
version = "0.1.0"
|
||||
description = "Low-level access to USB devices in pure Rust"
|
||||
description = "Cross-platform low-level access to USB devices in pure Rust"
|
||||
categories = ["hardware-support"]
|
||||
keywords = ["usb", "hardware"]
|
||||
authors = ["Kevin Mehall <km@kevinmehall.net>"]
|
||||
edition = "2021"
|
||||
license = "Apache-2.0 OR MIT"
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@ nusb
|
|||
|
||||
A new pure-Rust library for cross-platform low-level access to USB devices.
|
||||
|
||||
[Documentation](https://docs.rs/nusb)
|
||||
|
||||
### Compared to [rusb](https://docs.rs/rusb/latest/rusb/) and libusb
|
||||
|
||||
* Pure Rust, no dependency on libusb or any other C library.
|
||||
|
|
@ -11,14 +13,13 @@ A new pure-Rust library for cross-platform low-level access to USB devices.
|
|||
`futures_lite::block_on`.
|
||||
* No context object. You just open a device. There is a global event loop thread
|
||||
that is started when opening the first device.
|
||||
* Doesn't try to paper over OS differences. For example, on Windows, you must open
|
||||
a specific interface, not a device as a whole. `nusb`'s API makes working with interfaces
|
||||
a required step so that it can map directly to Windows APIs.
|
||||
* Thinner layer over OS APIs, with less internal state.
|
||||
|
||||
### :construction: Current status
|
||||
|
||||
* Linux: Control, bulk and interrupt transfers work, minimally tested
|
||||
* Windows: Control, bulk and interrupt transfers work, minimally tested
|
||||
* macOS : Not yet implemented
|
||||
|
||||
### License
|
||||
MIT or Apache 2.0, at your option
|
||||
|
|
|
|||
|
|
@ -8,7 +8,17 @@ use crate::{
|
|||
|
||||
/// An opened USB device.
|
||||
///
|
||||
/// Obtain a `Device` by calling [`DeviceInfo::open`].
|
||||
/// Obtain a `Device` by calling [`DeviceInfo::open`]:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use nusb;
|
||||
/// let device_info = nusb::list_devices().unwrap()
|
||||
/// .find(|dev| dev.vendor_id() == 0xAAAA && dev.product_id() == 0xBBBB)
|
||||
/// .expect("device not connected");
|
||||
///
|
||||
/// let device = device_info.open().expect("failed to open device");
|
||||
/// let interface = device.claim_interface(0);
|
||||
/// ```
|
||||
///
|
||||
/// This type is reference-counted with an [`Arc`] internally, and can be cloned cheaply for
|
||||
/// use in multiple places in your program. The device is closed when all clones and all
|
||||
|
|
@ -74,6 +84,27 @@ impl Interface {
|
|||
}
|
||||
|
||||
/// Submit a single **IN (device-to-host)** transfer on the default **control** endpoint.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use futures_lite::future::block_on;
|
||||
/// use nusb::transfer::{ ControlIn, ControlType, Recipient };
|
||||
/// # fn main() -> Result<(), std::io::Error> {
|
||||
/// # let di = nusb::list_devices().unwrap().next().unwrap();
|
||||
/// # let device = di.open().unwrap();
|
||||
/// # let interface = device.claim_interface(0).unwrap();
|
||||
///
|
||||
/// let data: Vec<u8> = block_on(interface.control_in(ControlIn {
|
||||
/// control_type: ControlType::Vendor,
|
||||
/// recipient: Recipient::Device,
|
||||
/// request: 0x30,
|
||||
/// value: 0x0,
|
||||
/// index: 0x0,
|
||||
/// length: 64,
|
||||
/// })).into_result()?;
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
pub fn control_in(&self, data: ControlIn) -> TransferFuture<ControlIn> {
|
||||
let mut t = self.backend.make_transfer(0, EndpointType::Control);
|
||||
t.submit::<ControlIn>(data);
|
||||
|
|
@ -81,6 +112,27 @@ impl Interface {
|
|||
}
|
||||
|
||||
/// Submit a single **OUT (host-to-device)** transfer on the default **control** endpoint.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use futures_lite::future::block_on;
|
||||
/// use nusb::transfer::{ ControlOut, ControlType, Recipient };
|
||||
/// # fn main() -> Result<(), std::io::Error> {
|
||||
/// # let di = nusb::list_devices().unwrap().next().unwrap();
|
||||
/// # let device = di.open().unwrap();
|
||||
/// # let interface = device.claim_interface(0).unwrap();
|
||||
///
|
||||
/// block_on(interface.control_out(ControlOut {
|
||||
/// control_type: ControlType::Vendor,
|
||||
/// recipient: Recipient::Device,
|
||||
/// request: 0x32,
|
||||
/// value: 0x0,
|
||||
/// index: 0x0,
|
||||
/// data: &[0x01, 0x02, 0x03, 0x04],
|
||||
/// })).into_result()?;
|
||||
/// # Ok(()) }
|
||||
/// ```
|
||||
pub fn control_out(&self, data: ControlOut) -> TransferFuture<ControlOut> {
|
||||
let mut t = self.backend.make_transfer(0, EndpointType::Control);
|
||||
t.submit::<ControlOut>(data);
|
||||
|
|
|
|||
32
src/lib.rs
32
src/lib.rs
|
|
@ -32,10 +32,10 @@
|
|||
//! device. To open an interface, call [`Device::claim_interface`]. Only one
|
||||
//! program (or kernel driver) may claim an interface at a time.
|
||||
//!
|
||||
//! Use the resulting [`Interface`] struct to transfer data on the device's
|
||||
//! control, bulk or interrupt endpoints. Transfers are async by default, and
|
||||
//! can be awaited as individual `Future`s, or use a [`transfer::Queue`] to
|
||||
//! manage streams of data.
|
||||
//! Use the resulting [`Interface`] to transfer data on the device's control,
|
||||
//! bulk or interrupt endpoints. Transfers are async by default, and can be
|
||||
//! awaited as individual [`Future`][`transfer::TransferFuture`]s, or use a
|
||||
//! [`Queue`][`transfer::Queue`] to manage streams of data.
|
||||
//!
|
||||
//! *For more details on how USB works, [USB in a
|
||||
//! Nutshell](https://beyondlogic.org/usbnutshell/usb1.shtml) is a good
|
||||
|
|
@ -44,10 +44,14 @@
|
|||
//! ## Logging
|
||||
//!
|
||||
//! `nusb` uses the [`log`](https://docs.rs/log) crate to log debug and error
|
||||
//! information. When submitting a bug report, please include the logs: include
|
||||
//! a logging backend like [`env_logger`](https://docs.rs/env_logger) and
|
||||
//! configure it to enable log output for this crate (for `env_logger` set
|
||||
//! environment variable `RUST_LOG=nusb=debug`.)
|
||||
//! information.
|
||||
//!
|
||||
//! When [submitting a bug report][gh-issues], please include the logs: use a
|
||||
//! `log` backend like [`env_logger`](https://docs.rs/env_logger) and configure
|
||||
//! it to enable log output for this crate (for `env_logger` set environment
|
||||
//! variable `RUST_LOG=nusb=debug`.)
|
||||
//!
|
||||
//! [gh-issues]: https://github.com/kevinmehall/nusb/issues
|
||||
//!
|
||||
//! ## Platform support
|
||||
//!
|
||||
|
|
@ -78,7 +82,7 @@
|
|||
//!
|
||||
//! ### Windows
|
||||
//!
|
||||
//! `nusb` uses [SetupAPI] to find devices and [WinUSB] to access them.
|
||||
//! `nusb` uses [WinUSB] on Windows.
|
||||
//!
|
||||
//! On Windows, devices are associated with a particular driver, which persists
|
||||
//! across connections and reboots. Composite devices appear as multiple devices
|
||||
|
|
@ -86,11 +90,11 @@
|
|||
//! separate driver.
|
||||
//!
|
||||
//! To use `nusb`, your device or interface must be associated with the `WinUSB`
|
||||
//! driver. The recommended way to this if you control the device firmware is to
|
||||
//! use a [WCID] descriptor to tell Windows to install the WinUSB driver
|
||||
//! automatically when the device is first connected. Alternatively [Zadig]
|
||||
//! (GUI) or [libwdi] (CLI / C library) can be used to manually install the
|
||||
//! WinUSB driver for a device.
|
||||
//! driver. If you control the device firmware, the recommended way is to use a
|
||||
//! [WCID] descriptor to tell Windows to install the WinUSB driver automatically
|
||||
//! when the device is first connected. Alternatively [Zadig] (GUI) or [libwdi]
|
||||
//! (CLI / C library) can be used to manually install the WinUSB driver for a
|
||||
//! device.
|
||||
//!
|
||||
//! [SetupAPI]:
|
||||
//! https://learn.microsoft.com/en-us/windows-hardware/drivers/install/setupapi
|
||||
|
|
|
|||
|
|
@ -132,7 +132,10 @@ impl LinuxInterface {
|
|||
}
|
||||
|
||||
pub fn set_alt_setting(&self, alt_setting: u8) -> Result<(), Error> {
|
||||
debug!("Set interface {} alt setting to {alt_setting}", self.interface);
|
||||
debug!(
|
||||
"Set interface {} alt setting to {alt_setting}",
|
||||
self.interface
|
||||
);
|
||||
Ok(usbfs::set_interface(
|
||||
&self.device.fd,
|
||||
self.interface,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
//! Wrappers for the [usbfs] character device ioctls, translated from the
|
||||
//! [C structures and ioctl definitions][uapi].
|
||||
//!
|
||||
//! [usbfs]: https://www.kernel.org/doc/html/latest/driver-api/usb/usb.html#the-usb-character-device-nodes
|
||||
//! [uapi]: https://github.com/torvalds/linux/blob/master/tools/include/uapi/linux/usbdevice_fs.h
|
||||
#![allow(dead_code)]
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ use std::{
|
|||
|
||||
use log::{debug, error};
|
||||
use windows_sys::Win32::{
|
||||
Devices::Usb::{WinUsb_Free, WinUsb_Initialize, WINUSB_INTERFACE_HANDLE, WinUsb_SetCurrentAlternateSetting},
|
||||
Devices::Usb::{
|
||||
WinUsb_Free, WinUsb_Initialize, WinUsb_SetCurrentAlternateSetting, WINUSB_INTERFACE_HANDLE,
|
||||
},
|
||||
Foundation::{FALSE, TRUE},
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -4,9 +4,11 @@
|
|||
//! transfers or obtain a [`Queue`] to manage multiple transfers.
|
||||
|
||||
use std::{
|
||||
fmt::Display,
|
||||
future::Future,
|
||||
io,
|
||||
marker::PhantomData,
|
||||
task::{Context, Poll}, io, fmt::Display,
|
||||
task::{Context, Poll},
|
||||
};
|
||||
|
||||
use crate::platform;
|
||||
|
|
|
|||
|
|
@ -19,8 +19,8 @@ use super::{Completion, EndpointType, PlatformSubmit, TransferHandle, TransferRe
|
|||
///
|
||||
/// When the `Queue` is dropped, all pending transfers are cancelled.
|
||||
///
|
||||
/// ### Why use a `Queue` instead of submitting multiple transfers individually
|
||||
/// with the methods on [`Interface`][`crate::Interface`]?
|
||||
/// ### Why use a `Queue` instead of submitting multiple transfers individually with the methods on [`Interface`][`crate::Interface`]?
|
||||
///
|
||||
/// * Individual transfers give you individual `Future`s, which you then have
|
||||
/// to keep track of and poll using something like `FuturesUnordered`.
|
||||
/// * A `Queue` provides better cancellation semantics than `Future`'s
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue