KaiseiYokoyama / joycon-rs

Joy-Con library for Rust 🦀 🎮
Apache License 2.0
117 stars 8 forks source link

Panic after reconnecting joycon #66

Open carl-anders opened 2 years ago

carl-anders commented 2 years ago

Hi. I'm using your library (version 0.6.1), and I'm noticing that with the example code in "standard_full_report.rs" the main thread panics if I

I'm using Windows 10 Pro - 21H1 - 19043.1348 Rust 1.56.1

I have lightly edited the example code to be able to show the error more clearly (without all the normal controller messages), and with a stacktrace

#![allow(unused_must_use)]

use joycon_rs::prelude::*;

fn main() -> JoyConResult<()> {
    // First, connect your Joy-Cons to your computer!

    let (tx, rx) = std::sync::mpsc::channel();

    let _output = std::thread::spawn(move || {
        // Push buttons or tilt the stick please.
        // Stop with `Cmd + C` or `Ctrl + C`
        while let Ok(_message) = rx.recv() {
            //dbg!(message);
        }
    });

    let manager = JoyConManager::get_instance();

    let devices = {
        let lock = manager.lock();
        match lock {
            Ok(manager) => manager.new_devices(),
            Err(_) => unreachable!(),
        }
    };

    devices.iter()
        .try_for_each::<_, JoyConResult<()>>(|d| {
            let driver = SimpleJoyConDriver::new(&d)?;
            let standard_full_mode = StandardFullMode::new(driver)?;
            let tx = tx.clone();

            std::thread::spawn( move || {
                loop {
                    match standard_full_mode.read_input_report() {
                        Ok(report) => {
                            tx.send(report).unwrap()
                        }
                        Err(JoyConError::Disconnected) => {
                            println!("Disconnected");
                            return;
                        }
                        Err(a) => {
                            dbg!(a);
                            return;
                        }
                    };
                }
            });

            Ok(())
        })?;

    Ok(())
}

Program output and stacktrace:

[src\main.rs:45] a = HidApiError(
    HidApiError {
        message: "The device is not connected.",
    },
)
thread '<unnamed>' panicked at 'internal error: entered unreachable code', C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\joycon-rs-0.6.1\src\joycon\manager.rs:219:30
stack backtrace:
   0:     0x7ff6bbaa36fe - std::backtrace_rs::backtrace::dbghelp::trace
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\..\..\backtrace\src\backtrace\dbghelp.rs:98
   1:     0x7ff6bbaa36fe - std::backtrace_rs::backtrace::trace_unsynchronized
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\..\..\backtrace\src\backtrace\mod.rs:66
   2:     0x7ff6bbaa36fe - std::sys_common::backtrace::_print_fmt
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\sys_common\backtrace.rs:67
   3:     0x7ff6bbaa36fe - std::sys_common::backtrace::_print::impl$0::fmt
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\sys_common\backtrace.rs:46
   4:     0x7ff6bbab361a - core::fmt::write
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\core\src\fmt\mod.rs:1150
   5:     0x7ff6bbaa1098 - std::io::Write::write_fmt<std::sys::windows::stdio::Stderr>
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\io\mod.rs:1667
   6:     0x7ff6bbaa5b56 - std::sys_common::backtrace::_print
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\sys_common\backtrace.rs:49
   7:     0x7ff6bbaa5b56 - std::sys_common::backtrace::print
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\sys_common\backtrace.rs:36
   8:     0x7ff6bbaa5b56 - std::panicking::default_hook::closure$1
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\panicking.rs:210
   9:     0x7ff6bbaa5644 - std::panicking::default_hook
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\panicking.rs:227
  10:     0x7ff6bbaa61b5 - std::panicking::rust_panic_with_hook
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\panicking.rs:624
  11:     0x7ff6bbaa5d6f - std::panicking::begin_panic_handler::closure$0
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\panicking.rs:519
  12:     0x7ff6bbaa4047 - std::sys_common::backtrace::__rust_end_short_backtrace<std::panicking::begin_panic_handler::closure$0,never$>
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\sys_common\backtrace.rs:141
  13:     0x7ff6bbaa5cf9 - std::panicking::begin_panic_handler
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\panicking.rs:517
  14:     0x7ff6bbaba400 - core::panicking::panic_fmt
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\core\src\panicking.rs:101
  15:     0x7ff6bbaba34c - core::panicking::panic
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\core\src\panicking.rs:50
  16:     0x7ff6bba45268 - joycon_rs::joycon::manager::impl$0::scan::closure$7
                               at C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\joycon-rs-0.6.1\src\joycon\manager.rs:219
  17:     0x7ff6bba4241d - core::iter::traits::iterator::Iterator::for_each::call::closure$0<ref$<ref$<joycon_rs::joycon::manager::JoyConSerialNumber> >,joycon_rs::joycon::manager::impl$0::scan::closure$7>
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\core\src\iter\traits\iterator.rs:730
  18:     0x7ff6bba68e62 - core::iter::traits::iterator::Iterator::fold<std::collections::hash::set::Iter<ref$<joycon_rs::joycon::manager::JoyConSerialNumber> >,tuple$<>,core::iter::traits::iterator::Iterator::for_each::call::closure$0>
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\core\src\iter\traits\iterator.rs:2170
  19:     0x7ff6bba690d9 - core::iter::traits::iterator::Iterator::for_each<std::collections::hash::set::Iter<ref$<joycon_rs::joycon::manager::JoyConSerialNumber> >,joycon_rs::joycon::manager::impl$0::scan::closure$7>
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\core\src\iter\traits\iterator.rs:733
  20:     0x7ff6bba44723 - joycon_rs::joycon::manager::JoyConManager::scan
                               at C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\joycon-rs-0.6.1\src\joycon\manager.rs:201
  21:     0x7ff6bba43ee4 - joycon_rs::joycon::manager::impl$0::with_interval::closure$1
                               at C:\Users\me\.cargo\registry\src\github.com-1ecc6299db9ec823\joycon-rs-0.6.1\src\joycon\manager.rs:93
  22:     0x7ff6bba5e4fa - std::sys_common::backtrace::__rust_begin_short_backtrace<joycon_rs::joycon::manager::impl$0::with_interval::closure$1,tuple$<> >
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\std\src\sys_common\backtrace.rs:125
  23:     0x7ff6bba53c28 - std::thread::impl$0::spawn_unchecked::closure$0::closure$0<joycon_rs::joycon::manager::impl$0::with_interval::closure$1,tuple$<> >
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\std\src\thread\mod.rs:481
  24:     0x7ff6bba5c588 - core::panic::unwind_safe::impl$23::call_once<tuple$<>,std::thread::impl$0::spawn_unchecked::closure$0::closure$0>
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\core\src\panic\unwind_safe.rs:271
  25:     0x7ff6bba6e708 - std::panicking::try::do_call<core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked::closure$0::closure$0>,tuple$<> >
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\std\src\panicking.rs:403
  26:     0x7ff6bba6f9c3 - crossbeam_channel::context::impl$2::clone
  27:     0x7ff6bba6e649 - std::panicking::try<tuple$<>,core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked::closure$0::closure$0> >
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\std\src\panicking.rs:367
  28:     0x7ff6bba62a88 - std::panic::catch_unwind<core::panic::unwind_safe::AssertUnwindSafe<std::thread::impl$0::spawn_unchecked::closure$0::closure$0>,tuple$<> >
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\std\src\panic.rs:129
  29:     0x7ff6bba53a8f - std::thread::impl$0::spawn_unchecked::closure$0<joycon_rs::joycon::manager::impl$0::with_interval::closure$1,tuple$<> >
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\std\src\thread\mod.rs:480
  30:     0x7ff6bba53fee - core::ops::function::FnOnce::call_once<std::thread::impl$0::spawn_unchecked::closure$0,tuple$<> >
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\core\src\ops\function.rs:227
  31:     0x7ff6bbaa7cdc - alloc::boxed::impl$44::call_once
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\alloc\src\boxed.rs:1636
  32:     0x7ff6bbaa7cdc - alloc::boxed::impl$44::call_once
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\library\alloc\src\boxed.rs:1636
  33:     0x7ff6bbaa7cdc - std::sys::windows::thread::impl$0::new::thread_start
                               at /rustc/59eed8a2aac0230a8b53e89d4e99d55912ba6b35\/library\std\src\sys\windows\thread.rs:58
  34:     0x7ffcaf2c7034 - BaseThreadInitThunk
  35:     0x7ffcb0202651 - RtlUserThreadStart
