Code refactor. Removed layout file. Changed back to 25 button descriptor. Added toggle switch mode.
This commit is contained in:
parent
748ca8aa94
commit
197b562a01
@ -1,347 +0,0 @@
|
|||||||
//! 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_BUTTONS;
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
|
|
||||||
pub enum ConfigButton {
|
|
||||||
CONF = 0,
|
|
||||||
BOOT = 1,
|
|
||||||
CAL = 2,
|
|
||||||
ELRS = 3,
|
|
||||||
USB = 4,
|
|
||||||
NoEventIndicated = 5,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
|
|
||||||
pub enum ElrsButton {
|
|
||||||
CH1 = 0,
|
|
||||||
CH2 = 1,
|
|
||||||
CH3 = 2,
|
|
||||||
CH4 = 3,
|
|
||||||
CH5 = 4, // AUX1/ARM
|
|
||||||
CH6 = 5,
|
|
||||||
CH7 = 6,
|
|
||||||
CH8 = 7,
|
|
||||||
CH9 = 8,
|
|
||||||
CH10 = 9,
|
|
||||||
CH11 = 10,
|
|
||||||
CH12 = 11,
|
|
||||||
CH5ON = 12,
|
|
||||||
CH6ON = 13,
|
|
||||||
CH7ON = 14,
|
|
||||||
CH8ON = 15,
|
|
||||||
CH9ON = 16,
|
|
||||||
CH10ON = 17,
|
|
||||||
CH11ON = 18,
|
|
||||||
CH12ON = 19,
|
|
||||||
CH5OFF = 20,
|
|
||||||
CH6OFF = 21,
|
|
||||||
CH7OFF = 22,
|
|
||||||
CH8OFF = 23,
|
|
||||||
CH9OFF = 24,
|
|
||||||
CH10OFF = 25,
|
|
||||||
CH11OFF = 26,
|
|
||||||
CH12OFF = 27,
|
|
||||||
CH1P = 28,
|
|
||||||
CH2P = 29,
|
|
||||||
CH3P = 30,
|
|
||||||
CH4P = 31,
|
|
||||||
CH1M = 32,
|
|
||||||
CH2M = 33,
|
|
||||||
CH3M = 34,
|
|
||||||
CH4M = 35,
|
|
||||||
CH12Z = 36,
|
|
||||||
CH34Z = 37,
|
|
||||||
NoEventIndicated = 38,
|
|
||||||
}
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[derive(Debug, PartialEq, PartialOrd, Copy, Clone)]
|
|
||||||
pub enum HidButton {
|
|
||||||
B1 = 0,
|
|
||||||
B2 = 1,
|
|
||||||
B3 = 2,
|
|
||||||
B4 = 3,
|
|
||||||
B5 = 4,
|
|
||||||
B6 = 5,
|
|
||||||
B7 = 6,
|
|
||||||
B8 = 7,
|
|
||||||
B9 = 8,
|
|
||||||
B10 = 9,
|
|
||||||
B11 = 10,
|
|
||||||
B12 = 11,
|
|
||||||
B13 = 12,
|
|
||||||
B14 = 13,
|
|
||||||
B15 = 14,
|
|
||||||
B16 = 15,
|
|
||||||
B17 = 16,
|
|
||||||
B18 = 17,
|
|
||||||
B19 = 18,
|
|
||||||
B20 = 19,
|
|
||||||
B21 = 20,
|
|
||||||
B22 = 21,
|
|
||||||
B23 = 22,
|
|
||||||
B24 = 23,
|
|
||||||
B25 = 24,
|
|
||||||
B26 = 25,
|
|
||||||
B27 = 26,
|
|
||||||
B28 = 27,
|
|
||||||
Fn = 28,
|
|
||||||
ModeL = 29,
|
|
||||||
ModeR = 30,
|
|
||||||
H1U = 31,
|
|
||||||
H1R = 32,
|
|
||||||
H1D = 33,
|
|
||||||
H1L = 34,
|
|
||||||
H1B = 35,
|
|
||||||
H2U = 36,
|
|
||||||
H2R = 37,
|
|
||||||
H2D = 38,
|
|
||||||
H2L = 39,
|
|
||||||
H2B = 40,
|
|
||||||
H3U = 41,
|
|
||||||
H3R = 42,
|
|
||||||
H3D = 43,
|
|
||||||
H3L = 44,
|
|
||||||
H3B = 45,
|
|
||||||
H4U = 46,
|
|
||||||
H4R = 47,
|
|
||||||
H4D = 48,
|
|
||||||
H4L = 49,
|
|
||||||
H4B = 50,
|
|
||||||
NoEventIndicated = 51,
|
|
||||||
}
|
|
||||||
#[warn(dead_code)]
|
|
||||||
// Button index map:
|
|
||||||
// --------------------------------------------------------------
|
|
||||||
// | 0 L| 1 U| | 2 | | 3 L| 4 U|
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
// | | 5 | 6 | 7 | | 12 | 11 | 10 | |
|
|
||||||
// | |
|
|
||||||
// | | 8 | | 13 | |
|
|
||||||
// | | 9 | | 14 | |
|
|
||||||
// | X1/Y1 X2/Y2 |
|
|
||||||
// | | 16 | | 21 | |
|
|
||||||
// | | 17 | 15 | 18 | | 22 | 20 | 23 | |
|
|
||||||
// | | 19 | | 24 | |
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
//
|
|
||||||
/// Button map to HID key (four function layers)
|
|
||||||
/// Please make sure to set Fn, 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.
|
|
||||||
/// Hat button 1-4 = HID B28-B32.
|
|
||||||
pub const HID_MAP: [[HidButton; NUMBER_OF_BUTTONS]; 4] = [
|
|
||||||
[
|
|
||||||
// Function layer 0
|
|
||||||
// HID Key // Button Index
|
|
||||||
// -----------------------------------------
|
|
||||||
HidButton::B23, // 0
|
|
||||||
HidButton::B1, // 1
|
|
||||||
HidButton::B27, // 2
|
|
||||||
HidButton::B21, // 3
|
|
||||||
HidButton::B6, // 4
|
|
||||||
HidButton::B2, // 5
|
|
||||||
HidButton::B3, // 6
|
|
||||||
HidButton::ModeL, // 7
|
|
||||||
HidButton::B4, // 8
|
|
||||||
HidButton::B5, // 9
|
|
||||||
HidButton::B7, // 10
|
|
||||||
HidButton::B8, // 11
|
|
||||||
HidButton::Fn, // 12
|
|
||||||
HidButton::B9, // 13
|
|
||||||
HidButton::B10, // 14
|
|
||||||
HidButton::H1B, // 15
|
|
||||||
HidButton::H1U, // 16
|
|
||||||
HidButton::H1R, // 17
|
|
||||||
HidButton::H1D, // 18
|
|
||||||
HidButton::H1L, // 19
|
|
||||||
HidButton::H2B, // 20
|
|
||||||
HidButton::H2U, // 21
|
|
||||||
HidButton::H2R, // 22
|
|
||||||
HidButton::H2D, // 23
|
|
||||||
HidButton::H2L, // 24
|
|
||||||
],
|
|
||||||
[
|
|
||||||
// Function layer 1 (Fn button pressed)
|
|
||||||
// HID Key // Button Index
|
|
||||||
// -----------------------------------------
|
|
||||||
HidButton::B24, // 0
|
|
||||||
HidButton::B16, // 1
|
|
||||||
HidButton::B28, // 2
|
|
||||||
HidButton::B11, // 3
|
|
||||||
HidButton::B22, // 4
|
|
||||||
HidButton::B12, // 5
|
|
||||||
HidButton::B13, // 6
|
|
||||||
HidButton::ModeL, // 7
|
|
||||||
HidButton::B14, // 8
|
|
||||||
HidButton::B15, // 9
|
|
||||||
HidButton::B17, // 10
|
|
||||||
HidButton::B18, // 11
|
|
||||||
HidButton::Fn, // 12
|
|
||||||
HidButton::B19, // 13
|
|
||||||
HidButton::B20, // 14
|
|
||||||
HidButton::H3B, // 15
|
|
||||||
HidButton::H3U, // 16
|
|
||||||
HidButton::H3R, // 17
|
|
||||||
HidButton::H3D, // 18
|
|
||||||
HidButton::H3L, // 19
|
|
||||||
HidButton::H4B, // 20
|
|
||||||
HidButton::H4U, // 21
|
|
||||||
HidButton::H4R, // 22
|
|
||||||
HidButton::H4D, // 23
|
|
||||||
HidButton::H4L, // 24
|
|
||||||
],
|
|
||||||
[
|
|
||||||
// Function layer 2 (Mode R selected)
|
|
||||||
// HID Key // Button Index
|
|
||||||
// -----------------------------------------
|
|
||||||
HidButton::Fn, // 0
|
|
||||||
HidButton::H3U, // 1
|
|
||||||
HidButton::NoEventIndicated, // 2
|
|
||||||
HidButton::B21, // 3
|
|
||||||
HidButton::B6, // 4
|
|
||||||
HidButton::B2, // 5
|
|
||||||
HidButton::B3, // 6
|
|
||||||
HidButton::ModeL, // 7
|
|
||||||
HidButton::B4, // 8
|
|
||||||
HidButton::B5, // 9
|
|
||||||
HidButton::B7, // 10
|
|
||||||
HidButton::B8, // 11
|
|
||||||
HidButton::ModeR, // 12
|
|
||||||
HidButton::B9, // 13
|
|
||||||
HidButton::B10, // 14
|
|
||||||
HidButton::H1B, // 15
|
|
||||||
HidButton::H1U, // 16
|
|
||||||
HidButton::H1R, // 17
|
|
||||||
HidButton::H1D, // 18
|
|
||||||
HidButton::H1L, // 19
|
|
||||||
HidButton::H2B, // 20
|
|
||||||
HidButton::H2U, // 21
|
|
||||||
HidButton::H2R, // 22
|
|
||||||
HidButton::H2D, // 23
|
|
||||||
HidButton::H2L, // 24
|
|
||||||
],
|
|
||||||
[
|
|
||||||
// Function layer 3 (Mode R selected, Fn button pressed)
|
|
||||||
// HID Key // Button Index
|
|
||||||
// -----------------------------------------
|
|
||||||
HidButton::Fn, // 0
|
|
||||||
HidButton::H3D, // 1
|
|
||||||
HidButton::NoEventIndicated, // 2
|
|
||||||
HidButton::B11, // 3
|
|
||||||
HidButton::B16, // 4
|
|
||||||
HidButton::B12, // 5
|
|
||||||
HidButton::B13, // 6
|
|
||||||
HidButton::ModeL, // 7
|
|
||||||
HidButton::B14, // 8
|
|
||||||
HidButton::B15, // 9
|
|
||||||
HidButton::B17, // 10
|
|
||||||
HidButton::B18, // 11
|
|
||||||
HidButton::ModeR, // 12
|
|
||||||
HidButton::B19, // 13
|
|
||||||
HidButton::B20, // 14
|
|
||||||
HidButton::H3B, // 15
|
|
||||||
HidButton::H3U, // 16
|
|
||||||
HidButton::H3R, // 17
|
|
||||||
HidButton::H3D, // 18
|
|
||||||
HidButton::H3L, // 19
|
|
||||||
HidButton::H4B, // 20
|
|
||||||
HidButton::H4U, // 21
|
|
||||||
HidButton::H4R, // 22
|
|
||||||
HidButton::H4D, // 23
|
|
||||||
HidButton::H4L, // 24
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
// Button index map:
|
|
||||||
// --------------------------------------------------------------
|
|
||||||
// | 0 L| 1 U| | 2 | | 3 L| 4 U|
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
// | | 5 | 6 | 7 | | 12 | 11 | 10 | |
|
|
||||||
// | |
|
|
||||||
// | | 8 | | 13 | |
|
|
||||||
// | | 9 | | 14 | |
|
|
||||||
// | X1/Y1 X2/Y2 |
|
|
||||||
// | | 16 | | 21 | |
|
|
||||||
// | | 17 | 15 | 18 | | 22 | 20 | 23 | |
|
|
||||||
// | | 19 | | 24 | |
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
//
|
|
||||||
pub const ELRS_MAP: [ElrsButton; NUMBER_OF_BUTTONS] = [
|
|
||||||
// ELRS Key // Button Index
|
|
||||||
// -----------------------------------------
|
|
||||||
ElrsButton::CH7OFF, // 0
|
|
||||||
ElrsButton::CH7ON, // 1
|
|
||||||
ElrsButton::NoEventIndicated, // 2
|
|
||||||
ElrsButton::CH8OFF, // 3
|
|
||||||
ElrsButton::CH8ON, // 4
|
|
||||||
ElrsButton::CH9ON, // 5
|
|
||||||
ElrsButton::CH9OFF, // 6
|
|
||||||
ElrsButton::CH5, // 7
|
|
||||||
ElrsButton::CH10ON, // 8
|
|
||||||
ElrsButton::CH10OFF, // 9
|
|
||||||
ElrsButton::CH11ON, // 10
|
|
||||||
ElrsButton::CH11OFF, // 11
|
|
||||||
ElrsButton::CH6, // 12
|
|
||||||
ElrsButton::CH12ON, // 13
|
|
||||||
ElrsButton::CH12OFF, // 14
|
|
||||||
ElrsButton::CH12Z, // 15
|
|
||||||
ElrsButton::CH2P, // 16
|
|
||||||
ElrsButton::CH1P, // 17
|
|
||||||
ElrsButton::CH2M, // 18
|
|
||||||
ElrsButton::CH1M, // 19
|
|
||||||
ElrsButton::CH34Z, // 20
|
|
||||||
ElrsButton::CH4P, // 21
|
|
||||||
ElrsButton::CH3P, // 22
|
|
||||||
ElrsButton::CH4M, // 23
|
|
||||||
ElrsButton::CH3M, // 24
|
|
||||||
];
|
|
||||||
|
|
||||||
// Button index map:
|
|
||||||
// --------------------------------------------------------------
|
|
||||||
// | 0 L| 1 U| | 2 | | 3 L| 4 U|
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
// | | 5 | 6 | 7 | | 12 | 11 | 10 | |
|
|
||||||
// | |
|
|
||||||
// | | 8 | | 13 | |
|
|
||||||
// | | 9 | | 14 | |
|
|
||||||
// | X1/Y1 X2/Y2 |
|
|
||||||
// | | 16 | | 21 | |
|
|
||||||
// | | 17 | 15 | 18 | | 22 | 20 | 23 | |
|
|
||||||
// | | 19 | | 24 | |
|
|
||||||
// ---------------------------------------------------------------
|
|
||||||
//
|
|
||||||
pub const CONFIG_MAP: [ConfigButton; NUMBER_OF_BUTTONS] = [
|
|
||||||
// Config Key // Button Index
|
|
||||||
// -----------------------------------------
|
|
||||||
ConfigButton::BOOT, // 0
|
|
||||||
ConfigButton::CAL, // 1
|
|
||||||
ConfigButton::CONF, // 2
|
|
||||||
ConfigButton::USB, // 3
|
|
||||||
ConfigButton::ELRS, // 4
|
|
||||||
ConfigButton::NoEventIndicated, // 5
|
|
||||||
ConfigButton::NoEventIndicated, // 6
|
|
||||||
ConfigButton::NoEventIndicated, // 7
|
|
||||||
ConfigButton::NoEventIndicated, // 8
|
|
||||||
ConfigButton::NoEventIndicated, // 9
|
|
||||||
ConfigButton::NoEventIndicated, // 10
|
|
||||||
ConfigButton::NoEventIndicated, // 11
|
|
||||||
ConfigButton::NoEventIndicated, // 12
|
|
||||||
ConfigButton::NoEventIndicated, // 13
|
|
||||||
ConfigButton::NoEventIndicated, // 14
|
|
||||||
ConfigButton::NoEventIndicated, // 15
|
|
||||||
ConfigButton::NoEventIndicated, // 16
|
|
||||||
ConfigButton::NoEventIndicated, // 17
|
|
||||||
ConfigButton::NoEventIndicated, // 18
|
|
||||||
ConfigButton::NoEventIndicated, // 19
|
|
||||||
ConfigButton::NoEventIndicated, // 20
|
|
||||||
ConfigButton::NoEventIndicated, // 21
|
|
||||||
ConfigButton::NoEventIndicated, // 22
|
|
||||||
ConfigButton::NoEventIndicated, // 23
|
|
||||||
ConfigButton::NoEventIndicated, // 24
|
|
||||||
];
|
|
||||||
@ -3,13 +3,62 @@
|
|||||||
//! Author: Christoffer Martinsson
|
//! Author: Christoffer Martinsson
|
||||||
//! Email: cm@cmtec.se
|
//! Email: cm@cmtec.se
|
||||||
//! License: Please refer to LICENSE in root directory
|
//! License: Please refer to LICENSE in root directory
|
||||||
|
//
|
||||||
|
// Button index map:
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// | 0 L| 1 U| | 2 | | 3 L| 4 U|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// | | 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:
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// | B1 L| B2 U| | B3 | | B4 L| B5 U|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// | | B6 | B7 | B8/16| |B13/17| B12 | B11 | |
|
||||||
|
// | |
|
||||||
|
// | | B9 | | B14 | |
|
||||||
|
// | | B10 | | B15 | |
|
||||||
|
// | X1/Y1 X2/Y2 |
|
||||||
|
// | | H1U | | H2U | |
|
||||||
|
// | | H1L | B18 | H1R | | H2L | B19 | H2R | |
|
||||||
|
// | | H1D | | H2D | |
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// Button (Switch) 7 changes following:
|
||||||
|
// * hat1 => hat3 (button press B20).
|
||||||
|
// Button (switch) 12 changes following:
|
||||||
|
// * B4 => B21
|
||||||
|
// * B5 => B22
|
||||||
|
// * B14 => B23
|
||||||
|
// * B15 => B24
|
||||||
|
// * hat2 => hat4 (button bpress B25)
|
||||||
|
//
|
||||||
|
// ELRS channel map (+ = ON, - = OFF, CHxP/M/Z = trim)
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// |CH7-L|CH7+U| | - | |CH8-L|CH8+U|
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
// | | THL | CH9 | CH5 | | CH6 |CH11-|CH11+| |
|
||||||
|
// | |
|
||||||
|
// | |CH10+| |CH12+| |
|
||||||
|
// | |CH10-| |CH12-| |
|
||||||
|
// | CH1/CH2 CH3/CH4 |
|
||||||
|
// | | - | |CH4P | |
|
||||||
|
// | |CH1M |CH12Z|CH1P | |CH3M |CH34Z|CH3P | |
|
||||||
|
// | | - | |CH4M | |
|
||||||
|
// ---------------------------------------------------------------
|
||||||
|
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
mod button_matrix;
|
mod button_matrix;
|
||||||
mod elrs;
|
mod elrs;
|
||||||
mod layout;
|
|
||||||
mod status_led;
|
mod status_led;
|
||||||
mod usb_joystick_device;
|
mod usb_joystick_device;
|
||||||
|
|
||||||
@ -78,16 +127,24 @@ pub const SENSITIVITY: i32 = (0.01 * ((1 << I32_FRAC_BITS) as f32)) as i32;
|
|||||||
|
|
||||||
pub const DEBOUNCE: u8 = 10;
|
pub const DEBOUNCE: u8 = 10;
|
||||||
|
|
||||||
|
pub const RELEASE_RIMEOUT: u16 = 30;
|
||||||
|
|
||||||
// Public types
|
// Public types
|
||||||
#[derive(Copy, Clone, Default)]
|
#[derive(Copy, Clone, Default)]
|
||||||
pub struct Button {
|
pub struct Button {
|
||||||
pub pressed: bool,
|
pub pressed: bool,
|
||||||
pub previous_pressed: bool,
|
pub previous_pressed: bool,
|
||||||
pub fn_mode: u8,
|
|
||||||
pub usb_changed: bool,
|
pub usb_changed: bool,
|
||||||
pub usb_changed_to: bool,
|
pub usb_changed_to: 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 elrs_changed: bool,
|
pub elrs_changed: bool,
|
||||||
pub elrs_changed_to: bool,
|
pub elrs_changed_to: bool,
|
||||||
|
pub usb_release_timeout: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
@ -98,10 +155,11 @@ pub struct GimbalAxis {
|
|||||||
pub max: u16,
|
pub max: u16,
|
||||||
pub min: u16,
|
pub min: u16,
|
||||||
pub center: u16,
|
pub center: u16,
|
||||||
pub fn_mode: u8,
|
|
||||||
pub deadzone: (u16, u16, u16),
|
pub deadzone: (u16, u16, u16),
|
||||||
pub expo: bool,
|
pub expo: bool,
|
||||||
pub trim: i16,
|
pub trim: i16,
|
||||||
|
pub hold: u16,
|
||||||
|
pub hold_pending: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for GimbalAxis {
|
impl Default for GimbalAxis {
|
||||||
@ -113,10 +171,11 @@ impl Default for GimbalAxis {
|
|||||||
max: AXIS_MAX,
|
max: AXIS_MAX,
|
||||||
min: AXIS_MIN,
|
min: AXIS_MIN,
|
||||||
center: AXIS_CENTER,
|
center: AXIS_CENTER,
|
||||||
fn_mode: 0,
|
|
||||||
deadzone: (100, 50, 100),
|
deadzone: (100, 50, 100),
|
||||||
expo: true,
|
expo: true,
|
||||||
trim: 0,
|
trim: 0,
|
||||||
|
hold: 0,
|
||||||
|
hold_pending: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,7 +322,6 @@ fn main() -> ! {
|
|||||||
let mut usb_update_count_down = timer.count_down();
|
let mut usb_update_count_down = timer.count_down();
|
||||||
usb_update_count_down.start(10.millis());
|
usb_update_count_down.start(10.millis());
|
||||||
|
|
||||||
let mut mode: u8 = 0;
|
|
||||||
let mut safety_check: bool = false;
|
let mut safety_check: bool = false;
|
||||||
let mut usb_activity: bool = false;
|
let mut usb_activity: bool = false;
|
||||||
let mut idle: bool = false;
|
let mut idle: bool = false;
|
||||||
@ -271,20 +329,49 @@ fn main() -> ! {
|
|||||||
let mut elrs_active: bool = false;
|
let mut elrs_active: bool = false;
|
||||||
let mut elrs_connected: bool = false;
|
let mut elrs_connected: bool = false;
|
||||||
let mut calibration_active: bool = false;
|
let mut calibration_active: bool = false;
|
||||||
|
let mut throttle_hold: bool = false;
|
||||||
|
|
||||||
let mut axis: [GimbalAxis; NBR_OF_GIMBAL_AXIS] = [Default::default(); NBR_OF_GIMBAL_AXIS];
|
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];
|
let mut buttons: [Button; NUMBER_OF_BUTTONS] = [Button::default(); NUMBER_OF_BUTTONS];
|
||||||
let mut channel_locks: [bool; 12] = [false; 12];
|
let mut channel_locks: [bool; 12] = [false; 12];
|
||||||
let mut gimbal_mode: u8;
|
let mut gimbal_mode: u8;
|
||||||
|
|
||||||
|
// Set up button layout
|
||||||
|
buttons[0].usb_button = 1;
|
||||||
|
buttons[1].usb_button = 2;
|
||||||
|
buttons[2].usb_button = 3;
|
||||||
|
buttons[3].usb_button = 4;
|
||||||
|
buttons[3].usb_button_sec_enable = true;
|
||||||
|
buttons[3].usb_button_sec = 21;
|
||||||
|
buttons[3].usb_button_sec_trigger_index = 12;
|
||||||
|
buttons[4].usb_button = 5;
|
||||||
|
buttons[4].usb_button_sec_enable = true;
|
||||||
|
buttons[4].usb_button_sec = 22;
|
||||||
|
buttons[4].usb_button_sec_trigger_index = 12;
|
||||||
|
buttons[5].usb_button = 6;
|
||||||
|
buttons[6].usb_button = 7;
|
||||||
|
buttons[7].usb_button = 8;
|
||||||
|
buttons[7].usb_button_sec = 16;
|
||||||
|
buttons[7].usb_button_toggle_enable = true;
|
||||||
|
buttons[8].usb_button = 9;
|
||||||
|
buttons[9].usb_button = 10;
|
||||||
|
buttons[10].usb_button = 11;
|
||||||
|
buttons[11].usb_button = 12;
|
||||||
|
buttons[12].usb_button = 13;
|
||||||
|
buttons[12].usb_button_sec = 17;
|
||||||
|
buttons[12].usb_button_toggle_enable = true;
|
||||||
|
buttons[13].usb_button = 14;
|
||||||
|
buttons[13].usb_button_sec_enable = true;
|
||||||
|
buttons[13].usb_button_sec = 23;
|
||||||
|
buttons[13].usb_button_sec_trigger_index = 12;
|
||||||
|
buttons[14].usb_button = 15;
|
||||||
|
buttons[14].usb_button_sec_enable = true;
|
||||||
|
buttons[14].usb_button_sec = 24;
|
||||||
|
buttons[14].usb_button_sec_trigger_index = 12;
|
||||||
|
|
||||||
// Table for gimbal expo curve lookup insded of doing floating point math for every analog read
|
// Table for gimbal expo curve lookup insded of doing floating point math for every analog read
|
||||||
let expo_lut: [u16; AXIS_MAX as usize + 1] = generate_expo_lut(0.3);
|
let expo_lut: [u16; AXIS_MAX as usize + 1] = generate_expo_lut(0.3);
|
||||||
|
|
||||||
// Set up left gimbal Y axis as full range without return to center spring
|
|
||||||
axis[GIMBAL_AXIS_LEFT_Y].idle_value = AXIS_MIN;
|
|
||||||
axis[GIMBAL_AXIS_LEFT_Y].deadzone = (100, 0, 100);
|
|
||||||
axis[GIMBAL_AXIS_LEFT_Y].expo = false;
|
|
||||||
|
|
||||||
// Create dynamic smoother array for gimbal axis
|
// Create dynamic smoother array for gimbal axis
|
||||||
let mut smoother: [DynamicSmootherEcoI32; NBR_OF_GIMBAL_AXIS] = [
|
let mut smoother: [DynamicSmootherEcoI32; NBR_OF_GIMBAL_AXIS] = [
|
||||||
DynamicSmootherEcoI32::new(BASE_FREQ, SAMPLE_FREQ, SENSITIVITY),
|
DynamicSmootherEcoI32::new(BASE_FREQ, SAMPLE_FREQ, SENSITIVITY),
|
||||||
@ -364,6 +451,7 @@ fn main() -> ! {
|
|||||||
&elrs.connected(),
|
&elrs.connected(),
|
||||||
&safety_check,
|
&safety_check,
|
||||||
&calibration_active,
|
&calibration_active,
|
||||||
|
&throttle_hold,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -373,8 +461,13 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if data_process_count_down.wait().is_ok() {
|
if data_process_count_down.wait().is_ok() {
|
||||||
|
// Update pressed keys status
|
||||||
|
for (index, key) in button_matrix.buttons_pressed().iter().enumerate() {
|
||||||
|
buttons[index].pressed = *key;
|
||||||
|
}
|
||||||
|
|
||||||
// Secondary way to enter bootloader (pressing all left hands buttons except the hat
|
// Secondary way to enter bootloader (pressing all left hands buttons except the hat
|
||||||
if button_matrix.buttons_pressed()[0] && button_matrix.buttons_pressed()[2] {
|
if buttons[0].pressed && buttons[2].pressed {
|
||||||
status_led.update(StatusMode::Bootloader);
|
status_led.update(StatusMode::Bootloader);
|
||||||
let gpio_activity_pin_mask: u32 = 0;
|
let gpio_activity_pin_mask: u32 = 0;
|
||||||
let disable_interface_mask: u32 = 0;
|
let disable_interface_mask: u32 = 0;
|
||||||
@ -385,22 +478,24 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ON/OFF switch for ELRS radio
|
// ON/OFF switch for ELRS radio
|
||||||
if button_matrix.buttons_pressed()[4]
|
if buttons[4].pressed && buttons[2].pressed && !elrs_active {
|
||||||
&& button_matrix.buttons_pressed()[2]
|
|
||||||
&& !elrs_active
|
|
||||||
{
|
|
||||||
safety_check = false;
|
safety_check = false;
|
||||||
elrs_active = true;
|
elrs_active = true;
|
||||||
} else if button_matrix.buttons_pressed()[3]
|
} else if buttons[3].pressed && buttons[2].pressed && elrs_active {
|
||||||
&& button_matrix.buttons_pressed()[2]
|
|
||||||
&& elrs_active
|
|
||||||
{
|
|
||||||
elrs_active = false;
|
elrs_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calibration of center position (pressing all right hands buttons except the hat
|
// ON/OFF switch for Throttle hold mode
|
||||||
// switch)
|
if buttons[6].pressed && buttons[2].pressed && !throttle_hold {
|
||||||
if button_matrix.buttons_pressed()[1] && button_matrix.buttons_pressed()[2] {
|
throttle_hold = true;
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].hold = 0;
|
||||||
|
} else if buttons[5].pressed && buttons[2].pressed && throttle_hold {
|
||||||
|
throttle_hold = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calibration of center position (pressing all right hands buttons except
|
||||||
|
// the hat switch)
|
||||||
|
if buttons[1].pressed && buttons[2].pressed {
|
||||||
for (index, item) in axis.iter_mut().enumerate() {
|
for (index, item) in axis.iter_mut().enumerate() {
|
||||||
item.center = smoother[index].value() as u16;
|
item.center = smoother[index].value() as u16;
|
||||||
item.min = item.center;
|
item.min = item.center;
|
||||||
@ -420,14 +515,14 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if calibration_active && button_matrix.buttons_pressed()[8] {
|
if calibration_active && buttons[8].pressed {
|
||||||
gimbal_mode = GIMBAL_MODE_M10;
|
gimbal_mode = GIMBAL_MODE_M10;
|
||||||
for (index, item) in axis.iter_mut().enumerate() {
|
for (index, item) in axis.iter_mut().enumerate() {
|
||||||
item.center = smoother[index].value() as u16;
|
item.center = smoother[index].value() as u16;
|
||||||
item.min = item.center;
|
item.min = item.center;
|
||||||
item.max = item.center;
|
item.max = item.center;
|
||||||
}
|
}
|
||||||
} else if calibration_active && button_matrix.buttons_pressed()[9] {
|
} else if calibration_active && buttons[9].pressed {
|
||||||
gimbal_mode = GIMBAL_MODE_M7;
|
gimbal_mode = GIMBAL_MODE_M7;
|
||||||
for (index, item) in axis.iter_mut().enumerate() {
|
for (index, item) in axis.iter_mut().enumerate() {
|
||||||
item.center = smoother[index].value() as u16;
|
item.center = smoother[index].value() as u16;
|
||||||
@ -436,7 +531,7 @@ fn main() -> ! {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Save calibration data to eeprom (pressing right hat switch)
|
// Save calibration data to eeprom (pressing right hat switch)
|
||||||
else if calibration_active && button_matrix.buttons_pressed()[20] {
|
else if calibration_active && buttons[20].pressed {
|
||||||
let mut eeprom_data: [u8; 25] = [0; 25];
|
let mut eeprom_data: [u8; 25] = [0; 25];
|
||||||
for (index, item) in axis.iter_mut().enumerate() {
|
for (index, item) in axis.iter_mut().enumerate() {
|
||||||
eeprom_data[index * 6] = item.min as u8;
|
eeprom_data[index * 6] = item.min as u8;
|
||||||
@ -464,37 +559,39 @@ fn main() -> ! {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update pressed keys status
|
// Process throttle hold value
|
||||||
for (index, key) in button_matrix.buttons_pressed().iter().enumerate() {
|
if throttle_hold
|
||||||
buttons[index].pressed = *key;
|
&& axis[GIMBAL_AXIS_LEFT_Y].value < AXIS_CENTER
|
||||||
|
&& !axis[GIMBAL_AXIS_LEFT_Y].hold_pending
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].value = remap(
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].value,
|
||||||
|
AXIS_MIN,
|
||||||
|
AXIS_CENTER,
|
||||||
|
AXIS_MIN,
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].hold,
|
||||||
|
);
|
||||||
|
} else if throttle_hold
|
||||||
|
&& axis[GIMBAL_AXIS_LEFT_Y].value > AXIS_CENTER
|
||||||
|
&& !axis[GIMBAL_AXIS_LEFT_Y].hold_pending
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].value = remap(
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].value,
|
||||||
|
AXIS_CENTER,
|
||||||
|
AXIS_MAX,
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].hold,
|
||||||
|
AXIS_MAX,
|
||||||
|
);
|
||||||
|
} else if throttle_hold && axis[GIMBAL_AXIS_LEFT_Y].value == AXIS_CENTER {
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].value = axis[GIMBAL_AXIS_LEFT_Y].hold;
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].hold_pending = false;
|
||||||
|
} else if throttle_hold {
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].value = axis[GIMBAL_AXIS_LEFT_Y].hold;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Fn mode for all axis that are in idle position
|
// Set idle state
|
||||||
// This is to avoid the Fn mode switching when moving the gimbal
|
for key in buttons.iter_mut() {
|
||||||
mode = get_mode(button_matrix.buttons_pressed());
|
if key.pressed {
|
||||||
idle = true;
|
|
||||||
for item in axis.iter_mut() {
|
|
||||||
if item.value == item.idle_value {
|
|
||||||
item.fn_mode = mode & 0x0F;
|
|
||||||
} else {
|
|
||||||
idle = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set fn mode for all keys that are in idle position
|
|
||||||
// This is to avoid the Fn mode switching when using a button
|
|
||||||
for (index, key) in buttons.iter_mut().enumerate() {
|
|
||||||
if !key.pressed {
|
|
||||||
key.fn_mode = mode & 0x0F;
|
|
||||||
} else if (usb_active
|
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] != layout::HidButton::Fn
|
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] != layout::HidButton::ModeL
|
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] != layout::HidButton::ModeR
|
|
||||||
&& index != 2)
|
|
||||||
|| (elrs_active
|
|
||||||
&& layout::ELRS_MAP[index] != layout::ElrsButton::NoEventIndicated
|
|
||||||
&& index != 2)
|
|
||||||
{
|
|
||||||
idle = false;
|
idle = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -507,23 +604,28 @@ fn main() -> ! {
|
|||||||
item.previous_value = item.value;
|
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
|
// Generate led activity when a button is pressed
|
||||||
// FnL, FnR, and ModeR are excluded
|
|
||||||
for (index, key) in buttons.iter_mut().enumerate() {
|
for (index, key) in buttons.iter_mut().enumerate() {
|
||||||
if (usb_active
|
if key.pressed != key.previous_pressed {
|
||||||
&& key.pressed != key.previous_pressed
|
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] != layout::HidButton::Fn
|
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] != layout::HidButton::ModeR)
|
|
||||||
|| (elrs_active
|
|
||||||
&& key.pressed != key.previous_pressed
|
|
||||||
&& layout::ELRS_MAP[index] != layout::ElrsButton::NoEventIndicated)
|
|
||||||
{
|
|
||||||
key.usb_changed = true;
|
key.usb_changed = true;
|
||||||
key.usb_changed_to = key.pressed;
|
key.usb_changed_to = key.pressed;
|
||||||
key.elrs_changed = true;
|
key.elrs_changed = true;
|
||||||
key.elrs_changed_to = key.pressed;
|
key.elrs_changed_to = key.pressed;
|
||||||
usb_activity = true;
|
usb_activity = true;
|
||||||
}
|
}
|
||||||
|
// Set throttle_hold_value
|
||||||
|
if key.pressed != key.previous_pressed && key.pressed && throttle_hold && index == 5
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].hold = axis[GIMBAL_AXIS_LEFT_Y].value;
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].hold_pending = true;
|
||||||
|
}
|
||||||
key.previous_pressed = key.pressed;
|
key.previous_pressed = key.pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -553,11 +655,10 @@ fn main() -> ! {
|
|||||||
// Dont send USB HID joystick report if there is no activity
|
// Dont send USB HID joystick report if there is no activity
|
||||||
// This is to avoid preventing the computer from going to sleep
|
// This is to avoid preventing the computer from going to sleep
|
||||||
if usb_update_count_down.wait().is_ok() && usb_activity {
|
if usb_update_count_down.wait().is_ok() && usb_activity {
|
||||||
match usb_hid_joystick.device().write_report(&get_joystick_report(
|
match usb_hid_joystick
|
||||||
&mut buttons,
|
.device()
|
||||||
&mut axis,
|
.write_report(&get_joystick_report(&mut buttons, &mut axis))
|
||||||
&mode,
|
{
|
||||||
)) {
|
|
||||||
Err(UsbHidError::WouldBlock) => {}
|
Err(UsbHidError::WouldBlock) => {}
|
||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -590,6 +691,7 @@ fn update_status_led<P, SM, I>(
|
|||||||
elrs_connected: &bool,
|
elrs_connected: &bool,
|
||||||
safety_check: &bool,
|
safety_check: &bool,
|
||||||
calibration_active: &bool,
|
calibration_active: &bool,
|
||||||
|
throttle_hold: &bool,
|
||||||
) where
|
) where
|
||||||
P: PIOExt + FunctionConfig,
|
P: PIOExt + FunctionConfig,
|
||||||
I: PinId,
|
I: PinId,
|
||||||
@ -602,7 +704,9 @@ fn update_status_led<P, SM, I>(
|
|||||||
status_led.update(StatusMode::Warning);
|
status_led.update(StatusMode::Warning);
|
||||||
} else if !*usb_active && !*elrs_active {
|
} else if !*usb_active && !*elrs_active {
|
||||||
status_led.update(StatusMode::NormalFlash);
|
status_led.update(StatusMode::NormalFlash);
|
||||||
} else if *usb_active && !*elrs_active {
|
} else if *usb_active && !*elrs_active && *throttle_hold {
|
||||||
|
status_led.update(StatusMode::Activity);
|
||||||
|
} else if *usb_active && !*elrs_active && !*throttle_hold {
|
||||||
status_led.update(StatusMode::Normal);
|
status_led.update(StatusMode::Normal);
|
||||||
} else if *elrs_active && *elrs_connected {
|
} else if *elrs_active && *elrs_connected {
|
||||||
status_led.update(StatusMode::Other);
|
status_led.update(StatusMode::Other);
|
||||||
@ -611,50 +715,6 @@ fn update_status_led<P, SM, I>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get current Fn mode (0, 1, 2 or 3 and alt l/r mode)
|
|
||||||
/// layout::MAP contains the button types
|
|
||||||
///
|
|
||||||
/// # Arguments
|
|
||||||
///
|
|
||||||
/// * `pressed_keys` - Array of pressed keys
|
|
||||||
fn get_mode(pressed_keys: [bool; NUMBER_OF_BUTTONS]) -> u8 {
|
|
||||||
// Check how many Fn keys are pressed
|
|
||||||
let mut mode: u8 = 0;
|
|
||||||
let mut fn_active: bool = false;
|
|
||||||
let mut alt_l_active: bool = false;
|
|
||||||
let mut alt_r_active: bool = false;
|
|
||||||
|
|
||||||
for (index, key) in pressed_keys.iter().enumerate() {
|
|
||||||
if *key && layout::HID_MAP[0][index] == layout::HidButton::Fn {
|
|
||||||
fn_active = true;
|
|
||||||
}
|
|
||||||
if *key && layout::HID_MAP[0][index] == layout::HidButton::ModeL {
|
|
||||||
alt_l_active = true;
|
|
||||||
}
|
|
||||||
if *key && layout::HID_MAP[0][index] == layout::HidButton::ModeR {
|
|
||||||
alt_r_active = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if alt_r_active && fn_active {
|
|
||||||
mode = 3;
|
|
||||||
} else if alt_r_active {
|
|
||||||
mode = 2;
|
|
||||||
} else if fn_active {
|
|
||||||
mode = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set bit 4 and 5 if mode l/r is active
|
|
||||||
if alt_l_active {
|
|
||||||
mode |= 0x10;
|
|
||||||
}
|
|
||||||
if alt_r_active {
|
|
||||||
mode |= 0x20;
|
|
||||||
}
|
|
||||||
|
|
||||||
mode
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generate keyboard report based on pressed keys and Fn mode (0, 1, 2 or 3)
|
/// Generate keyboard report based on pressed keys and Fn mode (0, 1, 2 or 3)
|
||||||
/// layout::MAP contains the keycodes for each key in each Fn mode
|
/// layout::MAP contains the keycodes for each key in each Fn mode
|
||||||
///
|
///
|
||||||
@ -662,104 +722,106 @@ fn get_mode(pressed_keys: [bool; NUMBER_OF_BUTTONS]) -> u8 {
|
|||||||
///
|
///
|
||||||
/// * `matrix_keys` - Array of pressed keys
|
/// * `matrix_keys` - Array of pressed keys
|
||||||
/// * `axis` - Array of joystick axis values
|
/// * `axis` - Array of joystick axis values
|
||||||
/// * `fn_mode` - Fn mode (0, 1, 2 or 3)
|
|
||||||
/// * `alt_l_mode` - Is left alt mode active
|
|
||||||
/// * `alt_r_mode` - Is right alt mode active
|
|
||||||
fn get_joystick_report(
|
fn get_joystick_report(
|
||||||
matrix_keys: &mut [Button; NUMBER_OF_BUTTONS],
|
matrix_keys: &mut [Button; NUMBER_OF_BUTTONS],
|
||||||
axis: &mut [GimbalAxis; 4],
|
axis: &mut [GimbalAxis; 4],
|
||||||
mode: &u8,
|
|
||||||
) -> JoystickReport {
|
) -> JoystickReport {
|
||||||
let mut x: u16 = axis[GIMBAL_AXIS_RIGHT_X].value;
|
let mut x: u16 = axis[GIMBAL_AXIS_RIGHT_X].value;
|
||||||
let mut y: u16 = AXIS_MAX - axis[GIMBAL_AXIS_RIGHT_Y].value;
|
let mut y: u16 = AXIS_MAX - axis[GIMBAL_AXIS_RIGHT_Y].value;
|
||||||
let z: u16 = axis[GIMBAL_AXIS_LEFT_X].value;
|
let z: u16 = axis[GIMBAL_AXIS_LEFT_X].value;
|
||||||
let mut rx: u16 = AXIS_CENTER;
|
let mut rx: u16 = AXIS_CENTER;
|
||||||
let mut ry: u16 = AXIS_CENTER;
|
let mut ry: u16 = AXIS_CENTER;
|
||||||
let mut rz: u16 = axis[GIMBAL_AXIS_LEFT_Y].value;
|
let rz: u16 = axis[GIMBAL_AXIS_LEFT_Y].value;
|
||||||
|
let (mut hat1, mut hat_button1) = format_hat_value(0);
|
||||||
// Left Alt mode active (bit 4)
|
let (mut hat2, mut hat_button2) = format_hat_value(0);
|
||||||
// Full range of left gimbal gives half range of joystick axis (center to max)
|
let (mut hat3, mut hat_button3) = format_hat_value(0);
|
||||||
// Left Fn mode = reversed range (center to min)
|
let (mut hat4, mut hat_button4) = format_hat_value(0);
|
||||||
if mode & 0x10 == 0x10
|
|
||||||
&& (axis[GIMBAL_AXIS_LEFT_Y].fn_mode == 0 || axis[GIMBAL_AXIS_LEFT_Y].fn_mode == 2)
|
|
||||||
{
|
|
||||||
rz = remap(
|
|
||||||
axis[GIMBAL_AXIS_LEFT_Y].value,
|
|
||||||
AXIS_MIN,
|
|
||||||
AXIS_MAX,
|
|
||||||
AXIS_CENTER,
|
|
||||||
AXIS_MAX,
|
|
||||||
);
|
|
||||||
} else if mode & 0x10 == 0x10
|
|
||||||
&& (axis[GIMBAL_AXIS_LEFT_Y].fn_mode == 1 || axis[GIMBAL_AXIS_LEFT_Y].fn_mode == 3)
|
|
||||||
{
|
|
||||||
rz = AXIS_MAX
|
|
||||||
- remap(
|
|
||||||
axis[GIMBAL_AXIS_LEFT_Y].value,
|
|
||||||
AXIS_MIN,
|
|
||||||
AXIS_MAX,
|
|
||||||
AXIS_CENTER,
|
|
||||||
AXIS_MAX,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right Alt mode active (bit 5)
|
// Right Alt mode active (bit 5)
|
||||||
// Right gimbal control third joystick axis when right Fn mode is active
|
// Right gimbal control third joystick axis when right Fn mode is active
|
||||||
if mode & 0x20 == 0x20 && (axis[GIMBAL_AXIS_RIGHT_X].fn_mode == 1) {
|
if matrix_keys[8].pressed {
|
||||||
x = AXIS_CENTER;
|
x = AXIS_CENTER;
|
||||||
rx = axis[GIMBAL_AXIS_RIGHT_X].value;
|
rx = axis[GIMBAL_AXIS_RIGHT_X].value;
|
||||||
}
|
|
||||||
if mode & 0x20 == 0x20 && axis[GIMBAL_AXIS_RIGHT_Y].fn_mode == 1 {
|
|
||||||
y = AXIS_CENTER;
|
y = AXIS_CENTER;
|
||||||
ry = AXIS_MAX - axis[GIMBAL_AXIS_RIGHT_Y].value;
|
ry = AXIS_MAX - axis[GIMBAL_AXIS_RIGHT_Y].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate array for all four hat switches with following structure:
|
let mut hat_left: u8 = 0;
|
||||||
// * bit 1: Up
|
let mut hat_right: u8 = 0;
|
||||||
// * bit 2: Right
|
|
||||||
// * bit 3: Down
|
|
||||||
// * bit 4: Left
|
|
||||||
// * bit 5: Button
|
|
||||||
// * value 0 = not pressed
|
|
||||||
// * value 1 = pressed
|
|
||||||
let mut hats: [u8; 4] = [0; 4];
|
|
||||||
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
||||||
if key.pressed
|
if (15..=19).contains(&index) && key.pressed {
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] >= layout::HidButton::H1U
|
hat_left |= 1 << (index - 15);
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] <= layout::HidButton::H4B
|
}
|
||||||
{
|
if (20..=24).contains(&index) && key.pressed {
|
||||||
hats[(layout::HID_MAP[key.fn_mode as usize][index] as usize
|
hat_right |= 1 << (index - 20);
|
||||||
- layout::HidButton::H1U as usize)
|
|
||||||
/ 5] |= 1
|
|
||||||
<< ((layout::HID_MAP[key.fn_mode as usize][index] as usize
|
|
||||||
- layout::HidButton::H1U as usize)
|
|
||||||
- (5 * ((layout::HID_MAP[key.fn_mode as usize][index] as usize
|
|
||||||
- layout::HidButton::H1U as usize)
|
|
||||||
/ 5)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert hat switch data to HID code
|
// Convert hat switch data to HID code
|
||||||
let (hat1, hat_button1) = format_hat_value(hats[0]);
|
if matrix_keys[7].pressed {
|
||||||
let (hat2, hat_button2) = format_hat_value(hats[1]);
|
(hat3, hat_button3) = format_hat_value(hat_left);
|
||||||
let (hat3, hat_button3) = format_hat_value(hats[2]);
|
} else {
|
||||||
let (hat4, hat_button4) = format_hat_value(hats[3]);
|
(hat1, hat_button1) = format_hat_value(hat_left);
|
||||||
|
}
|
||||||
|
if matrix_keys[12].pressed {
|
||||||
|
(hat4, hat_button4) = format_hat_value(hat_right);
|
||||||
|
} else {
|
||||||
|
(hat2, hat_button2) = format_hat_value(hat_right);
|
||||||
|
}
|
||||||
|
|
||||||
// Update button state for joystick button 21-24 according to hat button 1-4
|
// Update button state for joystick button 21-24 according to hat button 1-4
|
||||||
let mut buttons: u32 = (hat_button1 as u32) << 28
|
let mut buttons: u32 = (hat_button1 as u32) << 17
|
||||||
| ((hat_button2 as u32) << 29)
|
| ((hat_button2 as u32) << 18)
|
||||||
| ((hat_button3 as u32) << 30)
|
| ((hat_button3 as u32) << 19)
|
||||||
| ((hat_button4 as u32) << 31);
|
| ((hat_button4 as u32) << 24);
|
||||||
|
|
||||||
// Update button state for joystick button 1-28
|
// Update button array with Sec button trigger status
|
||||||
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
// Using indexing instead of iterating to be able to iterate inside loop
|
||||||
|
for index in 0..NUMBER_OF_BUTTONS {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
matrix_keys[index].usb_button_sec_pressed = sec_button_pressed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update button state for joystick buttons
|
||||||
|
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;
|
||||||
|
key.usb_changed = false;
|
||||||
|
}
|
||||||
if key.pressed
|
if key.pressed
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] as usize
|
&& key.usb_button != 0
|
||||||
>= layout::HidButton::B1 as usize
|
&& key.usb_button_toggle_enable
|
||||||
&& layout::HID_MAP[key.fn_mode as usize][index] as usize
|
&& key.usb_release_timeout > 1
|
||||||
<= layout::HidButton::B28 as usize
|
|
||||||
{
|
{
|
||||||
buttons |= 1 << layout::HID_MAP[key.fn_mode as usize][index] as usize;
|
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);
|
||||||
|
} else if key.pressed && key.usb_button != 0 && !key.usb_button_toggle_enable {
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -782,8 +844,8 @@ fn get_joystick_report(
|
|||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * `input` - Hat value coded as
|
/// * `input` - Hat value coded as
|
||||||
/// bit 1-4: direction (U R D L)
|
/// bit 2-5: direction (U L R D)
|
||||||
/// bit 5: button state
|
/// bit 1: button state
|
||||||
/// 0 = not pressed
|
/// 0 = not pressed
|
||||||
/// 1 = pressed
|
/// 1 = pressed
|
||||||
fn format_hat_value(input: u8) -> (u8, u8) {
|
fn format_hat_value(input: u8) -> (u8, u8) {
|
||||||
@ -797,21 +859,21 @@ fn format_hat_value(input: u8) -> (u8, u8) {
|
|||||||
const HAT_LEFT: u8 = 6;
|
const HAT_LEFT: u8 = 6;
|
||||||
const HAT_UP_LEFT: u8 = 7;
|
const HAT_UP_LEFT: u8 = 7;
|
||||||
|
|
||||||
let direction: u8 = match input & 0x0F {
|
let direction: u8 = match input & 0xFE {
|
||||||
1 => HAT_UP,
|
2 => HAT_UP,
|
||||||
2 => HAT_RIGHT,
|
4 => HAT_RIGHT,
|
||||||
3 => HAT_UP_RIGHT,
|
6 => HAT_UP_RIGHT,
|
||||||
4 => HAT_DOWN,
|
8 => HAT_DOWN,
|
||||||
6 => HAT_DOWN_RIGHT,
|
12 => HAT_DOWN_RIGHT,
|
||||||
8 => HAT_LEFT,
|
16 => HAT_LEFT,
|
||||||
12 => HAT_DOWN_LEFT,
|
24 => HAT_DOWN_LEFT,
|
||||||
9 => HAT_UP_LEFT,
|
18 => HAT_UP_LEFT,
|
||||||
_ => HAT_CENTER,
|
_ => HAT_CENTER,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Alpine hat switch button filter
|
// Alpine hat switch button filter
|
||||||
let mut button_state: u8 = 0;
|
let mut button_state: u8 = 0;
|
||||||
if input & 0x10 == 0x10 && direction == HAT_CENTER {
|
if input & 0x01 == 0x01 && direction == HAT_CENTER {
|
||||||
button_state = 1;
|
button_state = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -934,47 +996,62 @@ fn get_elrs_channels(
|
|||||||
let mut channels: [u16; 12] = [ELRS_MIN; 12];
|
let mut channels: [u16; 12] = [ELRS_MIN; 12];
|
||||||
|
|
||||||
// Check and store trim values
|
// Check and store trim values
|
||||||
let mut trim_active = false;
|
|
||||||
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
||||||
if key.pressed
|
// Left gimbal X
|
||||||
&& layout::ELRS_MAP[index] >= layout::ElrsButton::CH1P
|
if key.pressed && index == 17 && axis[GIMBAL_AXIS_LEFT_X].trim < ELRS_CENTER as i16 {
|
||||||
&& layout::ELRS_MAP[index] <= layout::ElrsButton::CH4P
|
axis[GIMBAL_AXIS_LEFT_X].trim += 1;
|
||||||
{
|
|
||||||
if axis[layout::ELRS_MAP[index] as usize - layout::ElrsButton::CH1P as usize].trim
|
|
||||||
< ELRS_CENTER as i16
|
|
||||||
{
|
|
||||||
axis[layout::ELRS_MAP[index] as usize - layout::ElrsButton::CH1P as usize].trim +=
|
|
||||||
1;
|
|
||||||
}
|
|
||||||
trim_active = true;
|
|
||||||
} else if key.pressed
|
} else if key.pressed
|
||||||
&& layout::ELRS_MAP[index] >= layout::ElrsButton::CH1M
|
&& index == 19
|
||||||
&& layout::ELRS_MAP[index] <= layout::ElrsButton::CH4M
|
&& axis[GIMBAL_AXIS_LEFT_X].trim > (0 - ELRS_CENTER as i16)
|
||||||
{
|
{
|
||||||
if axis[layout::ELRS_MAP[index] as usize - layout::ElrsButton::CH1M as usize].trim
|
axis[GIMBAL_AXIS_LEFT_X].trim -= 1;
|
||||||
> (0 - ELRS_CENTER as i16)
|
// Left gimbal Y
|
||||||
{
|
} else if key.pressed && index == 16 && axis[GIMBAL_AXIS_LEFT_Y].trim < ELRS_CENTER as i16 {
|
||||||
axis[layout::ELRS_MAP[index] as usize - layout::ElrsButton::CH1M as usize].trim -=
|
axis[GIMBAL_AXIS_LEFT_Y].trim += 1;
|
||||||
1;
|
} else if key.pressed
|
||||||
}
|
&& index == 18
|
||||||
trim_active = true;
|
&& axis[GIMBAL_AXIS_LEFT_Y].trim > (0 - ELRS_CENTER as i16)
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_LEFT_Y].trim -= 1;
|
||||||
|
// Right gimbal X
|
||||||
|
} else if key.pressed && index == 22 && axis[GIMBAL_AXIS_RIGHT_X].trim < ELRS_CENTER as i16
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_RIGHT_X].trim += 1;
|
||||||
|
} else if key.pressed
|
||||||
|
&& index == 24
|
||||||
|
&& axis[GIMBAL_AXIS_RIGHT_X].trim > (0 - ELRS_CENTER as i16)
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_RIGHT_X].trim -= 1;
|
||||||
|
// Right gimbal Y
|
||||||
|
} else if key.pressed && index == 21 && axis[GIMBAL_AXIS_RIGHT_Y].trim < ELRS_CENTER as i16
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_RIGHT_Y].trim += 1;
|
||||||
|
} else if key.pressed
|
||||||
|
&& index == 23
|
||||||
|
&& axis[GIMBAL_AXIS_RIGHT_Y].trim > (0 - ELRS_CENTER as i16)
|
||||||
|
{
|
||||||
|
axis[GIMBAL_AXIS_RIGHT_Y].trim -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Alpine hat switch filter
|
||||||
|
let mut hat_left_button_only: bool = true;
|
||||||
|
let mut hat_right_button_only: bool = true;
|
||||||
|
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
||||||
|
if key.pressed && (16..=19).contains(&index) {
|
||||||
|
hat_left_button_only = false;
|
||||||
|
}
|
||||||
|
if key.pressed && (21..=24).contains(&index) {
|
||||||
|
hat_right_button_only = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check and reset trim values
|
// Check and reset trim values
|
||||||
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
||||||
if !trim_active
|
if key.elrs_changed && key.elrs_changed_to && index == 15 && hat_left_button_only {
|
||||||
&& key.elrs_changed
|
|
||||||
&& key.elrs_changed_to
|
|
||||||
&& layout::ELRS_MAP[index] == layout::ElrsButton::CH12Z
|
|
||||||
{
|
|
||||||
axis[GIMBAL_AXIS_LEFT_X].trim = 0;
|
axis[GIMBAL_AXIS_LEFT_X].trim = 0;
|
||||||
axis[GIMBAL_AXIS_LEFT_Y].trim = 0;
|
axis[GIMBAL_AXIS_LEFT_Y].trim = 0;
|
||||||
} else if !trim_active
|
} else if key.elrs_changed && key.elrs_changed_to && index == 20 && hat_right_button_only {
|
||||||
&& key.elrs_changed
|
|
||||||
&& key.elrs_changed_to
|
|
||||||
&& layout::ELRS_MAP[index] == layout::ElrsButton::CH34Z
|
|
||||||
{
|
|
||||||
axis[GIMBAL_AXIS_RIGHT_X].trim = 0;
|
axis[GIMBAL_AXIS_RIGHT_X].trim = 0;
|
||||||
axis[GIMBAL_AXIS_RIGHT_Y].trim = 0;
|
axis[GIMBAL_AXIS_RIGHT_Y].trim = 0;
|
||||||
}
|
}
|
||||||
@ -1009,36 +1086,45 @@ fn get_elrs_channels(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update locking button state for ELRS channel 5-12
|
// Update button state for ELRS channels
|
||||||
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
||||||
if key.pressed
|
if key.pressed && index == 1 {
|
||||||
&& layout::ELRS_MAP[index] as usize >= layout::ElrsButton::CH5ON as usize
|
channel_locks[6] = true;
|
||||||
&& layout::ELRS_MAP[index] as usize <= layout::ElrsButton::CH12ON as usize
|
} else if key.pressed && index == 0 {
|
||||||
{
|
channel_locks[6] = false;
|
||||||
channel_locks
|
|
||||||
[layout::ELRS_MAP[index] as usize - layout::ElrsButton::CH5ON as usize + 4] = true;
|
|
||||||
}
|
}
|
||||||
if key.pressed
|
if key.pressed && index == 4 {
|
||||||
&& layout::ELRS_MAP[index] as usize >= layout::ElrsButton::CH5OFF as usize
|
channel_locks[7] = true;
|
||||||
&& layout::ELRS_MAP[index] as usize <= layout::ElrsButton::CH12OFF as usize
|
} else if key.pressed && index == 3 {
|
||||||
{
|
channel_locks[7] = false;
|
||||||
channel_locks
|
}
|
||||||
[layout::ELRS_MAP[index] as usize - layout::ElrsButton::CH5OFF as usize + 4] =
|
if key.pressed && index == 8 {
|
||||||
false;
|
channel_locks[9] = true;
|
||||||
|
} else if key.pressed && index == 9 {
|
||||||
|
channel_locks[9] = false;
|
||||||
|
}
|
||||||
|
if key.pressed && index == 10 {
|
||||||
|
channel_locks[10] = true;
|
||||||
|
} else if key.pressed && index == 11 {
|
||||||
|
channel_locks[10] = false;
|
||||||
|
}
|
||||||
|
if key.pressed && index == 13 {
|
||||||
|
channel_locks[11] = true;
|
||||||
|
} else if key.pressed && index == 14 {
|
||||||
|
channel_locks[11] = false;
|
||||||
|
}
|
||||||
|
if key.pressed && index == 7 {
|
||||||
|
channels[4] = ELRS_MAX;
|
||||||
|
}
|
||||||
|
if key.pressed && index == 12 {
|
||||||
|
channels[5] = ELRS_MAX;
|
||||||
|
}
|
||||||
|
if key.pressed && index == 6 {
|
||||||
|
channels[7] = ELRS_MAX;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update button state for ELRS channel 5-12
|
// Apply locking to ELRS channels
|
||||||
for (index, key) in matrix_keys.iter_mut().enumerate() {
|
|
||||||
if key.pressed
|
|
||||||
&& layout::ELRS_MAP[index] as usize >= layout::ElrsButton::CH5 as usize
|
|
||||||
&& layout::ELRS_MAP[index] as usize <= layout::ElrsButton::CH12 as usize
|
|
||||||
{
|
|
||||||
channels[layout::ELRS_MAP[index] as usize] = ELRS_MAX;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply locking to ELRS channel 5-12
|
|
||||||
for (index, lock_active) in channel_locks.iter().enumerate() {
|
for (index, lock_active) in channel_locks.iter().enumerate() {
|
||||||
if *lock_active {
|
if *lock_active {
|
||||||
channels[index] = ELRS_MAX;
|
channels[index] = ELRS_MAX;
|
||||||
|
|||||||
@ -90,12 +90,15 @@ pub const JOYSTICK_DESCRIPTOR: &[u8] = &[
|
|||||||
0xc0, // End Collection
|
0xc0, // End Collection
|
||||||
0x05, 0x09, // Usage Page (Button)
|
0x05, 0x09, // Usage Page (Button)
|
||||||
0x19, 0x01, // Usage Minimum (1)
|
0x19, 0x01, // Usage Minimum (1)
|
||||||
0x29, 0x20, // Usage Maximum (32)
|
0x29, 0x19, // Usage Maximum (25)
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
0x25, 0x01, // Logical Maximum (1)
|
0x25, 0x01, // Logical Maximum (1)
|
||||||
0x75, 0x01, // Report Size (1)
|
0x75, 0x01, // Report Size (1)
|
||||||
0x95, 0x20, // Report Count (32)
|
0x95, 0x19, // Report Count (25)
|
||||||
0x81, 0x02, // Input (Data, Variable, Absolute)
|
0x81, 0x02, // Input (Data, Variable, Absolute)
|
||||||
|
0x75, 0x01, // Report Size (1) PADDING
|
||||||
|
0x95, 0x07, // Report Count (7) PADDING
|
||||||
|
0x81, 0x03, // Input (Const, Variable, Absolute) PADDING
|
||||||
0x15, 0x00, // Logical Minimum (0)
|
0x15, 0x00, // Logical Minimum (0)
|
||||||
0x25, 0x07, // Logical Maximum (7)
|
0x25, 0x07, // Logical Maximum (7)
|
||||||
0x35, 0x00, // Physical Minimum (0)
|
0x35, 0x00, // Physical Minimum (0)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user