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

Implement asynchronous hotplug #156

Open
wants to merge 8 commits into
base: master
Choose a base branch
from

Conversation

StephanvanSchaik
Copy link

@StephanvanSchaik StephanvanSchaik commented Nov 11, 2022

This is based off the code for PR #155, so the first two commits are the same. The rest of this PR implements an asynchronous hotplug API.

It introduces HotplugBuilder that wraps the HotplugBuilder from the rusb crate. Instead of accepting anything implementing the Hotplug trait, HotplugBuilder::register() registers its own Hotplug object implementing that trait. HotplugBuilder::register() also sets up a channel to propagate any hotplug events when devices arrive or leave. Whenever any of the callbacks get invoked, the appropriate HotplugEvent is created and sent to the channel. The Registration object returned by HotplugBuilder::register() has a function next_event() to await hotplug events by simply polling the channel for hotplug events.

The API shouldn't have the same restrictions as the hotplug API in the rusb crate, as the callbacks simply send the Device object to the channel. That way no other operations are performed on these Device objects, and after retrieving these Device objects by polling the channel these restrictions should no longer apply..

This also adds an example (examples/async_hotplug.rs) that shows how to use the API.

@mcuee
Copy link

mcuee commented May 1, 2023

Somehow the hotplug feature does not seem to work under macOS, tested with macOS Ventura 13.3.1 using Mac Mini M1 (2020).

mcuee@mcuees-Mac-mini rusb_pr156 % ./target/debug/examples/async_hotplug

(nothing happened when I plug or unplug a USB device).

@mcuee
Copy link

mcuee commented May 1, 2023

Same thing that it does not seem to anything under Linux. Tested under Ubuntu 20.04. The original hotplug example works fine.

mcuee@UbuntuSwift3:~/build/libusb/rust/rusb_pr156$ ./target/debug/examples/async_hotplug
^C
mcuee@UbuntuSwift3:~/build/libusb/rust/rusb_pr156$ ./target/debug/examples/hotplug
device arrived Bus 004 Device 001: ID 1d6b:0003
device arrived Bus 003 Device 005: ID 1c7a:0575
device arrived Bus 003 Device 004: ID 04f2:b6dd
device arrived Bus 003 Device 003: ID 046d:c52b
device arrived Bus 003 Device 013: ID 04d8:fa2e
device arrived Bus 003 Device 002: ID 05e3:0610
device arrived Bus 003 Device 006: ID 8087:0026
device arrived Bus 003 Device 001: ID 1d6b:0002
device arrived Bus 002 Device 002: ID 05e3:0612
device arrived Bus 002 Device 001: ID 1d6b:0003
device arrived Bus 001 Device 001: ID 1d6b:0002
device left Bus 003 Device 013: ID 04d8:fa2e
HotPlugHandler dropped

@StephanvanSchaik
Copy link
Author

Somehow the hotplug feature does not seem to work under macOS, tested with macOS Ventura 13.3.1 using Mac Mini M1 (2020).

mcuee@mcuees-Mac-mini rusb_pr156 % ./target/debug/examples/async_hotplug

(nothing happened when I plug or unplug a USB device).

I haven't tested this on macOS on the Apple M1, but I can give that a try if it still doesn't work.

Same thing that it does not seem to anything under Linux. Tested under Ubuntu 20.04. The original hotplug example works fine.

mcuee@UbuntuSwift3:~/build/libusb/rust/rusb_pr156$ ./target/debug/examples/async_hotplug
^C
mcuee@UbuntuSwift3:~/build/libusb/rust/rusb_pr156$ ./target/debug/examples/hotplug
device arrived Bus 004 Device 001: ID 1d6b:0003
device arrived Bus 003 Device 005: ID 1c7a:0575
device arrived Bus 003 Device 004: ID 04f2:b6dd
device arrived Bus 003 Device 003: ID 046d:c52b
device arrived Bus 003 Device 013: ID 04d8:fa2e
device arrived Bus 003 Device 002: ID 05e3:0610
device arrived Bus 003 Device 006: ID 8087:0026
device arrived Bus 003 Device 001: ID 1d6b:0002
device arrived Bus 002 Device 002: ID 05e3:0612
device arrived Bus 002 Device 001: ID 1d6b:0003
device arrived Bus 001 Device 001: ID 1d6b:0002
device left Bus 003 Device 013: ID 04d8:fa2e
HotPlugHandler dropped