KaiseiYokoyama commented 2 years ago

I appreciate your report.

I tried to reproduce it on Windows 10 Home 21H1 19043.1348, but the main thread does not panic. (And it seems that JoyConManager does not recognize the reconnection :sob: )

@carl-anders Does it ALWAYS panics?

carl-anders commented 2 years ago

It seems to panic 90% of the times I try to reconnect a controller, and when it doesn't panic it hangs somewhere.

I did some basic debugging of the problem, and it seems to be that when it detects a reconnect it assumes that the JoyConDevice::new call was successful. On my joycon that call is only successful about 10% of the times it is run.

I added some dbg! commands, like this in src/joycon/manager.rs: bild

Which combined with the earlier example code gives this output when I connect, disconnect and reconnect the joycon:

[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedStickParameterLoading,
)
[src\joycon\manager.rs:168] &d = JoyConDevice { hid_device: Connected, serial_number: 9458cb03c2a3, device_type: JoyConL, stick_parameters: StickParameters { dead_zone: 174, range_ratio: 3604 }, , stick_factory_calibration: JoyConSticksCalibration { left: Available { x: AxisCalibration { max: 3235, center: 1906, min: 621 }, y: AxisCalibration { max: 3253, center: 2134, min: 1023 } }, right: Unavailable }, stick_user_calibration: JoyConSticksCalibration { left: Unavailable, right: Unavailable }, imu_offsets: IMUOffsets { x: 350, y: 0, z: 4081 }, imu_factory_calibration: Available { acc_origin_position: XYZ { x: 5, y: 19, z: 212 }, acc_sensitivity_special_coeff: XYZ { x: 16384, y: 16384, z: 16384 }, gyro_origin_position: XYZ { x: 9, y: -8, z: 2 }, gyro_sensitivity_special_coeff: XYZ { x: 15335, y: 15335, z: 15335 } }, imu_user_calibration: Unavailable, color: Color { body: [30, 220, 0], buttons: [0, 40, 0], left_grip: None, right_grip: None } }

[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedStickCalibrationLoading,
)
[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedStickParameterLoading,
)
[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedIMUCalibrationLoading,
)
[src\joycon\manager.rs:168] &d = JoyConDevice { hid_device: Connected, serial_number: 9458cb03c2a3, device_type: JoyConL, stick_parameters: StickParameters { dead_zone: 174, range_ratio: 3604 }, , stick_factory_calibration: JoyConSticksCalibration { left: Available { x: AxisCalibration { max: 3235, center: 1906, min: 621 }, y: AxisCalibration { max: 3253, center: 2134, min: 1023 } }, right: Unavailable }, stick_user_calibration: JoyConSticksCalibration { left: Unavailable, right: Unavailable }, imu_offsets: IMUOffsets { x: 350, y: 0, z: 4081 }, imu_factory_calibration: Available { acc_origin_position: XYZ { x: 5, y: 19, z: 212 }, acc_sensitivity_special_coeff: XYZ { x: 16384, y: 16384, z: 16384 }, gyro_origin_position: XYZ { x: 9, y: -8, z: 2 }, gyro_sensitivity_special_coeff: XYZ { x: 15335, y: 15335, z: 15335 } }, imu_user_calibration: Unavailable, color: Color { body: [30, 220, 0], buttons: [0, 40, 0], left_grip: None, right_grip: None } }

