GithubHelp home page GithubHelp logo

libusb-rs's Introduction

Libusb

This crate provides a safe wrapper around the native libusb library. It applies the RAII pattern and Rust lifetimes to ensure safe usage of all libusb functionality. The RAII pattern ensures that all acquired resources are released when they're no longer needed, and Rust lifetimes ensure that resources are released in a proper order.

Dependencies

In order to use the libusb crate, you must have the native libusb library installed where it can be found by pkg-config.

All systems supported by the native libusb library are also supported by the libusb crate. It's been tested on Linux, OS X, and Windows.

Cross-Compiling

The libusb crate can be used when cross-compiling to a foreign target. Details on how to cross-compile libusb are explained in the libusb-sys crate's README.

Usage

Add libusb as a dependency in Cargo.toml:

[dependencies]
libusb = "0.3"

Import the libusb crate. The starting point for nearly all libusb functionality is to create a context object. With a context object, you can list devices, read their descriptors, open them, and communicate with their endpoints:

extern crate libusb;

fn main() {
    let mut context = libusb::Context::new().unwrap();

    for mut device in context.devices().unwrap().iter() {
        let device_desc = device.device_descriptor().unwrap();

        println!("Bus {:03} Device {:03} ID {:04x}:{:04x}",
            device.bus_number(),
            device.address(),
            device_desc.vendor_id(),
            device_desc.product_id());
    }
}

Contributors

License

Copyright © 2015 David Cuddeback

Distributed under the MIT License.

libusb-rs's People

Contributors

dcuddeback avatar kevinmehall avatar nelsonjchen avatar r3n4ud avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

libusb-rs's Issues

hotplug callback

hi. thanks for making this library wrapper. one thing i would love to use but don't see implemented is the hotplug functionality. from the docs:


int libusb_hotplug_register_callback | ( | libusb_context * | ctx,
-- | -- | -- | --
  |   | libusb_hotplug_event | events,
  |   | libusb_hotplug_flag | flags,
  |   | int | vendor_id,
  |   | int | product_id,
  |   | int | dev_class,
  |   | libusb_hotplug_callback_fn | cb_fn,
  |   | void * | user_data,
  |   | libusb_hotplug_callback_handle * | handle
  | )

is this already available and i'm missing something?

Cant build libusb on gnu x64

on linux ubuntu 22.04 x64
rust 1.62.1

I think is because libusbsys is in 0.6x, and the project need to update dependencies.

Libusb is crashing on libusbsys during build.

error: failed to run custom build command for `libusb-sys v0.2.3`

Caused by:
  process didn't exit successfully: `/home/jcbritobr/Workspace/rust/systempr/target/debug/build/libusb-sys-540c2f6b8faff6ab/build-script-build` (exit status: 101)
  --- stdout
  cargo:rerun-if-env-changed=LIBUSB_1.0_NO_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_x86_64-unknown-linux-gnu
  cargo:rerun-if-env-changed=PKG_CONFIG_x86_64_unknown_linux_gnu
  cargo:rerun-if-env-changed=HOST_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG
  cargo:rerun-if-env-changed=LIBUSB_1.0_STATIC
  cargo:rerun-if-env-changed=LIBUSB_1.0_DYNAMIC
  cargo:rerun-if-env-changed=PKG_CONFIG_ALL_STATIC
  cargo:rerun-if-env-changed=PKG_CONFIG_ALL_DYNAMIC
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64-unknown-linux-gnu
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH_x86_64_unknown_linux_gnu
  cargo:rerun-if-env-changed=HOST_PKG_CONFIG_PATH
  cargo:rerun-if-env-changed=PKG_CONFIG_PATH
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64-unknown-linux-gnu
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR_x86_64_unknown_linux_gnu
  cargo:rerun-if-env-changed=HOST_PKG_CONFIG_LIBDIR
  cargo:rerun-if-env-changed=PKG_CONFIG_LIBDIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-linux-gnu
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_linux_gnu
  cargo:rerun-if-env-changed=HOST_PKG_CONFIG_SYSROOT_DIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR

Linking on Windows

Seeing @bitbegin's issue (#17), I tried to use the GNU toolchain, but ended up with an error.

I'm on Windows 10 Home 64 bit.

  • Switched to the GNU based toolchain: rustup override set stable-x86_64-pc-windows-gnu
  • Installed pkg-config-lite
  • Set %PATH% to pkg-config-lite-0.28-1\bin
  • Set %PKG_CONFIG_PATH% to pkg-config-lite-0.28-1\libs I created
  • Verified pkg-config was working using pkg-config -v
  • Donwloaded libusb for Windows by clicking Downloads > Latest Windows binaries
  • Created a libusb.pc file in the PKG_CONFIG_PATH directory:
# libusb.pc

prefix=C:/Users/Tom/Desktop/pkg-config-lite-0.28-1/libs/libusb
exec_prefix=${prefix}
includedir=${prefix}/include/libusb-1.0
libdir=${exec_prefix}/MinGW64/dll # `/dll`?

Name: libusb
Description: libusb
Version: 1.0
Cflags: -I${includedir}
Libs: -L${libdir} -llibusb-1.0

Here's what pkg-config --libs --cflags libusb-1.0 spits out for me:
-IC:/Users/Tom/Desktop/pkg-config-lite-0.28-1/libs/libusb/include/libusb-1.0 -LC:/Users/Tom/Desktop/pkg-config-lite-0.28-1/libs/libusb/MinGW64/dll -llibusb-1.0

I am using this example code based on what's in the README.md file of this repository:

extern crate libusb;

fn main() {
    let context = libusb::Context::new().unwrap();
    for device in context.devices().unwrap().iter() {
        let device_desc = device.device_descriptor().unwrap();

        println!("Bus {:03} Device {:03} ID {:04x}:{:04x}",
            device.bus_number(),
            device.address(),
            device_desc.vendor_id(),
            device_desc.product_id());
    }

    println!("Hello, world!");
}

Running cargo run then links just fine and runs the binary which subsequently fails with the 3221225781 exit code, which is 0xC0000135, which means STATUS_DLL_NOT_FOUND.

I suspect this is because I am using the dll directory, not the static directory, but with that one, I just get linked errors.

@dcuddeback would you be able to advise here?

async API?

It appears libusb-rs does not support the libusb async API. Any plans or thoughts on this?

I've used the async API from C++ before and am considering doing it from Rust.

read_languages() returns Err(Overflow)

I'm trying to use the read_device() function from the example, but read_languages() returns Err(Overflow).
Why?

Btw, the device I'm trying to read is a Corsair K95 RGB keyboard:

Bus 002 Device 009 ID 1b1c:1b11   12 Mbps
Device Descriptor:
  bcdUSB			  2.00
  bDeviceClass		0x00
  bDeviceSubClass	 0x00
  bDeviceProtocol	 0x00
  bMaxPacketSize0	   64
  idVendor		  0x1b1c
  idProduct		 0x1b11
  bcdDevice		   2.05
  iManufacturer		  1 
  iProduct			   2 
  iSerialNumber		  3 
  bNumConfigurations     1
  Config Descriptor:
	bNumInterfaces	     3
	bConfigurationValue    1
	iConfiguration	     0 
	bmAttributes:
	  Self Powered	 false
	  Remote Wakeup	 true
	bMaxPower		    500mW
	Interface Descriptor:
	  bInterfaceNumber	   0
	  bAlternateSetting	  0
	  bNumEndpoints		  1
	  bInterfaceClass	 0x03
	  bInterfaceSubClass  0x01
	  bInterfaceProtocol  0x01
	  iInterface		     0 
	  Endpoint Descriptor:
		bEndpointAddress	0x81 EP 1 In
		bmAttributes:
		  Transfer Type		  Interrupt
		  Synch Type			 NoSync
		  Usage Type			 Data
		wMaxPacketSize	0x0008
		bInterval			  8
	Interface Descriptor:
	  bInterfaceNumber	   1
	  bAlternateSetting	  0
	  bNumEndpoints		  1
	  bInterfaceClass	 0x03
	  bInterfaceSubClass  0x00
	  bInterfaceProtocol  0x00
	  iInterface		     0 
	  Endpoint Descriptor:
		bEndpointAddress	0x82 EP 2 In
		bmAttributes:
		  Transfer Type		  Interrupt
		  Synch Type			 NoSync
		  Usage Type			 Data
		wMaxPacketSize	0x0040
		bInterval			  1
	Interface Descriptor:
	  bInterfaceNumber	   2
	  bAlternateSetting	  0
	  bNumEndpoints		  1
	  bInterfaceClass	 0x03
	  bInterfaceSubClass  0x00
	  bInterfaceProtocol  0x00
	  iInterface		     0 
	  Endpoint Descriptor:
		bEndpointAddress	0x03 EP 3 Out
		bmAttributes:
		  Transfer Type		  Interrupt
		  Synch Type			 NoSync
		  Usage Type			 Data
		wMaxPacketSize	0x0040
		bInterval			  1

read_device example returns error on ArchLinux

libusb version: libusb-1.0.21-2-x86_64
Linux Kernel: x86_64 Linux 4.13.11-1-ARCH
2006 Motherboard USB2.0 Compatible
Intel chipset

Fails finding device.

lsusb info:

Bus 001 Device 010: ID 045e:02e6 Microsoft Corp. Wireless XBox Controller Dongle

read_device error:

./target/debug/read_device 1118 742
could not find device 045e:02e6

InvalidParam

I keep getting "InvalidParam" I have no idea what I am doing wrong here. I know a param is incorrect but witch one is it?

Part of my code:

let mut data: Vec<u8> = Vec::new();
handle.read_control(
                request_type(Direction::Out, RequestType::Class, Recipient::Interface),
                0x09,
                0x0200,
                0x0000,
                data.as_mut_slice(),
                Duration::from_secs(1)
).expect("Cant get data");

Info about the usb device I'm trying to talk with:

Frame 1: 36 bytes on wire (288 bits), 36 bytes captured (288 bits) on interface 0
USB URB
    [Source: host]
    [Destination: 6.1.0]
    USBPcap pseudoheader length: 28
    IRP ID: 0xffffe00029ceb500
    IRP USBD_STATUS: USBD_STATUS_SUCCESS (0x00000000)
    URB Function: URB_FUNCTION_CLASS_INTERFACE (0x001b)
    IRP information: 0x00, Direction: FDO -> PDO
    URB bus id: 6
    Device address: 1
    Endpoint: 0x00, Direction: OUT
        0... .... = Direction: OUT (0)
        .000 0000 = Endpoint value: 0
    URB transfer type: URB_CONTROL (0x02)
    Packet Data Length: 8
    [Response in: 2]
    Control transfer stage: Setup (0)
    [bInterfaceClass: Unknown (0xffff)]
URB setup
    bmRequestType: 0x21
        0... .... = Direction: Host-to-device
        .01. .... = Type: Class (0x01)
        ...0 0001 = Recipient: Interface (0x01)
    bRequest: 9
    wValue: 0x0200
    wIndex: 0 (0x0000)
    wLength: 64

Device method mutability?

I note that all the methods for Device require &mut instead of &. Is this needed? Can we consider those methods to be interior mutable and use a constant reference instead?

Motivation: I am trying to use Iterator::find() to locate a device of interest, and the predicate function must take a constant reference as a parameter. I need to call device_descriptor() inside the predicate but cannot without a mutable reference.

extern crate libusb;

fn check_device(device: &mut libusb::Device) -> bool {    
    let device_desc = device.device_descriptor().unwrap();
    (device_desc.vendor_id() == 0xffff) && (device_desc.product_id() == 3)
}

fn main() {
    let mut context = libusb::Context::new().unwrap();

    let mut device = context.devices().unwrap().iter().find(check_device).unwrap();  // error: check_device must take immutable ref.

    let device_desc = device.device_descriptor().unwrap();

    println!("Bus {:03} Device {:03} ID {:04x}:{:04x}",
        device.bus_number(),
        device.address(),
        device_desc.vendor_id(),
        device_desc.product_id());
}

Claiming interface: Access denied (insufficient permissions)

I was trying out the read_device.rs example but ran into a problem: when running the configure_endpoint function, claim_interface gave an Error::Access when ran. I suspect this might be a problem of OS X, but I am currently stuck. Any help would be greatly appreciated!

no_std support?

Is it possible to use this crate for embedded devices, ex, for targeting ARM chipsets?

Is this maintained?

@dcuddeback looking to file an unmaintained advisory against this but wanted to check in with you first.

