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

Device busy #100

Closed
CandySunPlus opened this issue Aug 3, 2021 · 4 comments · Fixed by #110
Closed

Device busy #100

CandySunPlus opened this issue Aug 3, 2021 · 4 comments · Fixed by #110

Comments

@CandySunPlus
Copy link

CandySunPlus commented Aug 3, 2021

When I try to get the USB information, like read_serial_number_string_ascii in the Hotplug event, it prompts Device busy.

use std::thread;

use rusb::{self, Hotplug, UsbContext};

struct HotplugHandler;

impl<T: UsbContext> Hotplug<T> for HotplugHandler {
    fn device_left(&mut self, device: rusb::Device<T>) {
        println!("device left: {:?}", device);
    }
    fn device_arrived(&mut self, device: rusb::Device<T>) {
        let desc = device.device_descriptor().unwrap();
        let handle = device.open().unwrap();

        let serial_num = handle.read_serial_number_string_ascii(&desc).unwrap();
        println!("device arrived: {:?}, serial_num: {}", device, serial_num);
    }
}

fn main() {
    if rusb::has_hotplug() {
        let ctx = rusb::GlobalContext::default();

        let mut reg = Some(
            ctx.register_callback(None, None, None, Box::new(HotplugHandler {}))
                .unwrap(),
        );

        let handle = thread::spawn(move || loop {
            ctx.handle_events(None).unwrap();
        });

        handle.join().unwrap();

        if let Some(reg) = reg.take() {
            ctx.unregister_callback(reg);
        }
    } else {
        eprintln!("libusb hotplug api unsupported");
    }
}

error log

device left: Bus 001 Device 070: ID 2717:ff48
thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value: Busy', src/main.rs:15:72
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
@CandySunPlus
Copy link
Author

CandySunPlus commented Aug 3, 2021

I found that we cannot call device synchronous API in hot-plug events, so how can I do in rusb

@a1ien
Copy link
Owner

a1ien commented Aug 3, 2021

It's libusb limitation.

When handling a LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED event it is considered safe to call any libusb function that takes a libusb_device. It also safe to open a device and submit asynchronous transfers. However, most other functions that take a libusb_device_handle are not safe to call. Examples of such functions are any of the synchronous API functions or the blocking functions that retrieve various USB descriptors. These functions must be used outside of the context of the hotplug callback.

I think we must add this to documentation.

You can add std::sync::mpsc::Sender in to HotplugHandler and send arrived device

@SuperHuangXu
Copy link

I tried many times, but failed.
Please add a example to help me.
Thanks 🥺

add std::sync::mpsc::Sender in to HotplugHandler and send arrived device

@a1ien
Copy link
Owner

a1ien commented Jan 13, 2022

use rusb::{Context, Device, HotplugBuilder, UsbContext};
use std::sync::mpsc;

struct HotPlugHandler<T: UsbContext> {
    sender: mpsc::Sender<Device<T>>,
}

impl<T: UsbContext> rusb::Hotplug<T> for HotPlugHandler<T> {
    fn device_arrived(&mut self, device: Device<T>) {
        println!("device arrived {:?}", device);
        self.sender.send(device);
    }

    fn device_left(&mut self, device: Device<T>) {
        println!("device left {:?}", device);
    }
}

impl<T: UsbContext> Drop for HotPlugHandler<T> {
    fn drop(&mut self) {
        println!("HotPlugHandler dropped");
    }
}

fn main() -> rusb::Result<()> {
    if rusb::has_hotplug() {
        let context = Context::new()?;
        let (tx, rx) = mpsc::channel::<Device<Context>>();
        let mut reg = Some(
            HotplugBuilder::new()
                .enumerate(true)
                .register(&context, Box::new(HotPlugHandler { sender: tx }))?,
        );

        std::thread::spawn(move || loop {
            let dev = rx.recv().unwrap();
            let desc = dev.device_descriptor().unwrap();
            println!("{:?}", desc);
        });

        loop {
            context.handle_events(None).unwrap();
            if let Some(reg) = reg.take() {
                context.unregister_callback(reg);
                break;
            }
        }
        Ok(())
    } else {
        eprint!("libusb hotplug api unsupported");
        Ok(())
    }
}

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