[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedColorLoading,
)
[src\joycon\manager.rs:168] &d = JoyConDevice { hid_device: Connected, serial_number: 9458cb03c2a3, device_type: JoyConL, stick_parameters: StickParameters { dead_zone: 174, range_ratio: 3604 }, , stick_factory_calibration: JoyConSticksCalibration { left: Available { x: AxisCalibration { max: 3235, center: 1906, min: 621 }, y: AxisCalibration { max: 3253, center: 2134, min: 1023 } }, right: Unavailable }, stick_user_calibration: JoyConSticksCalibration { left: Unavailable, right: Unavailable }, imu_offsets: IMUOffsets { x: 350, y: 0, z: 4081 }, imu_factory_calibration: Available { acc_origin_position: XYZ { x: 5, y: 19, z: 212 }, acc_sensitivity_special_coeff: XYZ { x: 16384, y: 16384, z: 16384 }, gyro_origin_position: XYZ { x: 9, y: -8, z: 2 }, gyro_sensitivity_special_coeff: XYZ { x: 15335, y: 15335, z: 15335 } }, imu_user_calibration: Unavailable, color: Color { body: [30, 220, 0], buttons: [0, 40, 0], left_grip: None, right_grip: None } }

[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedColorLoading,
)
[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedIMUOffsetsLoading,
)
[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedIMUCalibrationLoading,
)
[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedStickCalibrationLoading,
)
[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedStickParameterLoading,
)
[src\main.rs:47] a = HidApiError(
    HidApiError {
        message: "The device is not connected.",
    },
)
[src\joycon\manager.rs:169] e = JoyConDeviceError(
    FailedStickParameterLoading,
)
[src\joycon\manager.rs:206] &self.devices = {
    JoyConSerialNumber(
        "9458cb03c2a3",
    ): Mutex {
        data: JoyConDevice { hid_device: Disconnected, serial_number: 9458cb03c2a3, device_type: JoyConL, stick_parameters: StickParameters { dead_zone: 174, range_ratio: 3604 }, , stick_factory_calibration: JoyConSticksCalibration { left: Available { x: AxisCalibration { max: 3235, center: 1906, min: 621 }, y: AxisCalibration { max: 3253, center: 2134, min: 1023 } }, right: Unavailable }, stick_user_calibration: JoyConSticksCalibration { left: Unavailable, right: Unavailable }, imu_offsets: IMUOffsets { x: 350, y: 0, z: 4081 }, imu_factory_calibration: Available { acc_origin_position: XYZ { x: 5, y: 19, z: 212 }, acc_sensitivity_special_coeff: XYZ { x: 16384, y: 16384, z: 16384 }, gyro_origin_position: XYZ { x: 9, y: -8, z: 2 }, gyro_sensitivity_special_coeff: XYZ { x: 15335, y: 15335, z: 15335 } }, imu_user_calibration: Unavailable, color: Color { body: [30, 220, 0], buttons: [0, 40, 0], left_grip: None, right_grip: None } }
        ,
        poisoned: false,
        ..
    },
}
[src\joycon\manager.rs:207] &detected_devices = {}
[src\joycon\manager.rs:208] &k = JoyConSerialNumber(
    "9458cb03c2a3",
)
thread '<unnamed>' panicked at 'internal error: entered unreachable code', src\joycon\manager.rs:225:30

(Some duplicates removed)

As you can see, this time when it reconnect, the JoyConDevice::new command had failed (it was not lucky), so it could not find it in the list of devices, and panics.

Also, how come the JoyConDevice::new function is run for already connected joycons? Is it not better to only run it for new and reconnected serial numbers?

KaiseiYokoyama commented 2 years ago

Also, how come the JoyConDevice::new function is run for already connected joycons? Is it not better to only run it for new and reconnected serial numbers?

@carl-anders Yes, I admit that I made a mistake. Perhaps I was drinking when I wrote this code. 🍺