Something might have changed in libusb since I last looked at this, as it seems to end up calling the callback immediately during registration, whereas I remember it doing this after calling the register function. Basically, self.inner.register(context, hotplug)? in HotplugBuilder::register() ended up blocking, as it now ends up calling Hotplug<T>::device_arrived() which simply puts events on a channel. However, as that channel is bounded to 1 event, it would simply block after the first event, as nobody is calling Registration::next_event() yet to empty the channel. The above commit simply fixes this by using an unbounded channel.

@mcuee
Copy link

mcuee commented May 1, 2023

Great, now it works under Ubuntu Linux. It should work under macOS as well but I will test tomorrow.

mcuee@UbuntuSwift3:~/build/libusb/rust/rusb_pr156$ ./target/debug/examples/async_hotplug
device arrived Bus 004 Device 002: ID 04b4:00f1
device arrived Bus 004 Device 001: ID 1d6b:0003
device arrived Bus 003 Device 005: ID 1c7a:0575
device arrived Bus 003 Device 004: ID 04f2:b6dd
device arrived Bus 003 Device 003: ID 046d:c52b
device arrived Bus 003 Device 002: ID 05e3:0610
device arrived Bus 003 Device 006: ID 8087:0026
device arrived Bus 003 Device 001: ID 1d6b:0002
device arrived Bus 002 Device 002: ID 05e3:0612
device arrived Bus 002 Device 001: ID 1d6b:0003
device arrived Bus 001 Device 001: ID 1d6b:0002
device left Bus 004 Device 002: ID 04b4:00f1 (click reset button)
device arrived Bus 003 Device 007: ID 04b4:00f3 (it will renumerate as the defaul blank device)
device left Bus 003 Device 007: ID 04b4:00f3 (click reset button)
device arrived Bus 003 Device 008: ID 04b4:00f3


@mcuee
Copy link

mcuee commented May 1, 2023

Just something obvous, the behavior under Windows is also correct, as libusb does not support hotplug yet and it will not support in the near future due to lack of Windows developers. One potential workaround is to implement rusb's own hotplug mechanism under Windows but that may need some efforts.
Reference:

PS C:\work\libusb\rust\rusb_pr156> .\target\debug\examples\async_hotplug
libusb hotplug api unsupported

@mcuee
Copy link

mcuee commented May 1, 2023

Now it works under macOS as well.

mcuee@mcuees-Mac-mini rusb_pr156 % ./target/debug/examples/async_hotplug
device arrived Bus 002 Device 009: ID 1915:1025
device arrived Bus 002 Device 008: ID 046d:c52b
device arrived Bus 002 Device 007: ID 1a40:0201
device arrived Bus 002 Device 006: ID 1a40:0201
device arrived Bus 002 Device 005: ID 0bda:5411
device arrived Bus 002 Device 004: ID 05e3:0749
device arrived Bus 002 Device 003: ID 0bda:0411
device arrived Bus 002 Device 002: ID 0bda:0411
device arrived Bus 002 Device 001: ID 0bda:5411
device arrived Bus 002 Device 010: ID 04d8:fa2e (first plug-in)
device left Bus 002 Device 010: ID 04d8:fa2e (click reset button)
device arrived Bus 002 Device 011: ID 04d8:fa2e
device left Bus 002 Device 011: ID 04d8:fa2e (click reset button)
device arrived Bus 002 Device 012: ID 04d8:fa2e

@mcuee
Copy link

mcuee commented May 1, 2023

@StephanvanSchaik
Interestingly I am also testing the async PR for libusbdotnet project. The author there has an idea of the stableConnectionInterval feature for the device being monitored. I am not so sure if you want to implement something like that or not.

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

Successfully merging this pull request may close these issues.

2 participants