The reason this is important is that libusb is building against an old version of bit-sec that has an invalid Cargo.toml that will no longer be recognized as of Cargo 1.79, breaking builds of libusb and everyone who depends on it (see rust-lang/cargo#13824)

Looking over this repo,

  • The last commit or release was in 2016
  • Looking through the issues and PRs, I didn't see any activity from @dcuddeback since 2017 or so
  • The proposed fixes for the aforementioned bit-set issues have not gotten attention (#15, #45)

Since the start of 2022, the only public activity for @dcuddeback 's profile is two commits to their dotfiles.

There was some activity on libusb-sys in 2021 that was never released.

Transfer Ownership

I'm aware of the repeated queries to this repo (@AJAnderson) and the various forks (@a1lien, etc), but no one else has come out and asked...

Is @dcuddeback available and willing to transfer ownership of this repository and the associated project on crates.io?

Ditto for libusb.sys, and libudev-rs, for that matter.

The goal would be to consolidate all the outstanding PR's and forks, and then proceed with a new async/await API for the asynchronous calls in libusb.

Panic when call read_control() with 256 bytes buf

I have modify the read_control() in device_handle.rs to print out some useful informations:

    pub fn read_control(&self, request_type: u8, request: u8, value: u16, index: u16, buf: &mut [u8], timeout: Duration) -> ::Result<usize> {
        if request_type & LIBUSB_ENDPOINT_DIR_MASK != LIBUSB_ENDPOINT_IN {
            return Err(Error::InvalidParam);
        }

        let ptr = buf.as_mut_ptr() as *mut c_uchar;
        let len = buf.len() as u16;
        let timeout_ms = (timeout.as_secs() * 1000 + timeout.subsec_nanos() as u64 / 1_000_000) as c_uint;
        let res = unsafe {
            println!("libusb_control_transfer: len {:?}",len);
            libusb_control_transfer(self.handle, request_type, request, value, index, ptr, len, timeout_ms)
        };
        println!("libusb_control_transfer: res {:?}",res);
        if res < 0 {
            Err(error::from_libusb(res))
        } else {
            Ok(res as usize)
        }
}

When I try to read my bluetooth HID mouse, I got the error.
Here is the out put:

libusb_control_transfer: len 256
libusb_control_transfer: res -8
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: Overflow', src\libcore\result.rs:999:5
note: Run with `RUST_BACKTRACE=1` environment variable to display a backtrace.

After modify

    pub fn read_languages(&self, timeout: Duration) -> ::Result<Vec<Language>> {
        let mut buf = Vec::<u8>::with_capacity(256)
        ....

to

    pub fn read_languages(&self, timeout: Duration) -> ::Result<Vec<Language>> {
        let mut buf = Vec::<u8>::with_capacity(65)
        ....

it just works. Here is the output:

libusb_control_transfer: len 65
libusb_control_transfer: res 4

My enviroment:
Default host: x86_64-pc-windows-gnu
installed toolchains
nightly-2019-04-21-i686-pc-windows-msvc (default)
installed targets for active toolchain
i686-pc-windows-msvc
nightly-2019-04-21-i686-pc-windows-msvc (default)
rustc 1.36.0-nightly (33fe1131c 2019-04-20)

libusb-1.0.dll version: 1.0.20.11004

Unable to store, or Box, a `DeviceHandle`.

I can't find a way to hold a DeviceHandle in a struct and pass it around. It has a lifetime that must be longer than the Context object that created it. However, even when Boxing the Context and the DeviceHandle together, it's impossible to store a handle.

Did anyone get this to work? I need to store the handle because of how I have a transport-agnostic library built. It also uses the hid crate where the Handle type does not have a lifetime defined, but just documents that it cannot outlive the HidManager type. So I can just manually drop the Handle before dropping the manager.

@dcuddeback I saw a comment where you assume all users will create the Context in main and then just keep it around. Well, I'm not an end user, but a library implementer. The library connects to devices that support with WebUSB, HID and an HTTP bridge daemon. So the Context is created inside the library code and it's impossible to create the context and have it outlive the interface client object that the library returns.

control_transfer not implemented

control_transfer is not yet implemented in InterfaceHandle althought the binding is present in libusb-sys.

Any plan on that? Do you accept PR on this?

[Slightly OT but related]: xxx_transfer should have been implemented on DeviceHandle, no? I agree it makes sense on InterfaceHandle but

Regenerate docs, please

Documentation on docs.rs does not regenerate itself automatically with new versions of docs.rs, and it seems that the one for libusb is just as dated as the last release. Even if there were no changes during this whole period, please somehow force docs.rs to refresh its html. There were some cool and useful features introduced in rust docs lately.

Is this project actively maintained?

Hi there,

This is the first and foremost library for interacting with libusb in Rust but it seems to be gathering dust. Are you still actively maintaining this at all?

Holding an InterfaceHandle in a struct

I'd like to have a struct that contains an InterfaceHandle objects so that I can use the bulk_transfer method. I'm having trouble doing this because an InterfaceHandle object contains a reference to a DeviceHandle object, which contains a reference to a Context object. I'd be fine having the Context object be global, but I'd like to have the DeviceHandle and InterfaceHandle objects held in the same struct. But Rust has trouble with structs that contain references to objects within itself.

So what's the best approach for having a struct contain an InterfaceHandle? I can see a few options:

  • Use Rc and RefCell as is suggested by reem in this post
  • Carry around the DeviceHandle, and then use claim_interface to get the InterfaceHandle every time I need it.
  • Use the libusb-sys crate directly, and just carry around the pointers.

Here's an example of what I'm trying to do:

struct MyDevice<'a> {
    dev_handle: libusb::DeviceHandle<'a>,
    usb_interface: libusb::InterfaceHandle<'a>,
}

impl<'a> MyDevice<'a> {
    fn open(usb_ctx: &'a mut libusb::Context) -> Result<Self, libusb::UsbError> {
        let mut devices = try!(usb_ctx.devices());
        let mut dev_ref = devices.iter().next().unwrap();
        let mut dev_handle = try!(dev_ref.open());
        let interface = try!(dev_handle.claim_interface(0));
        Ok(MyDevice { dev_handle: dev_handle, usb_interface: interface })
    }
}

This fails to compile, saying that dev_handle does not live long enough.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.