From 8c952f26eda6c5ae57a9632a7bdbd5ec8e20f7a3 Mon Sep 17 00:00:00 2001 From: Christoffer Martinsson Date: Sat, 5 Aug 2023 13:01:01 +0200 Subject: [PATCH] Chaged to 24 HID buttons --- rp2040/src/layout.rs | 99 +++++++++++++++++-------------- rp2040/src/main.rs | 96 ++++++++++++++++-------------- rp2040/src/usb_joystick_device.rs | 19 +++--- 3 files changed, 115 insertions(+), 99 deletions(-) diff --git a/rp2040/src/layout.rs b/rp2040/src/layout.rs index 2d5dbd1..ffd23db 100644 --- a/rp2040/src/layout.rs +++ b/rp2040/src/layout.rs @@ -1,10 +1,10 @@ -//! Project: CMtec CMDR Keyboard 42 -//! Date: 2023-07-01 +//! Project: CMtec CMDR joystick 24 +//! Date: 2023-08-01 //! Author: Christoffer Martinsson //! Email: cm@cmtec.se //! License: Please refer to LICENSE in root directory -use crate::NUMBER_OF_KEYS; +use crate::NUMBER_OF_BUTTONS; #[derive(Debug, PartialEq, Copy, Clone)] pub enum ButtonType { @@ -24,31 +24,35 @@ pub enum ButtonType { B14 = 13, B15 = 14, B16 = 15, - FnL = 16, - FnR = 17, - ModeL = 18, - ModeR = 19, - Hat1U = 20, - Hat1R = 21, - Hat1D = 22, - Hat1L = 23, - Hat1B = 24, - Hat2U = 25, - Hat2R = 26, - Hat2D = 27, - Hat2L = 28, - Hat2B = 29, - Hat3U = 30, - Hat3R = 31, - Hat3D = 32, - Hat3L = 33, - Hat3B = 34, - Hat4U = 35, - Hat4R = 36, - Hat4D = 37, - Hat4L = 38, - Hat4B = 39, - NoEventIndicated = 40, + B17 = 16, + B18 = 17, + B19 = 18, + B20 = 19, + FnL = 20, + FnR = 21, + ModeL = 22, + ModeR = 23, + Hat1U = 24, + Hat1R = 25, + Hat1D = 26, + Hat1L = 27, + Hat1B = 28, + Hat2U = 29, + Hat2R = 30, + Hat2D = 31, + Hat2L = 32, + Hat2B = 33, + Hat3U = 34, + Hat3R = 35, + Hat3D = 36, + Hat3L = 37, + Hat3B = 38, + Hat4U = 39, + Hat4R = 40, + Hat4D = 41, + Hat4L = 42, + Hat4B = 43, + NoEventIndicated = 44, } // Button index map: @@ -56,16 +60,19 @@ pub enum ButtonType { // | 0 | 1 | | 2 | 3 | (4) // -------------------------------------------------------------- // | | 5 | 6 | 7 | | 12 | 11 | 10 | | -// | | (9) (14) +// | | // | | 8 | | 13 | | +// | | 9 | | 14 | | // | X1/Y1 X2/Y2 | // | | 16 | | 21 | | // | | 17 | 15 | 18 || 22 | 20 | 23 | | // | | 19 | | 24 | | // -------------------------------------------------------------- // -/// Button map to HID key (three Function layers) -pub const MAP: [[ButtonType; NUMBER_OF_KEYS]; 4] = [ +/// Button map to HID key (four function layers) +/// Please make sure to set FnL, FnR, ModeL and ModeR at the same position for all layers +/// alt. only set these at function layer 0 and set NoEventIndicated in layer 1-3. +pub const MAP: [[ButtonType; NUMBER_OF_BUTTONS]; 4] = [ [ // Function layer 0 // HID Key // Button Index @@ -74,17 +81,17 @@ pub const MAP: [[ButtonType; NUMBER_OF_KEYS]; 4] = [ ButtonType::B1, // 1 ButtonType::B5, // 2 ButtonType::FnR, // 3 - ButtonType::NoEventIndicated, // 4 + ButtonType::NoEventIndicated, // 4 Not connected to any button ButtonType::B2, // 5 ButtonType::B3, // 6 ButtonType::ModeL, // 7 ButtonType::B4, // 8 - ButtonType::NoEventIndicated, // 9 + ButtonType::B17, // 9 ButtonType::B6, // 10 ButtonType::B7, // 11 ButtonType::ModeR, // 12 ButtonType::B8, // 13 - ButtonType::NoEventIndicated, // 14 + ButtonType::B18, // 14 ButtonType::Hat1B, // 15 ButtonType::Hat1U, // 16 ButtonType::Hat1L, // 17 @@ -97,24 +104,24 @@ pub const MAP: [[ButtonType; NUMBER_OF_KEYS]; 4] = [ ButtonType::Hat2D, // 24 ], [ - // Function layer left + // Function layer 1 (left Fn button pressed) // HID Key // Button Index // ----------------------------------------- ButtonType::FnL, // 0 ButtonType::B9, // 1 ButtonType::B5, // 2 ButtonType::FnR, // 3 - ButtonType::NoEventIndicated, // 4 + ButtonType::NoEventIndicated, // 4 Not connected to any button ButtonType::B10, // 5 ButtonType::B11, // 6 ButtonType::ModeL, // 7 ButtonType::B12, // 8 - ButtonType::NoEventIndicated, // 9 + ButtonType::B19, // 9 ButtonType::B6, // 10 ButtonType::B7, // 11 ButtonType::ModeR, // 12 ButtonType::B8, // 13 - ButtonType::NoEventIndicated, // 14 + ButtonType::B18, // 14 ButtonType::Hat3B, // 15 ButtonType::Hat3U, // 16 ButtonType::Hat3L, // 17 @@ -127,24 +134,24 @@ pub const MAP: [[ButtonType; NUMBER_OF_KEYS]; 4] = [ ButtonType::Hat2D, // 24 ], [ - // Function layer right + // Function layer 2 (right Fn button pressed) // HID Key // Button Index // ----------------------------------------- ButtonType::FnL, // 0 ButtonType::B1, // 1 ButtonType::B13, // 2 ButtonType::FnR, // 3 - ButtonType::NoEventIndicated, // 4 + ButtonType::NoEventIndicated, // 4 Not connected to any button ButtonType::B2, // 5 ButtonType::B3, // 6 ButtonType::ModeL, // 7 ButtonType::B4, // 8 - ButtonType::NoEventIndicated, // 9 + ButtonType::B17, // 9 ButtonType::B14, // 10 ButtonType::B15, // 11 ButtonType::ModeR, // 12 ButtonType::B16, // 13 - ButtonType::NoEventIndicated, // 14 + ButtonType::B20, // 14 ButtonType::Hat1B, // 15 ButtonType::Hat1U, // 16 ButtonType::Hat1L, // 17 @@ -157,24 +164,24 @@ pub const MAP: [[ButtonType; NUMBER_OF_KEYS]; 4] = [ ButtonType::Hat4D, // 24 ], [ - // Function layer left + right + // Function layer 3 (left + right Fn button pressed) // HID Key // Button Index // ----------------------------------------- ButtonType::FnL, // 0 ButtonType::B9, // 1 ButtonType::B13, // 2 ButtonType::FnR, // 3 - ButtonType::NoEventIndicated, // 4 + ButtonType::NoEventIndicated, // 4 Not connected to any button ButtonType::B10, // 5 ButtonType::B11, // 6 ButtonType::ModeL, // 7 ButtonType::B12, // 8 - ButtonType::NoEventIndicated, // 9 + ButtonType::B19, // 9 ButtonType::B14, // 10 ButtonType::B15, // 11 ButtonType::ModeR, // 12 ButtonType::B16, // 13 - ButtonType::NoEventIndicated, // 14 + ButtonType::B20, // 14 ButtonType::Hat3B, // 15 ButtonType::Hat3U, // 16 ButtonType::Hat3L, // 17 diff --git a/rp2040/src/main.rs b/rp2040/src/main.rs index dc83e7e..527a75f 100644 --- a/rp2040/src/main.rs +++ b/rp2040/src/main.rs @@ -1,5 +1,5 @@ -//! Project: CMtec CMDR Keyboard 42 -//! Date: 2023-07-01 +//! Project: CMtec CMDR joystick 24 +//! Date: 2023-08-01 //! Author: Christoffer Martinsson //! Email: cm@cmtec.se //! License: Please refer to LICENSE in root directory @@ -46,9 +46,9 @@ use waveshare_rp2040_zero::{ }; // Public constants -pub const KEY_ROWS: usize = 5; -pub const KEY_COLS: usize = 5; -pub const NUMBER_OF_KEYS: usize = KEY_ROWS * KEY_COLS; +pub const BUTTON_ROWS: usize = 5; +pub const BUTTON_COLS: usize = 5; +pub const NUMBER_OF_BUTTONS: usize = BUTTON_ROWS * BUTTON_COLS; pub const AXIS_MIN: u16 = 0; pub const AXIS_MAX: u16 = 4095; @@ -67,7 +67,7 @@ pub const SENSITIVITY: i32 = (0.01 * ((1 << I32_FRAC_BITS) as f32)) as i32; // Public types #[derive(Copy, Clone, Default)] -pub struct JoystickButton { +pub struct Button { pub pressed: bool, pub previous_pressed: bool, pub fn_mode: u8, @@ -138,13 +138,15 @@ fn main() -> ! { let mut adc = Adc::new(pac.ADC, &mut pac.RESETS); // Configure ADC input pins + // Have not figured out hov to store the adc pins in an array yet + // TODO: Find a way to store adc pins in an array let mut adc_pin_left_x = pins.gp26.into_floating_input(); let mut adc_pin_left_y = pins.gp27.into_floating_input(); let mut adc_pin_right_x = pins.gp28.into_floating_input(); let mut adc_pin_right_y = pins.gp29.into_floating_input(); // Setting up array with pins connected to button rows - let button_matrix_row_pins: &[&dyn InputPin; KEY_ROWS] = &[ + let button_matrix_row_pins: &[&dyn InputPin; BUTTON_ROWS] = &[ &pins.gp9.into_pull_up_input(), &pins.gp10.into_pull_up_input(), &pins.gp11.into_pull_up_input(), @@ -153,7 +155,7 @@ fn main() -> ! { ]; // Setting up array with pins connected to button columns - let button_matrix_col_pins: &mut [&mut dyn OutputPin; KEY_COLS] = &mut [ + let button_matrix_col_pins: &mut [&mut dyn OutputPin; BUTTON_COLS] = &mut [ &mut pins.gp4.into_push_pull_output(), &mut pins.gp5.into_push_pull_output(), &mut pins.gp6.into_push_pull_output(), @@ -161,10 +163,13 @@ fn main() -> ! { &mut pins.gp8.into_push_pull_output(), ]; - // Create button matrix object that scans all the PCB buttons - let mut button_matrix: ButtonMatrix = + // Create button matrix object that scans all buttons + let mut button_matrix: ButtonMatrix = ButtonMatrix::new(button_matrix_row_pins, button_matrix_col_pins, 5); + // Initialize button matrix + button_matrix.init_pins(); + // Configure USB let usb_bus = UsbBusAllocator::new(waveshare_rp2040_zero::hal::usb::UsbBus::new( pac.USBCTRL_REGS, @@ -193,9 +198,6 @@ fn main() -> ! { clocks.peripheral_clock.freq(), ); - // Create joystick button array - let mut buttons: [JoystickButton; NUMBER_OF_KEYS] = [JoystickButton::default(); NUMBER_OF_KEYS]; - // Create timers/delays let timer = Timer::new(pac.TIMER, &mut pac.RESETS); let mut delay = Delay::new(core.SYST, clocks.system_clock.freq().to_Hz()); @@ -203,8 +205,8 @@ fn main() -> ! { let mut usb_hid_report_count_down = timer.count_down(); usb_hid_report_count_down.start(10.millis()); - let mut usb_tick_count_down = timer.count_down(); - usb_tick_count_down.start(1.millis()); + let mut scan_count_down = timer.count_down(); + scan_count_down.start(1.millis()); let mut status_led_count_down = timer.count_down(); status_led_count_down.start(250.millis()); @@ -212,8 +214,9 @@ fn main() -> ! { // Create variable to track modes let mut fn_mode: u8 = 0; - // Create joystick axis array + // Create joystick button/axis array let mut axis: [GimbalAxis; NBR_OF_GIMBAL_AXIS] = [Default::default(); NBR_OF_GIMBAL_AXIS]; + let mut buttons: [Button; NUMBER_OF_BUTTONS] = [Button::default(); NUMBER_OF_BUTTONS]; // Set up left gimbal Y axis as full range without return to center spring axis[GIMBAL_AXIS_LEFT_Y].idle_value = AXIS_MIN; @@ -221,6 +224,7 @@ fn main() -> ! { axis[GIMBAL_AXIS_LEFT_Y].expo = 0.0; // Create dynamic smoother array for gimbal axis + // TODO: Find a way to store dynamic smoother in the axis struct let mut smoother: [DynamicSmootherEcoI32; NBR_OF_GIMBAL_AXIS] = [ DynamicSmootherEcoI32::new(BASE_FREQ, SAMPLE_FREQ, SENSITIVITY), DynamicSmootherEcoI32::new(BASE_FREQ, SAMPLE_FREQ, SENSITIVITY), @@ -228,9 +232,6 @@ fn main() -> ! { DynamicSmootherEcoI32::new(BASE_FREQ, SAMPLE_FREQ, SENSITIVITY), ]; - // Initialize button matrix - button_matrix.init_pins(); - // Scan matrix to get initial state for _ in 0..10 { button_matrix.scan_matrix(&mut delay); @@ -261,7 +262,7 @@ fn main() -> ! { match usb_hid_joystick.device().write_report(&get_joystick_report( &mut buttons, &mut axis, - fn_mode, + &fn_mode, )) { Err(UsbHidError::WouldBlock) => {} Ok(_) => {} @@ -272,16 +273,17 @@ fn main() -> ! { }; } - if usb_tick_count_down.wait().is_ok() { + if scan_count_down.wait().is_ok() { button_matrix.scan_matrix(&mut delay); - // Read ADC values and smooth them + // Have not figured out hov to store the adc pins in an array yet + // so we have to read them one by one + // TODO: Find a way to store adc pins in an array smoother[GIMBAL_AXIS_LEFT_X].tick(adc.read(&mut adc_pin_left_x).unwrap()); smoother[GIMBAL_AXIS_LEFT_Y].tick(adc.read(&mut adc_pin_left_y).unwrap()); smoother[GIMBAL_AXIS_RIGHT_X].tick(adc.read(&mut adc_pin_right_x).unwrap()); smoother[GIMBAL_AXIS_RIGHT_Y].tick(adc.read(&mut adc_pin_right_y).unwrap()); - // Update axis values for (index, item) in axis.iter_mut().enumerate() { item.value = calculate_axis_value( smoother[index].value() as u16, @@ -301,8 +303,7 @@ fn main() -> ! { /// Update status LED colour based on function layer and capslock /// /// Normal = green (NORMAL) -/// GUI lock = blue (GUI LOCK) -/// Capslock active = flashing red (WARNING) +/// Left Alt mode = blue (GUI LOCK) /// Error = steady red (ERROR) /// /// # Arguments @@ -328,7 +329,7 @@ where /// # Arguments /// /// * `pressed_keys` - Array of pressed keys -fn get_mode(pressed_keys: [bool; NUMBER_OF_KEYS]) -> u8 { +fn get_mode(pressed_keys: [bool; NUMBER_OF_BUTTONS]) -> u8 { // Check how many Fn keys are pressed let mut fn_mode: u8 = 0; let mut fn_l_active: bool = false; @@ -381,9 +382,9 @@ fn get_mode(pressed_keys: [bool; NUMBER_OF_KEYS]) -> u8 { /// * `alt_l_mode` - Is left alt mode active /// * `alt_r_mode` - Is right alt mode active fn get_joystick_report( - matrix_keys: &mut [JoystickButton; NUMBER_OF_KEYS], + matrix_keys: &mut [Button; NUMBER_OF_BUTTONS], axis: &mut [GimbalAxis; 4], - fn_mode: u8, + fn_mode: &u8, ) -> JoystickReport { let mut x: u16 = axis[GIMBAL_AXIS_RIGHT_X].value; let mut y: u16 = axis[GIMBAL_AXIS_RIGHT_Y].value; @@ -392,14 +393,15 @@ fn get_joystick_report( let mut ry: u16 = AXIS_CENTER; let mut rz: u16 = axis[GIMBAL_AXIS_LEFT_Y].value; - // Update Fn mode for all axis + // Update Fn mode for all axis that are in idle position + // This is to avoid the Fn mode switching when moving the gimbal for item in axis.iter_mut() { if item.value == item.idle_value { item.fn_mode = fn_mode & 0x0F; } } - // Left Alt mode active + // Left Alt mode active (bit 4) // Full range of left gimbal gives half range of joystick axis (center to max) // Left Fn mode = reversed range (center to min) if fn_mode & 0x10 == 0x10 @@ -424,7 +426,7 @@ fn get_joystick_report( ); } - // Right Alt mode active + // Right Alt mode active (bit 5) // Right gimbal control third joystick axis when right Fn mode is active if fn_mode & 0x20 == 0x20 && (axis[GIMBAL_AXIS_RIGHT_X].fn_mode == 2 || axis[GIMBAL_AXIS_RIGHT_X].fn_mode == 3) @@ -439,12 +441,12 @@ fn get_joystick_report( ry = axis[GIMBAL_AXIS_RIGHT_Y].value; } - // Set fn mode for pressed button + // Set fn mode for all keys taht are in idle position + // This is to avoid the Fn mode switching when using a button for key in matrix_keys.iter_mut() { - if key.pressed != key.previous_pressed && key.pressed { + if !key.pressed { key.fn_mode = fn_mode & 0x0F; } - key.previous_pressed = key.pressed; } // Generate array for all four hat switches with following structure: @@ -458,8 +460,10 @@ fn get_joystick_report( let mut hats: [u8; 4] = [0; 4]; for (index, key) in matrix_keys.iter_mut().enumerate() { if key.pressed - && layout::MAP[fn_mode as usize][index] as usize >= layout::ButtonType::Hat1U as usize - && layout::MAP[fn_mode as usize][index] as usize <= layout::ButtonType::Hat4B as usize + && layout::MAP[(fn_mode & 0x0F) as usize][index] as usize + >= layout::ButtonType::Hat1U as usize + && layout::MAP[(fn_mode & 0x0F) as usize][index] as usize + <= layout::ButtonType::Hat4B as usize { hats[(index - layout::ButtonType::Hat1U as usize) / 4] |= 1 << ((index - layout::ButtonType::Hat1U as usize) @@ -473,19 +477,21 @@ fn get_joystick_report( let (hat3, hat_button3) = format_hat_value(hats[2]); let (hat4, hat_button4) = format_hat_value(hats[3]); - // Update button state for joystick button 17-20 according to hat button 1-4 - let mut buttons: u32 = (hat_button1 as u32) << 16 - | ((hat_button2 as u32) << 17) - | ((hat_button3 as u32) << 18) - | ((hat_button4 as u32) << 19); + // Update button state for joystick button 21-24 according to hat button 1-4 + let mut buttons: u32 = (hat_button1 as u32) << 20 + | ((hat_button2 as u32) << 21) + | ((hat_button3 as u32) << 22) + | ((hat_button4 as u32) << 23); - // Update button state for joystick button 1-16 + // Update button state for joystick button 1-20 for (index, key) in matrix_keys.iter_mut().enumerate() { if key.pressed - && layout::MAP[fn_mode as usize][index] as usize >= layout::ButtonType::B1 as usize - && layout::MAP[fn_mode as usize][index] as usize <= layout::ButtonType::B16 as usize + && layout::MAP[(fn_mode & 0x0F) as usize][index] as usize + >= layout::ButtonType::B1 as usize + && layout::MAP[(fn_mode & 0x0F) as usize][index] as usize + <= layout::ButtonType::B20 as usize { - buttons |= 1 << layout::MAP[fn_mode as usize][index] as usize; + buttons |= 1 << layout::MAP[(fn_mode & 0x0F) as usize][index] as usize; } } diff --git a/rp2040/src/usb_joystick_device.rs b/rp2040/src/usb_joystick_device.rs index 2fd20e0..1d81a58 100644 --- a/rp2040/src/usb_joystick_device.rs +++ b/rp2040/src/usb_joystick_device.rs @@ -1,4 +1,9 @@ -//!HID joystick +//! Project: CMtec CMDR joystick 24 +//! Date: 2023-08-01 +//! Author: Christoffer Martinsson +//! Email: cm@cmtec.se +//! License: Please refer to LICENSE in root directory + use core::default::Default; use fugit::ExtU32; use usb_device::bus::UsbBus; @@ -63,7 +68,7 @@ impl Try for Result { } // Based on example device from https://github.com/dlkj/usbd-human-interface-device/blob/main/src/device/joystick.rs -// Updated to 6pc 12bit axis, 20pc buttons and 4pc hat switches +// Updated to 6pc 12bit axis, 24pc buttons and 4pc hat switches #[rustfmt::skip] pub const JOYSTICK_DESCRIPTOR: &[u8] = &[ 0x05, 0x01, // Usage Page (Generic Desktop) @@ -85,15 +90,12 @@ pub const JOYSTICK_DESCRIPTOR: &[u8] = &[ 0xc0, // End Collection 0x05, 0x09, // Usage Page (Button) 0x19, 0x01, // Usage Minimum (1) - 0x29, 0x14, // Usage Maximum (20) + 0x29, 0x18, // Usage Maximum (24) 0x15, 0x00, // Logical Minimum (0) 0x25, 0x01, // Logical Maximum (1) 0x75, 0x01, // Report Size (1) - 0x95, 0x14, // Report Count (20) + 0x95, 0x18, // Report Count (24) 0x81, 0x02, // Input (Data, Variable, Absolute) - 0x75, 0x01, // Report Size (1) PADDING - 0x95, 0x04, // Report Count (4) PADDING - 0x81, 0x03, // Input (Const, Variable, Absolute) PADDING 0x15, 0x00, // Logical Minimum (0) 0x25, 0x07, // Logical Maximum (7) 0x35, 0x00, // Physical Minimum (0) @@ -118,7 +120,7 @@ pub struct JoystickReport { pub rx: u16, // 12bit pub ry: u16, // 12bit pub rz: u16, // 12bit - pub buttons: u32, // 20bit + pub buttons: u32, // 24bit pub hat1: u8, // 4bit pub hat2: u8, // 4bit pub hat3: u8, // 4bit @@ -134,6 +136,7 @@ impl<'a, B: UsbBus> Joystick<'a, B> { let mut data: [u8; 14] = [0; 14]; // Did not make the packed struct work, so doing it manually + // TODO: make this work with packed struct data[0] = report.x as u8; data[1] = ((report.x >> 8) as u8) | ((report.y << 4) as u8); data[2] = (report.y >> 4) as u8;