Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

async API? #4

Open
goertzenator opened this issue Mar 7, 2016 · 11 comments
Open

async API? #4

goertzenator opened this issue Mar 7, 2016 · 11 comments

Comments

@goertzenator
Copy link

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.

@kevinmehall
Copy link
Contributor

I started implementing safe Rust bindings to the libusb async transfer functions a while ago, but haven't gotten around to finishing it yet. I'll try to clean it up later this week.

@goertzenator
Copy link
Author

Thanks, I'll give that a look when you push it.

@dcuddeback
Copy link
Owner

@goertzenator Yeah, definitely. Sounds like @kevinmehall might be ahead of me on that. I'd love to see what he comes up with.

@kevinmehall
Copy link
Contributor

Work in progress here: https://github.com/kevinmehall/libusb-rs/blob/async/src/async.rs

Example streaming from a device

The new concept (vs libusb) is the AsyncGroup (could use a better name), which takes ownership of transfers when they are submitted, manages completions, and returns the completed transfers back to you to be handled and/or resubmitted. Libusb does that with callbacks, but this wraps that error-prone API in a safe Rust interface. It's not quite zero-cost, because it keeps track of pending transfers in a HashSet and completed transfers in a VecDeque, but should have minimal overhead.

I still need to rework the buffer management. Right now a transfer takes &'d mut [u8]. That lifetime must outlive the AsyncGroup to guarantee that it stays valid while the transfer is pending, In reality, it only needs to live until the transfer completes, but references can't express that. It requires a mutable buffer because the same type is shared for both IN and OUT directions. I'm thinking the Transfer should own the buffer -- that solves the mutability question, and if it let you give ownership to the AsyncGroup on submit, and take it back on completion, you can stream owned buffers into or out of a USB endpoint.

Other TODOs (some could happen later);

  • A nonblocking version of wait_any (returns None immediately if there are no completions ready)
  • A variant of cancel_all that just requests cancellation, and lets you wait for it yourself, so
    you can collect data from already- or partially-completed transfers.
  • The ability to cancel individual transfers. submit could return something that contains the
    *mut libusb_transfer but only offers a cancel method.
  • The ability to associate user data with transfers. Right now it works if all the transfers are
    indistinguishable, but to use the same AsyncGroup / thread for multiple endpoints or devices,
    you want a way to distinguish them. AsyncGroup could be parametrized over an arbitrary token type
    that would be passed to submit, kept in a HashMap (instead of the HashSet), and returned
    from wait_any.
  • Support for control and isochronous transfers, which have specialized buffer layouts.

@goertzenator
Copy link
Author

Thanks Kevin. I'm actually interested in using my own event loop (mio), and this wrapper doesn't seem to support that... and I'm not certain it should since libusb doesn't provide it in a portable manner (no Windows support).

My inclination for my project at hand is to just code straight to Linux usbfs. Using the libusb usbfs layer as a guide, this seems very doable.

@kevinmehall
Copy link
Contributor

I think it would be possible to make the AsyncGroup a mio Evented under the proposed new mio API such that you could add the AsyncGroup to your event loop and get notified when a completion is ready. Windows could use an event listener thread, or maybe someday libusb will expose the underlying IOCP handles on Windows.

@oberien
Copy link

oberien commented Apr 22, 2016

@kevinmehall What's the status here? I would really love to see this, especially because currently I need to read_interrupt on 2 interfaces while i read_control from a 3rd one. With threads this is pretty messy. But with your given "Example streaming from a device" it seems easily possible :)

Looking forward to seeing this!

@marjakm
Copy link

marjakm commented Mar 6, 2018

I have an async implementation for linux (and possibly mac, haven't tested it) that can be used with mio, but it made the api somewhat more complicated - most structs are generic to enable choosing whether you want to use the libusb sync or async api's (and to enable different async solutions for linux and windows) and if you want to store references, Rc's or Arc's to the Context. Sync and Async api's are also defined in traits. There is practically no documentation, errors are not thought through and it may be very broken (but it seems to work in one app). There is some design motivation written in the readme. Some code was copied from @kevinmehall code, I hope thats fine.

https://github.com/marjakm/libusb-rs/tree/no-lifetimes

@whitequark
Copy link

@kevinmehall Thanks for your code! I've found one serious issue with it though, fixed in commit whitequark/libusb-rs@9cc650c.

@brandonros
Copy link

brandonros commented Jul 4, 2020

where did this end up? is there a way to do async USB I/O in rust with any library in 2020 or not?

@jesultra
Copy link

jesultra commented Mar 5, 2022

I am interested in this as well. My application does TCP communication via mio, and also uses rusb (currently only synchronously). Ideally, I would like to be able to wait for both sockets and asynchronous rusb requests using the same Poll.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants