From 89254b903f605073f6ba224a39f00751cd385f65 Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Sun, 25 May 2025 13:03:50 +0200 Subject: [PATCH] Changed to a simpler layout to support Linux better --- layout.drawio | 340 +++++++++++++++++++++++------- rp2040/src/main.rs | 283 +++++-------------------- rp2040/src/usb_joystick_device.rs | 81 +++---- 3 files changed, 353 insertions(+), 351 deletions(-) diff --git a/layout.drawio b/layout.drawio index fc14a26..062b926 100644 --- a/layout.drawio +++ b/layout.drawio @@ -1,6 +1,6 @@ - + - + @@ -193,195 +193,389 @@ - + - - - + + + - + - + - + - + - + - + - + - - - - - - - - - - - - - - - - - - - + - + + + + + + + + + + + + + - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - - + + - + - + - + - + - + - + - + - + - + - - + + - - + + - + - + - + - + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/rp2040/src/main.rs b/rp2040/src/main.rs index 0c9d2ad..799b39c 100644 --- a/rp2040/src/main.rs +++ b/rp2040/src/main.rs @@ -82,12 +82,6 @@ pub struct Button { pub usb_changed: bool, pub usb_changed_to_pressed: bool, pub usb_button: usize, - pub usb_button_sec_enable: bool, - pub usb_button_sec: usize, - pub usb_button_sec_trigger_index: usize, - pub usb_button_sec_pressed: bool, - pub usb_button_toggle_enable: bool, - pub usb_release_timeout: u16, } #[derive(Copy, Clone)] @@ -285,119 +279,57 @@ fn main() -> ! { // | | - | - | - | | - |C OK | - | | // | | - | | - | | // --------------------------------------------------------------- + // USB HID joystick map : + // --------------------------------------------------------------- + // | B4 L| B3 U| B7 U| | B26 | | B8 U| B1 U| B2 L| + // --------------------------------------------------------------- + // | | B5 | B14 | B9 | | B10 | B15 | B6 | | + // | | + // | | B13 | | B17 | | + // | | B16 | | B12 | | + // | X1/Y1 X2/Y2 | + // | | B18 | | B22 | | + // | | B21 | B11 | B19 | | B25 | TH | B23 | | + // | | B20 | | B24 | | + // --------------------------------------------------------------- + // pub const CONFIG_BUTTON: usize = 2; pub const BOOT_BUTTON: usize = 0; pub const CAL_BUTTON: usize = 1; pub const CAL_DONE_BUTTON: usize = 20; pub const CAL_M10_GIMBLE_BUTTON: usize = 8; pub const CAL_M7_GIMBLE_BUTTON: usize = 9; - // HW Button index map: - // --------------------------------------------------------------- - // | 0 L| 1 U| 25 U | | 2 | | 26 U | 4 U| 3 L| - // --------------------------------------------------------------- - // | | 5 | 6 | 7 | | 12 | 11 | 10 | | - // | | - // | | 8 | | 13 | | - // | | 9 | | 14 | | - // | X1/Y1 X2/Y2 | - // | | 16 | | 21 | | - // | | 19 | 15 | 17 | | 24 | 20 | 22 | | - // | | 18 | | 23 | | - // --------------------------------------------------------------- - // - // USB HID joystick map : - // --------------------------------------------------------------- - // | Fn L| B19 U| B7 U| | B32 | | B8 U| B1 U| B2 L| - // --------------------------------------------------------------- - // | | B5 | B14 | B9 | | B10 | B15 | B6 | | - // | | - // | | B13 | | B17 | | - // | | B16 | | B18 | | - // | X1/Y1 X2/Y2 | - // | | H1U | | H2U | | - // | | H1L | B11 | H1R | | H2L | B12 | H2R | | - // | | H1D | | H2D | | - // --------------------------------------------------------------- - // - // USB HID joystick map (Fn): - // --------------------------------------------------------------- - // | Fn L| B21 U| B27 U| | B32 | | B8 U| B3 U| B4 L| - // --------------------------------------------------------------- - // | | TH | B22 | B26 | | B28 | B24 | B23 | | - // | | - // | | B29 | | B31 | | - // | | B16 | | B18 | | - // | X1/Y1 X2/Y2 | - // | | H3U | | H4U | | - // | | H3L | B20 | H3R | | H4L | B25 | H4R | | - // | | H3D | | H4D | | - // --------------------------------------------------------------- // Special button functions // Throttle hold: - pub const TH_BUTTON: usize = 5; - pub const TH_BUTTON_TRIGGER: usize = 0; + pub const TH_BUTTON: usize = 20; - // Set up usb button layout (button 0 to 15, 20, 25 and 26) - buttons[0].usb_button = 0; // Fn. Setting to 0 to disable USB button generation - buttons[1].usb_button = 19; - buttons[1].usb_button_sec_enable = true; - buttons[1].usb_button_sec = 21; - buttons[1].usb_button_sec_trigger_index = 0; - buttons[2].usb_button = 32; // Button used as global config. Do not define secondary USB button! + // Set up usb button layout + buttons[0].usb_button = 4; + buttons[1].usb_button = 3; + buttons[2].usb_button = 26; // Button used as global config. Do not define secondary USB button! buttons[3].usb_button = 2; - buttons[3].usb_button_sec_enable = true; - buttons[3].usb_button_sec = 4; - buttons[3].usb_button_sec_trigger_index = 0; buttons[4].usb_button = 1; - buttons[4].usb_button_sec_enable = true; - buttons[4].usb_button_sec = 3; - buttons[4].usb_button_sec_trigger_index = 0; buttons[5].usb_button = 5; - buttons[5].usb_button_sec_enable = true; // Set TH_BUTTON to inhibit button press on throttle hold - buttons[5].usb_button_sec = 0; // Setting to 0 to disable USB buttton generation - buttons[5].usb_button_sec_trigger_index = 0; // Set same as TH_BUTTON_TRIGGER buttons[6].usb_button = 14; - buttons[6].usb_button_sec_enable = true; - buttons[6].usb_button_sec = 22; - buttons[6].usb_button_sec_trigger_index = 0; buttons[7].usb_button = 9; - buttons[7].usb_button_sec_enable = true; - buttons[7].usb_button_sec = 26; - buttons[7].usb_button_sec_trigger_index = 0; buttons[8].usb_button = 13; - buttons[8].usb_button_sec_enable = true; - buttons[8].usb_button_sec = 29; - buttons[8].usb_button_sec_trigger_index = 0; buttons[9].usb_button = 16; buttons[10].usb_button = 6; - buttons[10].usb_button_sec_enable = true; - buttons[10].usb_button_sec = 23; - buttons[10].usb_button_sec_trigger_index = 0; buttons[11].usb_button = 15; - buttons[11].usb_button_sec_enable = true; - buttons[11].usb_button_sec = 24; - buttons[11].usb_button_sec_trigger_index = 0; buttons[12].usb_button = 10; - buttons[12].usb_button_sec_enable = true; - buttons[12].usb_button_sec = 28; - buttons[12].usb_button_sec_trigger_index = 0; buttons[13].usb_button = 17; - buttons[13].usb_button_sec_enable = true; - buttons[13].usb_button_sec = 31; - buttons[13].usb_button_sec_trigger_index = 0; - buttons[14].usb_button = 18; + buttons[14].usb_button = 12; buttons[15].usb_button = 11; - buttons[15].usb_button_sec_enable = true; - buttons[15].usb_button_sec = 20; - buttons[15].usb_button_sec_trigger_index = 0; - buttons[20].usb_button = 12; - buttons[20].usb_button_sec_enable = true; - buttons[20].usb_button_sec = 25; - buttons[20].usb_button_sec_trigger_index = 0; + buttons[16].usb_button = 18; + buttons[17].usb_button = 19; + buttons[18].usb_button = 20; + buttons[19].usb_button = 21; + buttons[20].usb_button = 0; + buttons[21].usb_button = 22; + buttons[22].usb_button = 23; + buttons[23].usb_button = 24; + buttons[24].usb_button = 25; buttons[25].usb_button = 7; - buttons[25].usb_button_sec_enable = true; - buttons[25].usb_button_sec = 27; - buttons[25].usb_button_sec_trigger_index = 0; buttons[26].usb_button = 8; // Table for gimbal expo curve lookup insded of doing floating point math for every analog read @@ -496,6 +428,27 @@ fn main() -> ! { buttons[25].pressed = left_extra_button.is_low().unwrap(); buttons[26].pressed = right_extra_button.is_low().unwrap(); + // Filter left hat swith buttons + for i in 16..=19 { + if (16..=19).filter(|&j| j != i).any(|j| buttons[j].pressed) { + buttons[i].pressed = false; + } + } + // Fix button state for center hat press on hat + if buttons[16..=19].iter().any(|b| b.pressed) { + buttons[15].pressed = false; + } + // Filter right hat swith buttons + for i in 21..=24 { + if (21..=24).filter(|&j| j != i).any(|j| buttons[j].pressed) { + buttons[i].pressed = false; + } + } + // Fix button state for center hat press on hat + if buttons[21..=24].iter().any(|b| b.pressed) { + buttons[20].pressed = false; + } + // Secondary way to enter bootloader (pressing all left hands buttons except the hat if buttons[BOOT_BUTTON].pressed && buttons[CONFIG_BUTTON].pressed { status_led.update(StatusMode::Bootloader); @@ -615,20 +568,7 @@ fn main() -> ! { item.previous_value = item.value; } - // Make sure usb will be updated during timeout countdown - for key in buttons.iter() { - if key.usb_release_timeout != 0 { - usb_activity = true; - } - } - // Generate led activity when a button is pressed - let mut th_trigger_pressed: bool = false; - for (index, key) in buttons.iter_mut().enumerate() { - if key.pressed && index == TH_BUTTON_TRIGGER { - th_trigger_pressed = true; - } - } for (index, key) in buttons.iter_mut().enumerate() { if key.pressed != key.previous_pressed { key.usb_changed = true; @@ -639,7 +579,6 @@ fn main() -> ! { if key.pressed != key.previous_pressed && key.pressed && index == TH_BUTTON - && th_trigger_pressed && unprocessed_value != AXIS_CENTER { axis[GIMBAL_AXIS_LEFT_Y].hold = axis[GIMBAL_AXIS_LEFT_Y].value; @@ -647,7 +586,6 @@ fn main() -> ! { } else if key.pressed != key.previous_pressed && key.pressed && index == TH_BUTTON - && th_trigger_pressed && unprocessed_value == AXIS_CENTER { axis[GIMBAL_AXIS_LEFT_Y].hold = AXIS_CENTER; @@ -730,127 +668,12 @@ fn get_joystick_report( let y: i16 = axis_12bit_to_i16(ADC_MAX - axis[GIMBAL_AXIS_LEFT_Y].value); let z: i16 = axis_12bit_to_i16(axis[GIMBAL_AXIS_RIGHT_X].value); let rx: i16 = axis_12bit_to_i16(ADC_MAX - axis[GIMBAL_AXIS_RIGHT_Y].value); - let mut hat1: u8 = 0xf; - let mut hat2: u8 = 0xf; - let mut hat3: u8 = 0xf; - let mut hat4: u8 = 0xf; - - // Store hat bits - let mut hat_left: u8 = 0; - let mut hat_right: u8 = 0; - for (index, key) in matrix_keys.iter_mut().enumerate() { - if (15..=19).contains(&index) && key.pressed { - hat_left |= 1 << (index - 15); - } - if (20..=24).contains(&index) && key.pressed { - hat_right |= 1 << (index - 20); - } - } - - // Convert hat switch data to HID code - let (hat_l, hat_button_l) = format_hat_value(hat_left); - let (hat_r, hat_button_r) = format_hat_value(hat_right); - - // Handle sec_button (Fn) for left hat switch - let mut sec_button_pressed: bool = false; - for (sec_index, sec_key) in matrix_keys.iter().enumerate() { - if matrix_keys[15].usb_button_sec_enable - && matrix_keys[15].usb_button_sec_trigger_index == sec_index - && sec_key.pressed - { - sec_button_pressed = true; - break; - } - } - if matrix_keys[15].usb_changed { - matrix_keys[15].usb_button_sec_pressed = sec_button_pressed; - } - if matrix_keys[15].usb_button_sec != 0 && matrix_keys[15].usb_button_sec_pressed { - hat2 = hat_l; - } else { - hat4 = hat_l; - } - - // Handle sec_button (Fn) for right hat switch - let mut sec_button_pressed: bool = false; - for (sec_index, sec_key) in matrix_keys.iter().enumerate() { - if matrix_keys[20].usb_button_sec_enable - && matrix_keys[20].usb_button_sec_trigger_index == sec_index - && sec_key.pressed - { - sec_button_pressed = true; - break; - } - } - if matrix_keys[20].usb_changed { - matrix_keys[20].usb_button_sec_pressed = sec_button_pressed; - } - if matrix_keys[20].usb_button_sec != 0 && matrix_keys[20].usb_button_sec_pressed { - hat1 = hat_r; - } else { - hat3 = hat_r; - } - - // Fix button state for center hat press on hat - matrix_keys[15].pressed = hat_button_l != 0; - matrix_keys[20].pressed = hat_button_r != 0; - - // Update button array with Sec button trigger status - // Using indexing instead of iterating to be able to iterate inside loop - for index in 0..NUMBER_OF_BUTTONS + 2 { - let mut sec_button_pressed: bool = false; - for (sec_index, sec_key) in matrix_keys.iter().enumerate() { - if matrix_keys[index].usb_button_sec_enable - && matrix_keys[index].usb_button_sec_trigger_index == sec_index - && sec_key.pressed - { - sec_button_pressed = true; - break; - } - } - // Only update button when "root key" is pressed (ie. Do not change sec button as soon as Fn - // key is pressed - if matrix_keys[index].usb_changed { - matrix_keys[index].usb_button_sec_pressed = sec_button_pressed; - } - } // Update button state for joystick buttons let mut buttons: u32 = 0; for key in matrix_keys.iter_mut() { - // Toggle mode button - if key.usb_changed && key.usb_button_toggle_enable { - key.usb_release_timeout = RELEASE_RIMEOUT; - } - if key.pressed - && key.usb_button != 0 - && key.usb_button_toggle_enable - && key.usb_release_timeout > 1 - { + if key.pressed && key.usb_button != 0 { buttons |= 1 << (key.usb_button - 1); - } else if !key.pressed - && key.usb_button_sec != 0 - && key.usb_button_toggle_enable - && key.usb_release_timeout > 1 - { - buttons |= 1 << (key.usb_button_sec - 1); - // Sec button mode - } else if key.pressed && key.usb_button_sec != 0 && key.usb_button_sec_pressed { - buttons |= 1 << (key.usb_button_sec - 1); - // Standard mode - } else if key.pressed - && key.usb_button != 0 - && !key.usb_button_toggle_enable - && !key.usb_button_sec_pressed - { - buttons |= 1 << (key.usb_button - 1); - } - } - - // Auto release button when in toggle mode - for key in matrix_keys.iter_mut() { - if key.usb_release_timeout > 0 { - key.usb_release_timeout -= 1; } } @@ -864,10 +687,6 @@ fn get_joystick_report( y, z, rx, - hat1, - hat2, - hat3, - hat4, buttons, } } diff --git a/rp2040/src/usb_joystick_device.rs b/rp2040/src/usb_joystick_device.rs index da44dc4..216f5ce 100644 --- a/rp2040/src/usb_joystick_device.rs +++ b/rp2040/src/usb_joystick_device.rs @@ -63,42 +63,37 @@ impl Try for Result { // Updated to 6x 12bit axis, 32x buttons and 4x hat switches #[rustfmt::skip] pub const JOYSTICK_DESCRIPTOR: &[u8] = &[ -0x05, 0x01, // Usage Page (Generic Desktop) -0x09, 0x04, // Usage (Joystick) -0xA1, 0x01, // Collection (Application) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + // 4 signed 16-bit axes: X, Y, Z, Rx - 0x09, 0x30, // Usage (X) - 0x09, 0x31, // Usage (Y) - 0x09, 0x32, // Usage (Z) - 0x09, 0x33, // Usage (Rx) - 0x16, 0x00, 0x80,// Logical Minimum (-32768) - 0x26, 0xFF, 0x7F,// Logical Maximum (32767) - 0x75, 0x10, // Report Size (16) - 0x95, 0x04, // Report Count (4) - 0x81, 0x02, // Input (Data,Var,Abs) - // 4 Hat Switches (4-bit) - 0x09, 0x39, // Usage (Hat switch) - 0x09, 0x39, - 0x09, 0x39, - 0x09, 0x39, - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x07, // Logical Maximum (7) - 0x35, 0x00, // Physical Minimum (0) - 0x46, 0x3B, 0x01,// Physical Maximum (315) - 0x65, 0x14, // Unit (Degrees) - 0x75, 0x04, // Report Size (4) - 0x95, 0x04, // Report Count (4) - 0x81, 0x02, // Input (Data,Var,Abs) - // 32 Buttons (1-bit each) - 0x05, 0x09, // Usage Page (Button) - 0x19, 0x01, // Usage Minimum (1) - 0x29, 0x20, // Usage Maximum (32) - 0x15, 0x00, // Logical Minimum (0) - 0x25, 0x01, // Logical Maximum (1) - 0x75, 0x01, // Report Size (1) - 0x95, 0x20, // Report Count (32) - 0x81, 0x02, // Input (Data,Var,Abs) -0xC0 // End Collection + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x33, // Usage (Rx) + 0x16, 0x00, 0x80, // Logical Minimum (-32768) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x75, 0x10, // Report Size (16) + 0x95, 0x04, // Report Count (4) + 0x81, 0x02, // Input (Data,Var,Abs) + + // 26 Buttons (1-bit each) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (1) + 0x29, 0x1A, // Usage Maximum (26) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x75, 0x01, // Report Size (1) + 0x95, 0x1A, // Report Count (26) + 0x81, 0x02, // Input (Data,Var,Abs) + + // Padding to align buttons to byte boundary (26 bits → +6 bits padding) + 0x75, 0x01, // Report Size (1) + 0x95, 0x06, // Report Count (6) + 0x81, 0x03, // Input (Const,Var,Abs) + + 0xC0 // End Collection ]; #[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] @@ -107,10 +102,6 @@ pub struct JoystickReport { pub y: i16, // 16bit pub z: i16, // 16bit pub rx: i16, // 16bit - pub hat1: u8, // 4bit - pub hat2: u8, // 4bit - pub hat3: u8, // 4bit - pub hat4: u8, // 4bit pub buttons: u32, // 32bit } @@ -120,7 +111,7 @@ pub struct Joystick<'a, B: UsbBus> { impl Joystick<'_, B> { pub fn write_report(&mut self, report: &JoystickReport) -> Result<(), UsbHidError> { - let mut data: [u8; 14] = [0; 14]; + let mut data: [u8; 12] = [0; 12]; // Did not make the packed struct work, so doing it manually data[0] = report.x as u8; @@ -131,12 +122,10 @@ impl Joystick<'_, B> { data[5] = (report.z >> 8) as u8; data[6] = report.rx as u8; data[7] = (report.rx >> 8) as u8; - data[8] = (report.hat3) | (report.hat4 << 4); - data[9] = (report.hat1) | (report.hat2 << 4); - data[10] = report.buttons as u8; - data[11] = (report.buttons >> 8) as u8; - data[12] = (report.buttons >> 16) as u8; - data[13] = (report.buttons >> 24) as u8; + data[8] = report.buttons as u8; + data[9] = (report.buttons >> 8) as u8; + data[10] = (report.buttons >> 16) as u8; + data[11] = (report.buttons >> 24) as u8; self.interface .write_report(&data)