diff --git a/layout.drawio b/layout.drawio index fc14a26..4492d13 100644 --- a/layout.drawio +++ b/layout.drawio @@ -1,970 +1,245 @@ - - - + + + - - - + + + - + - + - + - - - - - - - - - - - - - - - - - - - - - - - - - + - + - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - + + - - - - + - + - + - + - + - + - + - + - + - - + + - - + + - + - + - - + + - + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/rp2040/src/main.rs b/rp2040/src/main.rs index 0c9d2ad..fa5e844 100644 --- a/rp2040/src/main.rs +++ b/rp2040/src/main.rs @@ -49,6 +49,57 @@ pub static BOOT2_FIRMWARE: [u8; 256] = rp2040_boot2::BOOT_LOADER_W25Q080; const XTAL_FREQ_HZ: u32 = 12_000_000u32; // Public constants +// 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 | | +// --------------------------------------------------------------- +pub const BUTTON_FRONT_LEFT_LOWER: usize = 0; +pub const BUTTON_FRONT_LEFT_UPPER: usize = 1; +pub const BUTTON_FRONT_LEFT_EXTRA: usize = 25; +pub const BUTTON_FRONT_CONFIG: usize = 2; +pub const BUTTON_FRONT_RIGHT_LOWER: usize = 3; +pub const BUTTON_FRONT_RIGHT_UPPER: usize = 4; +pub const BUTTON_FRONT_RIGHT_EXTRA: usize = 26; +pub const BUTTON_TOP_LEFT_LOW: usize = 5; +pub const BUTTON_TOP_LEFT_HIGH: usize = 6; +pub const BUTTON_TOP_LEFT_MODE: usize = 7; +pub const BUTTON_TOP_LEFT_UP: usize = 8; +pub const BUTTON_TOP_LEFT_DOWN: usize = 9; +pub const BUTTON_TOP_LEFT_HAT: usize = 15; +pub const BUTTON_TOP_LEFT_HAT_UP: usize = 16; +pub const BUTTON_TOP_LEFT_HAT_RIGHT: usize = 17; +pub const BUTTON_TOP_LEFT_HAT_DOWN: usize = 18; +pub const BUTTON_TOP_LEFT_HAT_LEFT: usize = 19; +pub const BUTTON_TOP_RIGHT_LOW: usize = 10; +pub const BUTTON_TOP_RIGHT_HIGH: usize = 11; +pub const BUTTON_TOP_RIGHT_MODE: usize = 12; +pub const BUTTON_TOP_RIGHT_UP: usize = 13; +pub const BUTTON_TOP_RIGHT_DOWN: usize = 14; +pub const BUTTON_TOP_RIGHT_HAT: usize = 20; +pub const BUTTON_TOP_RIGHT_HAT_UP: usize = 21; +pub const BUTTON_TOP_RIGHT_HAT_RIGHT: usize = 22; +pub const BUTTON_TOP_RIGHT_HAT_DOWN: usize = 23; +pub const BUTTON_TOP_RIGHT_HAT_LEFT: usize = 24; + +pub const USB_HAT_UP: usize = 33; +pub const USB_HAT_RIGHT: usize = 34; +pub const USB_HAT_DOWN: usize = 35; +pub const USB_HAT_LEFT: usize = 36; + +// Special button functions +// Throttle hold: +pub const TH_BUTTON: usize = BUTTON_TOP_LEFT_MODE; +pub const VT_BUTTON: usize = BUTTON_TOP_RIGHT_MODE; + pub const BUTTON_ROWS: usize = 5; pub const BUTTON_COLS: usize = 5; pub const NUMBER_OF_BUTTONS: usize = BUTTON_ROWS * BUTTON_COLS; @@ -74,6 +125,8 @@ pub const DEBOUNCE: u8 = 10; pub const RELEASE_RIMEOUT: u16 = 30; // => 300ms +pub const EEPROM_DATA_LENGTH: usize = 25; + // Public types #[derive(Copy, Clone, Default)] pub struct Button { @@ -81,13 +134,17 @@ pub struct Button { pub previous_pressed: bool, 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, + pub usb_button: usize, // For short press + pub usb_button_long: usize, // For long press + pub enable_long_press: bool, // Flag to enable special behavior + pub enable_long_hold: bool, // Flag to enable special behavior + + // Internals + pub press_start_time: u32, // When physical press started + pub long_press_handled: bool, // True if long press activated + pub active_usb_button: usize, // Currently active USB button + pub usb_press_active: bool, // Is USB press currently "down" + pub usb_press_start_time: u32, // When USB press was sent } #[derive(Copy, Clone)] @@ -226,9 +283,10 @@ fn main() -> ! { // Scan matrix to get initial state and check if bootloader should be entered // This is done by holding button 0 pressed while power on the unit for _ in 0..10 { + // Scan 10 times to make sure debounce routine covered all buttons button_matrix.scan_matrix(&mut delay); } - if button_matrix.buttons_pressed()[0] { + if button_matrix.buttons_pressed()[BUTTON_FRONT_LEFT_LOWER] { status_led.update(StatusMode::Bootloader); let gpio_activity_pin_mask: u32 = 0; let disable_interface_mask: u32 = 0; @@ -241,6 +299,9 @@ fn main() -> ! { let mut status_led_count_down = timer.count_down(); status_led_count_down.start(250.millis()); + let mut ms_count_down = timer.count_down(); + ms_count_down.start(1.millis()); + let mut scan_count_down = timer.count_down(); scan_count_down.start(200u32.micros()); @@ -254,154 +315,70 @@ fn main() -> ! { let mut usb_active: bool = false; let mut calibration_active: bool = false; let mut throttle_hold_enable: bool = false; + let mut vt_enable: bool = false; let mut axis: [GimbalAxis; NBR_OF_GIMBAL_AXIS] = [Default::default(); NBR_OF_GIMBAL_AXIS]; let mut buttons: [Button; NUMBER_OF_BUTTONS + 2] = [Button::default(); NUMBER_OF_BUTTONS + 2]; + let mut virtual_ry: u16 = AXIS_CENTER; + let mut virtual_rz: u16 = AXIS_CENTER; let mut gimbal_mode: u8; - // 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 | | - // --------------------------------------------------------------- - // Config Layer (holding CONFIG button) - // --------------------------------------------------------------- - // |BOOT L| CAL U| | CONFIG | | - | - | - // --------------------------------------------------------------- - // | | - | - | - | | - | - | - | | - // | | - // | |C M10| | - | | - // | |C M7 | | - | | - // | -/- -/- | - // | | - | | - | | - // | | - | - | - | | - |C OK | - | | - // | | - | | - | | - // --------------------------------------------------------------- - 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; - - // 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! - 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[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[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; + // Set up usb button layout + buttons[BUTTON_FRONT_LEFT_LOWER].usb_button = 29; + buttons[BUTTON_FRONT_LEFT_UPPER].usb_button = 28; + buttons[BUTTON_FRONT_CONFIG].usb_button = 32; // Button used as global config. + buttons[BUTTON_FRONT_CONFIG].usb_button_long = 3; + buttons[BUTTON_FRONT_CONFIG].enable_long_press = true; + buttons[BUTTON_FRONT_RIGHT_LOWER].usb_button = 2; + buttons[BUTTON_FRONT_RIGHT_UPPER].usb_button = 1; + buttons[BUTTON_TOP_LEFT_LOW].usb_button = 4; + buttons[BUTTON_TOP_LEFT_LOW].usb_button_long = 5; + buttons[BUTTON_TOP_LEFT_LOW].enable_long_press = true; + buttons[BUTTON_TOP_LEFT_LOW].enable_long_hold = true; + buttons[BUTTON_TOP_LEFT_HIGH].usb_button = 6; + buttons[BUTTON_TOP_LEFT_HIGH].usb_button_long = 7; + buttons[BUTTON_TOP_LEFT_HIGH].enable_long_press = true; + buttons[BUTTON_TOP_LEFT_MODE].usb_button = 0; + buttons[BUTTON_TOP_LEFT_UP].usb_button = 12; + buttons[BUTTON_TOP_LEFT_UP].usb_button_long = 13; + buttons[BUTTON_TOP_LEFT_UP].enable_long_press = true; + buttons[BUTTON_TOP_LEFT_DOWN].usb_button = 16; + buttons[BUTTON_TOP_LEFT_DOWN].usb_button_long = 17; + buttons[BUTTON_TOP_LEFT_DOWN].enable_long_press = true; + buttons[BUTTON_TOP_LEFT_DOWN].enable_long_hold = true; + buttons[BUTTON_TOP_RIGHT_LOW].usb_button = 10; + buttons[BUTTON_TOP_RIGHT_LOW].usb_button_long = 11; + buttons[BUTTON_TOP_RIGHT_LOW].enable_long_press = true; + buttons[BUTTON_TOP_RIGHT_HIGH].usb_button = 8; + buttons[BUTTON_TOP_RIGHT_HIGH].usb_button_long = 9; + buttons[BUTTON_TOP_RIGHT_HIGH].enable_long_press = true; + buttons[BUTTON_TOP_RIGHT_MODE].usb_button = 0; + buttons[BUTTON_TOP_RIGHT_UP].usb_button = 14; + buttons[BUTTON_TOP_RIGHT_UP].usb_button_long = 15; + buttons[BUTTON_TOP_RIGHT_UP].enable_long_press = true; + buttons[BUTTON_TOP_RIGHT_DOWN].usb_button = 18; + buttons[BUTTON_TOP_RIGHT_DOWN].usb_button_long = 19; + buttons[BUTTON_TOP_RIGHT_DOWN].enable_long_press = true; + buttons[BUTTON_TOP_LEFT_HAT].usb_button = 20; + buttons[BUTTON_TOP_LEFT_HAT].usb_button_long = 21; + buttons[BUTTON_TOP_LEFT_HAT].enable_long_press = true; + buttons[BUTTON_TOP_LEFT_HAT_UP].usb_button = 22; + buttons[BUTTON_TOP_LEFT_HAT_RIGHT].usb_button = 23; + buttons[BUTTON_TOP_LEFT_HAT_DOWN].usb_button = 24; + buttons[BUTTON_TOP_LEFT_HAT_LEFT].usb_button = 25; + buttons[BUTTON_TOP_RIGHT_HAT].usb_button = 26; + buttons[BUTTON_TOP_RIGHT_HAT].usb_button_long = 27; + buttons[BUTTON_TOP_RIGHT_HAT].enable_long_press = true; + buttons[BUTTON_TOP_RIGHT_HAT_UP].usb_button = 33; + buttons[BUTTON_TOP_RIGHT_HAT_RIGHT].usb_button = 34; + buttons[BUTTON_TOP_RIGHT_HAT_DOWN].usb_button = 35; + buttons[BUTTON_TOP_RIGHT_HAT_LEFT].usb_button = 36; + buttons[BUTTON_FRONT_LEFT_EXTRA].usb_button = 30; + buttons[BUTTON_FRONT_RIGHT_EXTRA].usb_button = 31; // Table for gimbal expo curve lookup insded of doing floating point math for every analog read let expo_lut: [u16; ADC_MAX as usize + 1] = generate_expo_lut(0.3); + let expo_lut_virtual: [u16; ADC_MAX as usize + 1] = generate_expo_lut(0.6); // Create dynamic smoother array for gimbal axis let mut smoother: [DynamicSmootherEcoI32; NBR_OF_GIMBAL_AXIS] = [ @@ -444,7 +421,7 @@ fn main() -> ! { item.center <<= 8; item.center |= eeprom.read_byte((index as u32 * 6) + 5).unwrap() as u16; } - gimbal_mode = eeprom.read_byte(25).unwrap(); + gimbal_mode = eeprom.read_byte(EEPROM_DATA_LENGTH as u32).unwrap(); loop { // Take care of USB HID poll requests @@ -483,6 +460,7 @@ fn main() -> ! { &usb_active, &calibration_active, &throttle_hold_enable, + &vt_enable, ); } @@ -493,11 +471,60 @@ fn main() -> ! { } // Updated extra buttons - buttons[25].pressed = left_extra_button.is_low().unwrap(); - buttons[26].pressed = right_extra_button.is_low().unwrap(); + buttons[BUTTON_FRONT_LEFT_EXTRA].pressed = left_extra_button.is_low().unwrap(); + buttons[BUTTON_FRONT_RIGHT_EXTRA].pressed = right_extra_button.is_low().unwrap(); - // Secondary way to enter bootloader (pressing all left hands buttons except the hat - if buttons[BOOT_BUTTON].pressed && buttons[CONFIG_BUTTON].pressed { + // Filter left hat swith buttons + for i in BUTTON_TOP_LEFT_HAT_UP..=BUTTON_TOP_LEFT_HAT_LEFT { + if (BUTTON_TOP_LEFT_HAT_UP..=BUTTON_TOP_LEFT_HAT_LEFT) + .filter(|&j| j != i) + .any(|j| buttons[j].pressed) + { + buttons[i].pressed = false; + } + } + // Fix button state for center hat press on hat + if buttons[BUTTON_TOP_LEFT_HAT_UP..=BUTTON_TOP_LEFT_HAT_LEFT] + .iter() + .any(|b| b.pressed) + { + buttons[BUTTON_TOP_LEFT_HAT].pressed = false; + } + // Filter right hat swith buttons + for i in BUTTON_TOP_RIGHT_HAT_UP..=BUTTON_TOP_RIGHT_HAT_LEFT { + if (BUTTON_TOP_RIGHT_HAT_UP..=BUTTON_TOP_RIGHT_HAT_LEFT) + .filter(|&j| j != i) + .any(|j| buttons[j].pressed) + { + buttons[i].pressed = false; + } + } + // Fix button state for center hat press on hat + if buttons[BUTTON_TOP_RIGHT_HAT_UP..=BUTTON_TOP_RIGHT_HAT_LEFT] + .iter() + .any(|b| b.pressed) + { + buttons[BUTTON_TOP_RIGHT_HAT].pressed = false; + } + + // Config Layer + // --------------------------------------------------------------- + // |BOOT L| CAL U| | CONFIG | | - | - | + // --------------------------------------------------------------- + // | | - | - | - | | - | - | - | | + // | | + // | |C M10| | - | | + // | |C M7 | | - | | + // | -/- -/- | + // | | - | | - | | + // | | - | - | - | | - |C OK | - | | + // | | - | | - | | + // --------------------------------------------------------------- + // Secondary way to enter bootloader + if buttons[BUTTON_FRONT_LEFT_LOWER].pressed + && buttons[BUTTON_TOP_LEFT_MODE].pressed + && buttons[BUTTON_TOP_RIGHT_MODE].pressed + { status_led.update(StatusMode::Bootloader); let gpio_activity_pin_mask: u32 = 0; let disable_interface_mask: u32 = 0; @@ -507,9 +534,11 @@ fn main() -> ! { ); } - // Calibration of center position (pressing all right hands buttons except - // the hat switch) - if buttons[CAL_BUTTON].pressed && buttons[CONFIG_BUTTON].pressed { + // Calibration of center position + if buttons[BUTTON_FRONT_LEFT_UPPER].pressed + && buttons[BUTTON_TOP_LEFT_MODE].pressed + && buttons[BUTTON_TOP_RIGHT_MODE].pressed + { for (index, item) in axis.iter_mut().enumerate() { item.center = smoother[index].value() as u16; item.min = item.center; @@ -529,14 +558,16 @@ fn main() -> ! { } } - if calibration_active && buttons[CAL_M10_GIMBLE_BUTTON].pressed { + // Calibration set M10 gimbal mode + if calibration_active && buttons[BUTTON_TOP_LEFT_UP].pressed { gimbal_mode = GIMBAL_MODE_M10; for (index, item) in axis.iter_mut().enumerate() { item.center = smoother[index].value() as u16; item.min = item.center; item.max = item.center; } - } else if calibration_active && buttons[CAL_M7_GIMBLE_BUTTON].pressed { + // Calibration set M7 gimbal mode + } else if calibration_active && buttons[BUTTON_TOP_LEFT_DOWN].pressed { gimbal_mode = GIMBAL_MODE_M7; for (index, item) in axis.iter_mut().enumerate() { item.center = smoother[index].value() as u16; @@ -545,8 +576,8 @@ fn main() -> ! { } } // Save calibration data to eeprom (pressing right hat switch) - else if calibration_active && buttons[CAL_DONE_BUTTON].pressed { - let mut eeprom_data: [u8; 25] = [0; 25]; + else if calibration_active && buttons[BUTTON_TOP_RIGHT_HAT].pressed { + let mut eeprom_data: [u8; EEPROM_DATA_LENGTH] = [0; EEPROM_DATA_LENGTH]; for (index, item) in axis.iter_mut().enumerate() { eeprom_data[index * 6] = item.min as u8; eeprom_data[(index * 6) + 1] = (item.min >> 8) as u8; @@ -555,12 +586,12 @@ fn main() -> ! { eeprom_data[(index * 6) + 4] = item.center as u8; eeprom_data[(index * 6) + 5] = (item.center >> 8) as u8; } - eeprom_data[24] = gimbal_mode; + eeprom_data[EEPROM_DATA_LENGTH - 1] = gimbal_mode; let _ = eeprom.write_page(0x01, &eeprom_data); calibration_active = false; } - // // ON/OFF switch for Throttle hold mode + // ON/OFF switch for Throttle hold mode throttle_hold_enable = axis[GIMBAL_AXIS_LEFT_Y].hold != AXIS_CENTER; // Process axis values @@ -607,7 +638,88 @@ fn main() -> ! { axis[GIMBAL_AXIS_LEFT_Y].value = axis[GIMBAL_AXIS_LEFT_Y].hold; } - // Generate led activity when gimbal is moved from idle position + // Update Virtual RY + let virtual_step: u16 = 5; + // Compensate value when changing direction + if buttons[BUTTON_FRONT_LEFT_UPPER].pressed + && !buttons[BUTTON_FRONT_LEFT_LOWER].pressed + && virtual_ry < AXIS_CENTER + { + virtual_ry = AXIS_CENTER + (AXIS_CENTER - virtual_ry) / 2; + } else if buttons[BUTTON_FRONT_LEFT_LOWER].pressed + && !buttons[BUTTON_FRONT_LEFT_UPPER].pressed + && virtual_ry > AXIS_CENTER + { + virtual_ry = AXIS_CENTER - (virtual_ry - AXIS_CENTER) / 2; + } + // Move virtual axis + if buttons[BUTTON_FRONT_LEFT_UPPER].pressed + && !buttons[BUTTON_FRONT_LEFT_LOWER].pressed + && virtual_ry < ADC_MAX - virtual_step + { + virtual_ry = virtual_ry + virtual_step; + usb_activity = true; + } else if buttons[BUTTON_FRONT_LEFT_LOWER].pressed + && !buttons[BUTTON_FRONT_LEFT_UPPER].pressed + && virtual_ry > ADC_MIN + virtual_step + { + virtual_ry = virtual_ry - virtual_step; + usb_activity = true; + } else if (virtual_ry != AXIS_CENTER + && !buttons[BUTTON_FRONT_LEFT_UPPER].pressed + && !buttons[BUTTON_FRONT_LEFT_LOWER].pressed) + || (buttons[BUTTON_FRONT_LEFT_UPPER].pressed + && buttons[BUTTON_FRONT_LEFT_LOWER].pressed) + { + if virtual_ry < AXIS_CENTER + virtual_step { + virtual_ry = virtual_ry + virtual_step; + } else if virtual_ry > AXIS_CENTER - virtual_step { + virtual_ry = virtual_ry - virtual_step; + } + usb_activity = true; + } + + // Update Virtual RZ + // Compensate value when changing direction + if buttons[BUTTON_FRONT_RIGHT_EXTRA].pressed + && !buttons[BUTTON_FRONT_LEFT_EXTRA].pressed + && virtual_rz < AXIS_CENTER + { + virtual_rz = AXIS_CENTER + (AXIS_CENTER - virtual_rz) / 2; + } else if buttons[BUTTON_FRONT_LEFT_EXTRA].pressed + && !buttons[BUTTON_FRONT_RIGHT_EXTRA].pressed + && virtual_rz > AXIS_CENTER + { + virtual_rz = AXIS_CENTER - (virtual_rz - AXIS_CENTER) / 2; + } + // Move virtual axis + if buttons[BUTTON_FRONT_RIGHT_EXTRA].pressed + && !buttons[BUTTON_FRONT_LEFT_EXTRA].pressed + && virtual_rz < ADC_MAX - virtual_step + { + virtual_rz = virtual_rz + virtual_step; + usb_activity = true; + } else if buttons[BUTTON_FRONT_LEFT_EXTRA].pressed + && !buttons[BUTTON_FRONT_RIGHT_EXTRA].pressed + && virtual_rz > ADC_MIN + virtual_step + { + virtual_rz = virtual_rz - virtual_step; + usb_activity = true; + } else if (virtual_rz != AXIS_CENTER + && !buttons[BUTTON_FRONT_RIGHT_EXTRA].pressed + && !buttons[BUTTON_FRONT_LEFT_EXTRA].pressed) + || (buttons[BUTTON_FRONT_RIGHT_EXTRA].pressed + && buttons[BUTTON_FRONT_LEFT_EXTRA].pressed) + { + if virtual_rz < AXIS_CENTER + virtual_step { + virtual_rz = virtual_rz + virtual_step; + } else if virtual_rz > AXIS_CENTER - virtual_step { + virtual_rz = virtual_rz - virtual_step; + } + usb_activity = true; + } + + // Indicate activity when gimbal is moved from idle position for item in axis.iter_mut() { if item.value != item.previous_value { usb_activity = true; @@ -615,31 +727,17 @@ 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; - } - } + // Indicate activity when a button is pressed + for (index, key) in buttons.iter_mut().enumerate() { + update_button_press_type(key, (timer.get_counter().ticks() / 1000) as u32); - // 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; - key.usb_changed_to_pressed = key.pressed; - usb_activity = true; } // Set throttle_hold_value 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,11 +745,16 @@ 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; axis[GIMBAL_AXIS_LEFT_Y].hold_pending = true; + } else if key.pressed != key.previous_pressed && key.pressed && index == VT_BUTTON { + vt_enable = !vt_enable; + } + + if key.usb_changed { + usb_activity = true; } key.previous_pressed = key.pressed; } @@ -667,10 +770,29 @@ fn main() -> ! { // Dont send USB HID joystick report if there is no activity // This is to avoid preventing the computer from going to sleep if usb_update_count_down.wait().is_ok() && usb_activity { - match usb_hid_joystick - .device() - .write_report(&get_joystick_report(&mut buttons, &mut axis)) - { + match usb_hid_joystick.device().write_report(&get_joystick_report( + &mut buttons, + &mut axis, + calculate_axis_value( + virtual_ry, + ADC_MIN, + ADC_MAX, + AXIS_CENTER, + (0, 0, 0), + true, + &expo_lut_virtual, + ), + calculate_axis_value( + virtual_rz, + ADC_MIN, + ADC_MAX, + AXIS_CENTER, + (0, 0, 0), + true, + &expo_lut_virtual, + ), + &vt_enable, + )) { Err(UsbHidError::WouldBlock) => {} Ok(_) => {} Err(e) => { @@ -683,6 +805,60 @@ fn main() -> ! { } } +fn update_button_press_type(button: &mut Button, current_time: u32) { + const LONG_PRESS_THRESHOLD: u32 = 200; + const USB_MIN_HOLD_MS: u32 = 50; + + // Pressing button + if button.pressed && !button.previous_pressed { + button.press_start_time = current_time; + button.long_press_handled = false; + } + + // While held: trigger long press if applicable + if button.pressed && button.enable_long_press && !button.long_press_handled { + if current_time - button.press_start_time >= LONG_PRESS_THRESHOLD { + button.active_usb_button = button.usb_button_long; + button.usb_press_start_time = current_time; + button.usb_press_active = true; + button.usb_changed = true; + button.long_press_handled = true; + } + } + + // Releasing button + if !button.pressed && button.previous_pressed { + // If long press wasn't triggered, it's a short press + if (!button.enable_long_press || !button.long_press_handled) && button.usb_button != 0 { + button.active_usb_button = button.usb_button; + button.usb_press_start_time = current_time; + button.usb_press_active = true; + button.usb_changed = true; + } + + // If long press was active, release now + if button.long_press_handled && button.usb_press_active { + button.usb_changed = true; + button.usb_press_active = false; + button.active_usb_button = 0; + } + } + + // Auto-release for short press after minimum hold time + if button.usb_press_active + && (!button.pressed + && !button.long_press_handled + && current_time - button.usb_press_start_time >= USB_MIN_HOLD_MS) + || (!button.enable_long_hold + && button.long_press_handled + && current_time - button.usb_press_start_time >= USB_MIN_HOLD_MS) + { + button.usb_changed = true; + button.usb_press_active = false; + button.active_usb_button = 0; + } +} + /// Update status LED colour /// /// Waiting for USB enumerate = flashing green @@ -699,6 +875,7 @@ fn update_status_led( usb_active: &bool, calibration_active: &bool, throttle_hold_enable: &bool, + vt_enable: &bool, ) where I: AnyPin, P: PIOExt, @@ -708,6 +885,8 @@ fn update_status_led( status_led.update(StatusMode::ActivityFlash); } else if !*usb_active { status_led.update(StatusMode::NormalFlash); + } else if *usb_active && *vt_enable { + status_led.update(StatusMode::Activity); } else if *usb_active && *throttle_hold_enable { status_led.update(StatusMode::Other); } else if *usb_active && !*throttle_hold_enable { @@ -725,132 +904,66 @@ fn update_status_led( fn get_joystick_report( matrix_keys: &mut [Button; NUMBER_OF_BUTTONS + 2], axis: &mut [GimbalAxis; 4], + virtual_ry: u16, + virtual_rz: u16, + vt_enable: &bool, ) -> JoystickReport { let x: i16 = axis_12bit_to_i16(axis[GIMBAL_AXIS_LEFT_X].value); - 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 y: i16 = axis_12bit_to_i16(axis[GIMBAL_AXIS_LEFT_Y].value); + let mut 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; + let ry: i16 = axis_12bit_to_i16(virtual_ry); + let rz: i16 = axis_12bit_to_i16(virtual_rz); + let mut slider: i16 = axis_12bit_to_i16(ADC_MIN); + let mut hat: u8 = 8; // Hat center position - // 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; + // Virtual axix control. Disables z and rx axis and using right gimbal Y axis to control + // slider axis. Values from center stick to max or min will be recalculated to min to max. + if *vt_enable { + if axis[GIMBAL_AXIS_RIGHT_X].value >= AXIS_CENTER { + slider = axis_12bit_to_i16(remap( + axis[GIMBAL_AXIS_RIGHT_X].value, + AXIS_CENTER, + ADC_MAX, + ADC_MIN, + ADC_MAX, + )); + } else { + slider = axis_12bit_to_i16( + ADC_MAX + - remap( + axis[GIMBAL_AXIS_RIGHT_X].value, + ADC_MIN, + AXIS_CENTER, + ADC_MIN, + ADC_MAX, + ), + ); } + z = 0; } // 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 - { - 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; + if key.enable_long_press { + if key.active_usb_button != 0 { + // Check if key is assigned as hat switch + if key.active_usb_button >= USB_HAT_UP && key.active_usb_button <= USB_HAT_LEFT { + hat = (key.active_usb_button as u8 - USB_HAT_UP as u8) * 2; + } else { + buttons |= 1 << (key.active_usb_button - 1); + } + } + } else { + if key.pressed && key.usb_button != 0 { + // Check if key is assigned as hat switch + if key.usb_button >= USB_HAT_UP && key.usb_button <= USB_HAT_LEFT { + hat = (key.usb_button as u8 - USB_HAT_UP as u8) * 2; + } else { + buttons |= 1 << (key.usb_button - 1); + } + } } } @@ -864,54 +977,14 @@ fn get_joystick_report( y, z, rx, - hat1, - hat2, - hat3, - hat4, + ry, + rz, + slider, + hat, buttons, } } -/// Format hat value from 5 switches to USB HID coded value and button state -/// -/// # Arguments -/// * `input` - Hat value coded as -/// bit 2-5: direction (U L R D) -/// bit 1: button state -/// 0 = not pressed -/// 1 = pressed -fn format_hat_value(input: u8) -> (u8, u8) { - const HAT_CENTER: u8 = 8; //8 or 15 (OS-dependent; usually 8) - const HAT_UP: u8 = 0; - const HAT_UP_RIGHT: u8 = 1; - const HAT_RIGHT: u8 = 2; - const HAT_DOWN_RIGHT: u8 = 3; - const HAT_DOWN: u8 = 4; - const HAT_DOWN_LEFT: u8 = 5; - const HAT_LEFT: u8 = 6; - const HAT_UP_LEFT: u8 = 7; - - let direction: u8 = match input & 0xFE { - 2 => HAT_UP, - 4 => HAT_RIGHT, - 6 => HAT_UP_RIGHT, - 8 => HAT_DOWN, - 12 => HAT_DOWN_RIGHT, - 16 => HAT_LEFT, - 24 => HAT_DOWN_LEFT, - 18 => HAT_UP_LEFT, - _ => HAT_CENTER, - }; - - // Alpine hat switch button filter - let mut button_state: u8 = 0; - if input & 0x01 == 0x01 && direction == HAT_CENTER { - button_state = 1; - } - - (direction, button_state) -} - /// Calculate value for joystick axis /// /// # Arguments diff --git a/rp2040/src/usb_joystick_device.rs b/rp2040/src/usb_joystick_device.rs index da44dc4..be6118c 100644 --- a/rp2040/src/usb_joystick_device.rs +++ b/rp2040/src/usb_joystick_device.rs @@ -63,42 +63,51 @@ 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) - // 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) + 0x05, 0x01, // Usage Page (Generic Desktop) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Application) + + // 7 signed 16-bit axes: X, Y, Z, Rx, Ry, Rz, Slider + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x33, // Usage (Rx) + 0x09, 0x34, // Usage (Ry) + 0x09, 0x35, // Usage (Rz) + 0x09, 0x36, // Usage (Slider) + 0x16, 0x00, 0x80, // Logical Minimum (-32768) + 0x26, 0xFF, 0x7F, // Logical Maximum (32767) + 0x75, 0x10, // Report Size (16) + 0x95, 0x07, // Report Count (7) + 0x81, 0x02, // Input (Data,Var,Abs) + + // 1 Hat Switch + 0x09, 0x39, // Usage (Hat switch) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x07, // Logical Maximum (7) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0x3B, 0x01, // Physical Maximum (315) + 0x65, 0x14, // Unit (Eng Rot: Degrees) + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x42, // Input (Data,Var,Abs,Null) + + // Padding for 4 bits to align to byte + 0x75, 0x04, // Report Size (4) + 0x95, 0x01, // Report Count (1) + 0x81, 0x03, // Input (Const,Var,Abs) – padding + // 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 + 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 ]; #[derive(Clone, Copy, Debug, Eq, PartialEq, Default)] @@ -107,20 +116,20 @@ 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 ry: i16, // 16bit + pub rz: i16, // 16bit + pub slider: i16, // 16bit + pub hat: u8, // 8bit pub buttons: u32, // 32bit } pub struct Joystick<'a, B: UsbBus> { - interface: Interface<'a, B, InBytes16, OutNone, ReportSingle>, + interface: Interface<'a, B, InBytes32, OutNone, ReportSingle>, } impl Joystick<'_, B> { pub fn write_report(&mut self, report: &JoystickReport) -> Result<(), UsbHidError> { - let mut data: [u8; 14] = [0; 14]; + let mut data: [u8; 19] = [0; 19]; // Did not make the packed struct work, so doing it manually data[0] = report.x as u8; @@ -131,12 +140,17 @@ 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.ry as u8; + data[9] = (report.ry >> 8) as u8; + data[10] = report.rz as u8; + data[11] = (report.rz >> 8) as u8; + data[12] = report.slider as u8; + data[13] = (report.slider >> 8) as u8; + data[14] = report.hat; + data[15] = report.buttons as u8; + data[16] = (report.buttons >> 8) as u8; + data[17] = (report.buttons >> 16) as u8; + data[18] = (report.buttons >> 24) as u8; self.interface .write_report(&data) @@ -146,7 +160,7 @@ impl Joystick<'_, B> { } impl<'a, B: UsbBus> DeviceClass<'a> for Joystick<'a, B> { - type I = Interface<'a, B, InBytes16, OutNone, ReportSingle>; + type I = Interface<'a, B, InBytes32, OutNone, ReportSingle>; fn interface(&mut self) -> &mut Self::I { &mut self.interface @@ -160,7 +174,7 @@ impl<'a, B: UsbBus> DeviceClass<'a> for Joystick<'a, B> { } pub struct JoystickConfig<'a> { - interface: InterfaceConfig<'a, InBytes16, OutNone, ReportSingle>, + interface: InterfaceConfig<'a, InBytes32, OutNone, ReportSingle>, } impl Default for JoystickConfig<'_> { @@ -181,7 +195,7 @@ impl Default for JoystickConfig<'_> { impl<'a> JoystickConfig<'a> { #[must_use] - pub fn new(interface: InterfaceConfig<'a, InBytes16, OutNone, ReportSingle>) -> Self { + pub fn new(interface: InterfaceConfig<'a, InBytes32, OutNone, ReportSingle>) -> Self { Self { interface } } }