From 32be2229c9a2776514523a095213aeea2e53d367 Mon Sep 17 00:00:00 2001 From: Mike Parks Date: Mon, 16 Sep 2024 18:01:06 -0700 Subject: [PATCH 1/8] GamepadAuxState functionality (#1084) * Started implementation of GamepadAuxState to store values that are outside of normal Gamepad button/analog functions, such as IMU (accelerometer, gyroscope) and rumble state. * Added gyroscope values for future Wii Motion Plus implementation. * Reduced additional PS sensor fields until necessary. Renamed PS gyro_accel_misc to sensor_data. Changed sensor fields to u16. * Refactored Wii data handler & added Motion Plus support * Implemented rumble, gyro, and accelerometer data structure usage if enabled * Refactor how Motion Plus and standard Extensions are detected. Prioritize Motion Plus if both are available. * Added missing report types and OUT report endpoint to PS4. * Added UDraw Wii Tablet support to WiiExtension library * Implemented touch counter for PS4 touchpad usage. * Added "active" state to Aux sensors to be used when a sensor is enabled, but not actively sending data. * Added sensor types for relative values * Added A3 & A4 button bindings to keyboard host Keyboard host now implements mouse bindings for left, middle, right buttons Relative mouse movements stored in the GamepadAux mouse sensor for later usage Added exclusion list for KeyboardMapper control to filter out unused entries * Temporarily removed GamepadAuxState from gamepad.h to resolve conflict * Removed blank space for resolving merge * Reimplemented GamepadAuxState in gamepad.h * Changed length checks on PS4 get reports to return max of request value and array size. * Replaced GamepadRumbleState with GamepadAuxHaptics structures. Implemented haptics control in PS4 and OGXbox modes. * Fix indentation on PS4 descriptors. Comment out debug outputs. * Added WiiExtension wrapper for new I2C interface Fixed initial states for MotionPlus gyro * Added PS4 accelerometer and gyrometer known range values * DS3 additions * Removed HID report repeating as this could cause incorrect report parsing to occur * Removed old quirks mode PS3 descriptors in favor of DS3 specific ones. This change would make PS3 mode specifically PS3, and standard HID/"DInput" should no longer use this mode. Still to do: better define and explain what each report blob is used for. * Updated PS3/PS4 device constants to not conflict with HID defines. Included state checking for Aux gyro and accel sensors. * Remove USB report repeat sample code * Added haptic enable state checks on most modes supporting it * Clean up debug code for PS4 expansion * Fix tabs for keyboard host mouse definitions * Started cleaning up naming of PS3 report IDs for documentation. Removed btaddr values for actual PS3 devices. * Removed hard-coded data for BT device details (0xF2) in favor of a data struct. Randomized BT addresses on start for 0xF2 and 0xF5 reports. * Update all drivers to remove feature data parameter in process(). Added player ID & LED data to main Aux structure. Set default values of zero on integer Aux values. Deprecated Storage::*FeatureData methods in favor of Aux values. * Updated DRV8833 to validate left/right motor pins and enable the Aux haptics if valid. * Aligned forced player number to new Aux storage, but functionally still not working as expected. * Updated XInput, PS3 & PS4 feature outputs to store LED & rumble status on processed gamepad. * Added new speed settings and a custom blink timing mode to PlayerLEDs. Added on/off blink timing to DS4 lightbar usage in RGB PLEDs. * Added PS4 configuration switch between Console and Emulation modes * Added PS4 ID mode help text and included option in PS5 mode. * Removed XInput reference from Player LED as other modes now make use of it. * Set active state to true when Wii gyro/accel sensors are being fed data --- headers/addons/drv8833_rumble.h | 3 +- headers/addons/keyboard_host_listener.h | 17 + headers/addons/wiiext.h | 39 ++ headers/drivers/astro/AstroDriver.h | 2 +- headers/drivers/egret/EgretDriver.h | 2 +- headers/drivers/hid/HIDDriver.h | 2 +- headers/drivers/keyboard/KeyboardDriver.h | 2 +- headers/drivers/mdmini/MDMiniDriver.h | 2 +- headers/drivers/neogeo/NeoGeoDriver.h | 2 +- headers/drivers/net/NetDriver.h | 2 +- headers/drivers/pcengine/PCEngineDriver.h | 2 +- headers/drivers/ps3/PS3Descriptors.h | 493 ++++++++++++------ headers/drivers/ps3/PS3Driver.h | 9 +- headers/drivers/ps4/PS4Descriptors.h | 288 +++++++++- headers/drivers/ps4/PS4Driver.h | 17 +- headers/drivers/psclassic/PSClassicDriver.h | 2 +- headers/drivers/switch/SwitchDriver.h | 2 +- headers/drivers/xbone/XBOneDriver.h | 2 +- .../drivers/xboxog/XboxOriginalDescriptors.h | 1 + headers/drivers/xboxog/XboxOriginalDriver.h | 3 +- headers/drivers/xinput/XInputDriver.h | 5 +- headers/gamepad.h | 3 +- headers/gamepad/GamepadAuxState.h | 145 ++++++ headers/gamepad/GamepadState.h | 10 - headers/gpdriver.h | 2 +- .../i2c/wiiextension/wiiextension_dev.h | 2 +- headers/storagemanager.h | 4 - lib/PlayerLEDs/src/PlayerLEDs.cpp | 4 + lib/PlayerLEDs/src/PlayerLEDs.h | 44 +- lib/WiiExtension/CMakeLists.txt | 6 +- lib/WiiExtension/WiiExtension.cpp | 286 ++++++---- lib/WiiExtension/WiiExtension.h | 12 + lib/WiiExtension/extensions/ExtensionBase.cpp | 1 - lib/WiiExtension/extensions/ExtensionBase.h | 16 +- lib/WiiExtension/extensions/Extensions.h | 2 + .../extensions/MotionPlusExtension.cpp | 166 ++++++ .../extensions/MotionPlusExtension.h | 51 ++ .../extensions/NunchuckExtension.cpp | 6 +- .../extensions/UDrawExtension.cpp | 32 ++ lib/WiiExtension/extensions/UDrawExtension.h | 16 + proto/config.proto | 6 + proto/enums.proto | 8 + src/addons/drv8833_rumble.cpp | 50 +- src/addons/keyboard_host_listener.cpp | 108 +++- src/addons/neopicoleds.cpp | 200 ++++--- src/addons/playerleds.cpp | 102 ++-- src/addons/playernum.cpp | 15 +- src/addons/wiiext.cpp | 71 ++- src/config_utils.cpp | 5 + src/configs/webconfig.cpp | 16 + src/drivers/astro/AstroDriver.cpp | 2 +- src/drivers/egret/EgretDriver.cpp | 2 +- src/drivers/hid/HIDDriver.cpp | 2 +- src/drivers/keyboard/KeyboardDriver.cpp | 2 +- src/drivers/mdmini/MDMiniDriver.cpp | 2 +- src/drivers/neogeo/NeoGeoDriver.cpp | 2 +- src/drivers/net/NetDriver.cpp | 2 +- src/drivers/pcengine/PCEngineDriver.cpp | 2 +- src/drivers/ps3/PS3Driver.cpp | 380 ++++++++++---- src/drivers/ps4/PS4Driver.cpp | 282 ++++++++-- src/drivers/psclassic/PSClassicDriver.cpp | 2 +- src/drivers/switch/SwitchDriver.cpp | 2 +- src/drivers/xbone/XBOneDriver.cpp | 2 +- src/drivers/xboxog/XboxOriginalDriver.cpp | 18 +- src/drivers/xinput/XInputDriver.cpp | 89 +++- src/gamepad.cpp | 12 +- src/gp2040.cpp | 4 +- src/storagemanager.cpp | 15 - www/server/app.js | 4 + www/src/Addons/Keyboard.tsx | 120 ++++- www/src/Components/KeyboardMapper.jsx | 2 + www/src/Locales/en/AddonsConfig.jsx | 9 +- www/src/Locales/en/LedConfig.jsx | 2 +- www/src/Locales/en/SettingsPage.jsx | 8 + www/src/Pages/SettingsPage.jsx | 77 +++ 75 files changed, 2603 insertions(+), 727 deletions(-) create mode 100644 headers/gamepad/GamepadAuxState.h create mode 100644 lib/WiiExtension/extensions/MotionPlusExtension.cpp create mode 100644 lib/WiiExtension/extensions/MotionPlusExtension.h create mode 100644 lib/WiiExtension/extensions/UDrawExtension.cpp create mode 100644 lib/WiiExtension/extensions/UDrawExtension.h diff --git a/headers/addons/drv8833_rumble.h b/headers/addons/drv8833_rumble.h index 3000328f7..f71c966e2 100644 --- a/headers/addons/drv8833_rumble.h +++ b/headers/addons/drv8833_rumble.h @@ -5,6 +5,7 @@ #include #include "gpaddon.h" #include "gamepad/GamepadState.h" +#include "gamepad/GamepadAuxState.h" #ifndef DRV8833_RUMBLE_ENABLED #define DRV8833_RUMBLE_ENABLED 0 @@ -68,7 +69,7 @@ class DRV8833RumbleAddon : public GPAddon float dutyMin; float dutyMax; uint32_t sysClock; - GamepadRumbleState currentRumbleState; + GamepadAuxHaptics currentRumbleState; }; #endif diff --git a/headers/addons/keyboard_host_listener.h b/headers/addons/keyboard_host_listener.h index 044a163fa..769d9cca2 100644 --- a/headers/addons/keyboard_host_listener.h +++ b/headers/addons/keyboard_host_listener.h @@ -38,7 +38,9 @@ class KeyboardHostListener : public USBListener { GamepadState _keyboard_host_state; bool _keyboard_host_enabled; uint8_t getKeycodeFromModifier(uint8_t modifier); + void preprocess_report(); void process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report); + void process_mouse_report(uint8_t dev_addr, hid_mouse_report_t const *report); KeyboardButtonMapping _keyboard_host_mapDpadUp; KeyboardButtonMapping _keyboard_host_mapDpadDown; @@ -58,9 +60,24 @@ class KeyboardHostListener : public USBListener { KeyboardButtonMapping _keyboard_host_mapButtonR3; KeyboardButtonMapping _keyboard_host_mapButtonA1; KeyboardButtonMapping _keyboard_host_mapButtonA2; + KeyboardButtonMapping _keyboard_host_mapButtonA3; + KeyboardButtonMapping _keyboard_host_mapButtonA4; uint8_t _keyboard_dev_addr; uint8_t _keyboard_instance; + + bool _mouse_host_enabled; + uint8_t _mouse_dev_addr; + uint8_t _mouse_instance; + + uint16_t mouseLeftMapping; + uint16_t mouseMiddleMapping; + uint16_t mouseRightMapping; + + int16_t mouseX = 0; + int16_t mouseY = 0; + int16_t mouseZ = 0; + bool mouseActive = false; }; #endif // _KeyboardHost_H_ \ No newline at end of file diff --git a/headers/addons/wiiext.h b/headers/addons/wiiext.h index b4f3a2535..9d81f4374 100644 --- a/headers/addons/wiiext.h +++ b/headers/addons/wiiext.h @@ -270,6 +270,28 @@ class WiiExtensionInput : public GPAddon { } } }, + { + WiiExtensionController::WII_EXTENSION_DRAWSOME, + { + { + {WiiButtons::WII_BUTTON_A, GAMEPAD_MASK_B2}, + {WiiButtons::WII_BUTTON_L, GAMEPAD_MASK_L2}, + {WiiButtons::WII_BUTTON_R, GAMEPAD_MASK_R2}, + }, + {} + } + }, + { + WiiExtensionController::WII_EXTENSION_UDRAW, + { + { + {WiiButtons::WII_BUTTON_A, GAMEPAD_MASK_B2}, + {WiiButtons::WII_BUTTON_L, GAMEPAD_MASK_L2}, + {WiiButtons::WII_BUTTON_R, GAMEPAD_MASK_R2}, + }, + {} + } + }, }; WiiExtensionConfig* currentConfig = NULL; @@ -295,6 +317,9 @@ class WiiExtensionInput : public GPAddon { bool dpadRight = false; bool isAnalogTriggers = false; + bool isGyroscope = false; + bool isAccelerometer = false; + bool isTouch = false; uint16_t triggerLeft = 0; uint16_t triggerRight = 0; @@ -314,6 +339,19 @@ class WiiExtensionInput : public GPAddon { uint16_t rightY = 0; uint16_t lastRightY = 0; + uint16_t accelerometerX = 0; + uint16_t accelerometerY = 0; + uint16_t accelerometerZ = 0; + + uint16_t gyroscopeX = 0; + uint16_t gyroscopeY = 0; + uint16_t gyroscopeZ = 0; + + uint16_t touchX = 0; + uint16_t touchY = 0; + uint16_t touchZ = 0; + bool touchPressed = false; + std::map> analogChanges = { {WII_ANALOG_TYPE_LEFT_STICK_X,{}}, {WII_ANALOG_TYPE_LEFT_STICK_Y,{}}, @@ -344,6 +382,7 @@ class WiiExtensionInput : public GPAddon { void setButtonState(bool buttonState, uint16_t buttonMask); void queueAnalogChange(uint16_t analogInput, uint16_t analogValue, uint16_t lastAnalogValue); void updateAnalogState(); + void updateMotionState(); void reloadConfig(); uint16_t getAverage(std::vector const& changes); diff --git a/headers/drivers/astro/AstroDriver.h b/headers/drivers/astro/AstroDriver.h index 5fab52078..418cf3461 100644 --- a/headers/drivers/astro/AstroDriver.h +++ b/headers/drivers/astro/AstroDriver.h @@ -12,7 +12,7 @@ class AstroDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/egret/EgretDriver.h b/headers/drivers/egret/EgretDriver.h index 74796ccdb..ca9529f3b 100644 --- a/headers/drivers/egret/EgretDriver.h +++ b/headers/drivers/egret/EgretDriver.h @@ -12,7 +12,7 @@ class EgretDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/hid/HIDDriver.h b/headers/drivers/hid/HIDDriver.h index a0ce70ffc..fb85db5fc 100644 --- a/headers/drivers/hid/HIDDriver.h +++ b/headers/drivers/hid/HIDDriver.h @@ -12,7 +12,7 @@ class HIDDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/keyboard/KeyboardDriver.h b/headers/drivers/keyboard/KeyboardDriver.h index c3b25e816..11f5286b9 100644 --- a/headers/drivers/keyboard/KeyboardDriver.h +++ b/headers/drivers/keyboard/KeyboardDriver.h @@ -12,7 +12,7 @@ class KeyboardDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/mdmini/MDMiniDriver.h b/headers/drivers/mdmini/MDMiniDriver.h index 88dfc8099..d9f21cf27 100644 --- a/headers/drivers/mdmini/MDMiniDriver.h +++ b/headers/drivers/mdmini/MDMiniDriver.h @@ -12,7 +12,7 @@ class MDMiniDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/neogeo/NeoGeoDriver.h b/headers/drivers/neogeo/NeoGeoDriver.h index a4920fec4..fa9987f1c 100644 --- a/headers/drivers/neogeo/NeoGeoDriver.h +++ b/headers/drivers/neogeo/NeoGeoDriver.h @@ -12,7 +12,7 @@ class NeoGeoDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/net/NetDriver.h b/headers/drivers/net/NetDriver.h index 616e5084f..e448d2f92 100644 --- a/headers/drivers/net/NetDriver.h +++ b/headers/drivers/net/NetDriver.h @@ -11,7 +11,7 @@ class NetDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/pcengine/PCEngineDriver.h b/headers/drivers/pcengine/PCEngineDriver.h index 655d84805..9c653e0d8 100644 --- a/headers/drivers/pcengine/PCEngineDriver.h +++ b/headers/drivers/pcengine/PCEngineDriver.h @@ -12,7 +12,7 @@ class PCEngineDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/ps3/PS3Descriptors.h b/headers/drivers/ps3/PS3Descriptors.h index 6d7ae2fa0..734f0c015 100644 --- a/headers/drivers/ps3/PS3Descriptors.h +++ b/headers/drivers/ps3/PS3Descriptors.h @@ -13,8 +13,12 @@ // Windows, even though the driver is supplied by Microsoft, an // INF file is needed to load the driver. These numbers need to // match the INF file. -#define VENDOR_ID 0x10C4 -#define PRODUCT_ID 0x82C0 +//#define PS3_VENDOR_ID 0x10C4 +//#define PS3_PRODUCT_ID 0x82C0 + +// DS3 Sixaxis +#define PS3_VENDOR_ID 0x054C +#define PS3_PRODUCT_ID 0x0268 /************************************************************************** * @@ -23,6 +27,7 @@ **************************************************************************/ #define ENDPOINT0_SIZE 64 +#define PS3_FEATURES_SIZE 48 #define GAMEPAD_INTERFACE 0 #define GAMEPAD_ENDPOINT 1 @@ -60,66 +65,191 @@ // HID analog sticks only report 8 bits #define PS3_JOYSTICK_MIN 0x00 -#define PS3_JOYSTICK_MID 0x80 +#define PS3_JOYSTICK_MID 0x7F #define PS3_JOYSTICK_MAX 0xFF +#define PS3_CENTER_SIXAXIS 0xFF01 + +typedef enum { + PS3_FEATURE_01 = 0x01, + PS3_FEATURE_EF = 0xEF, + PS3_GET_PAIRING_INFO = 0xF2, + PS3_FEATURE_F4 = 0xF4, + PS3_FEATURE_F5 = 0xF5, + PS3_FEATURE_F7 = 0xF7, + PS3_FEATURE_F8 = 0xF8, +} PS3ReportTypes; + +typedef enum { + PS3_PLUGGED = 0x02, + PS3_UNPLUGGED = 0x03 +} PS3PluggedInState; + +typedef enum { + PS3_POWER_CHARGING = 0xEE, + PS3_POWER_NOT_CHARGING = 0xF1, + PS3_POWER_SHUTDOWN = 0x01, + PS3_POWER_DISCHARGING = 0x02, + PS3_POWER_LOW = 0x03, + PS3_POWER_HIGH = 0x04, + PS3_POWER_FULL = 0x05, +} PS3PowerState; + +typedef enum { + PS3_WIRED_RUMBLE = 0x10, + PS3_WIRED_NO_RUMBLE = 0x12, + PS3_WIRELESS_RUMBLE = 0x14, + PS3_WIRELESS_NO_RUMBLE = 0x16, +} PS3WiredState; + typedef struct __attribute((packed, aligned(1))) { // digital buttons, 0 = off, 1 = on + // 0 + uint8_t reportID; + // 1 + uint8_t reserved; + + // 2 + uint8_t select_btn : 1; + uint8_t l3_btn : 1; + uint8_t r3_btn : 1; + uint8_t start_btn : 1; + + uint8_t dpad_up : 1; + uint8_t dpad_right : 1; + uint8_t dpad_down : 1; + uint8_t dpad_left : 1; + + // 3 + uint8_t l2_btn : 1; + uint8_t r2_btn : 1; + uint8_t l1_btn : 1; + uint8_t r1_btn : 1; + + uint8_t triangle_btn : 1; + uint8_t circle_btn : 1; + uint8_t cross_btn : 1; + uint8_t square_btn : 1; + + // 4 + uint8_t ps_btn : 1; + uint8_t tp_btn : 1; + uint8_t : 6; + + // 5 + uint8_t : 8; + + // left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down + // 6 + uint8_t l_x_axis; + // 7 + uint8_t l_y_axis; + // 8 + uint8_t r_x_axis; + // 9 + uint8_t r_y_axis; + // 10 + uint8_t : 8; + + // 11 + uint8_t : 8; + + // 12 + uint8_t movePowerStatus : 8; + + // 13 + uint8_t : 8; + + // button analog values for the d-pad. + // 14 + uint8_t up_axis; + // 15 + uint8_t right_axis; + // 16 + uint8_t down_axis; + // 17 + uint8_t left_axis; + + // button axis, 0x00 = unpressed, 0xff = fully pressed + // 18 + uint8_t l2_axis; + // 19 + uint8_t r2_axis; + // 20 + uint8_t l1_axis; + // 21 + uint8_t r1_axis; + + // 22 + uint8_t triangle_axis; + // 23 + uint8_t circle_axis; + // 24 + uint8_t cross_axis; + // 25 + uint8_t square_axis; + + // 26 + uint8_t reserved2[3]; - uint8_t square_btn : 1; - uint8_t cross_btn : 1; - uint8_t circle_btn : 1; - uint8_t triangle_btn : 1; - - uint8_t l1_btn : 1; - uint8_t r1_btn : 1; - uint8_t l2_btn : 1; - uint8_t r2_btn : 1; - - uint8_t select_btn : 1; - uint8_t start_btn : 1; - uint8_t l3_btn : 1; - uint8_t r3_btn : 1; - - uint8_t ps_btn : 1; - uint8_t tp_btn : 1; -// uint8_t l2_btn_alt : 1; - -// uint8_t r2_btn_alt : 1; - uint8_t : 2; - - // digital direction, use the dir_* constants(enum) - // 8 = center, 0 = up, 1 = up/right, 2 = right, 3 = right/down - // 4 = down, 5 = down/left, 6 = left, 7 = left/up - - uint8_t direction; - - // left and right analog sticks, 0x00 left/up, 0x80 middle, 0xff right/down - - uint8_t l_x_axis; - uint8_t l_y_axis; - uint8_t r_x_axis; - uint8_t r_y_axis; - - // button analog values for the d-pad. - uint8_t right_axis; - uint8_t left_axis; - uint8_t up_axis; - uint8_t down_axis; - - // button axis, 0x00 = unpressed, 0xff = fully pressed - - uint8_t triangle_axis; - uint8_t circle_axis; - uint8_t cross_axis; - uint8_t square_axis; - - uint8_t l1_axis; - uint8_t r1_axis; - uint8_t l2_axis; - uint8_t r2_axis; -} PS3Report; + // 29 + uint8_t plugged; + // 30 + uint8_t powerStatus; + + // 31 + uint8_t rumbleStatus; + + // 32 + uint8_t reserved3[9]; + + // 40 + uint16_t accelerometer_x; + // 42 + uint16_t accelerometer_y; + // 44 + uint16_t accelerometer_z; + // 46 + uint16_t gyroscope_z; + + // 48 + uint16_t reserved4; +} PS3Report; // 49 length + +typedef struct __attribute((packed, aligned(1))) +{ + // 0 + uint8_t reserved; + + // 1 + uint8_t rightMotorDuration; + // 2 + uint8_t rightMotorPower; + + // 3 + uint8_t leftMotorDuration; + // 4 + uint8_t leftMotorPower; + + // 5 + uint8_t reserved2[4]; + + // 9 + uint8_t playerLED : 4; + uint8_t : 4; + + // 10 + uint8_t reserved3[38]; +} PS3Features; // 48 length + +typedef struct __attribute((packed, aligned(1))) +{ + uint8_t reserved[2]; + uint8_t deviceAddress[7]; // leading zero followed by address + uint8_t hostAddress[7]; // leading zero followed by address + uint8_t reserved1; +} PS3BTInfo; static const uint8_t ps3_string_language[] = { 0x09, 0x04 }; static const uint8_t ps3_string_manufacturer[] = "Open Stick Community"; @@ -136,128 +266,155 @@ static const uint8_t *ps3_string_descriptors[] __attribute__((unused)) = static const uint8_t ps3_device_descriptor[] = { - 18, // bLength - 1, // bDescriptorType - 0x00, 0x02, // bcdUSB - 0, // bDeviceClass - 0, // bDeviceSubClass - 0, // bDeviceProtocol - ENDPOINT0_SIZE, // bMaxPacketSize0 - LSB(VENDOR_ID), MSB(VENDOR_ID), // idVendor - LSB(PRODUCT_ID), MSB(PRODUCT_ID), // idProduct - 0x00, 0x01, // bcdDevice - 1, // iManufacturer - 2, // iProduct - 0, // iSerialNumber - 1 // bNumConfigurations + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0x00, // bDeviceClass (Use class information in the Interface Descriptors) + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + 0x40, // bMaxPacketSize0 64 + LSB(PS3_VENDOR_ID), MSB(PS3_VENDOR_ID), // idVendor + LSB(PS3_PRODUCT_ID), MSB(PS3_PRODUCT_ID), // idProduct + 0x00, 0x01, // bcdDevice 1.00 + 0x01, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x00, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 }; static const uint8_t ps3_report_descriptor[] = { - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x09, 0x05, // USAGE (Gamepad) - 0xa1, 0x01, // COLLECTION (Application) - 0x15, 0x00, // LOGICAL_MINIMUM (0) - 0x25, 0x01, // LOGICAL_MAXIMUM (1) - 0x35, 0x00, // PHYSICAL_MINIMUM (0) - 0x45, 0x01, // PHYSICAL_MAXIMUM (1) - 0x75, 0x01, // REPORT_SIZE (1) - 0x95, 0x0e, // REPORT_COUNT (13) - 0x05, 0x09, // USAGE_PAGE (Button) - 0x19, 0x01, // USAGE_MINIMUM (Button 1) - 0x29, 0x0e, // USAGE_MAXIMUM (Button 13) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x95, 0x02, // REPORT_COUNT (3) - 0x81, 0x01, // INPUT (Cnst,Ary,Abs) - 0x05, 0x01, // USAGE_PAGE (Generic Desktop) - 0x25, 0x07, // LOGICAL_MAXIMUM (7) - 0x46, 0x3b, 0x01, // PHYSICAL_MAXIMUM (315) - 0x75, 0x04, // REPORT_SIZE (4) - 0x95, 0x01, // REPORT_COUNT (1) - 0x65, 0x14, // UNIT (Eng Rot:Angular Pos) - 0x09, 0x39, // USAGE (Hat switch) - 0x81, 0x42, // INPUT (Data,Var,Abs,Null) - 0x65, 0x00, // UNIT (None) - 0x95, 0x01, // REPORT_COUNT (1) - 0x81, 0x01, // INPUT (Cnst,Ary,Abs) - 0x26, 0xff, 0x00, // LOGICAL_MAXIMUM (255) - 0x46, 0xff, 0x00, // PHYSICAL_MAXIMUM (255) - 0x09, 0x30, // USAGE (X) - 0x09, 0x31, // USAGE (Y) - 0x09, 0x32, // USAGE (Z) - 0x09, 0x35, // USAGE (Rz) - 0x75, 0x08, // REPORT_SIZE (8) - 0x95, 0x04, // REPORT_COUNT (6) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x06, 0x00, 0xff, // USAGE_PAGE (Vendor Specific) - 0x09, 0x20, // Unknown - 0x09, 0x21, // Unknown - 0x09, 0x22, // Unknown - 0x09, 0x23, // Unknown - 0x09, 0x24, // Unknown - 0x09, 0x25, // Unknown - 0x09, 0x26, // Unknown - 0x09, 0x27, // Unknown - 0x09, 0x28, // Unknown - 0x09, 0x29, // Unknown - 0x09, 0x2a, // Unknown - 0x09, 0x2b, // Unknown - 0x95, 0x0c, // REPORT_COUNT (12) - 0x81, 0x02, // INPUT (Data,Var,Abs) - 0x0a, 0x21, 0x26, // Unknown - 0x95, 0x08, // REPORT_COUNT (8) - 0xb1, 0x02, // FEATURE (Data,Var,Abs) - 0xc0 // END_COLLECTION + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x04, // Usage (Joystick) + 0xA1, 0x01, // Collection (Physical) + 0xA1, 0x02, // Collection (Application) + 0x85, 0x01, // Report ID (1) + 0x75, 0x08, // Report Size (8) + 0x95, 0x01, // Report Count (1) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: reserved byte + 0x75, 0x01, // Report Size (1) + 0x95, 0x13, // Report Count (19) + 0x15, 0x00, // Logical Minimum (0) + 0x25, 0x01, // Logical Maximum (1) + 0x35, 0x00, // Physical Minimum (0) + 0x45, 0x01, // Physical Maximum (1) + 0x05, 0x09, // Usage Page (Button) + 0x19, 0x01, // Usage Minimum (0x01) + 0x29, 0x13, // Usage Maximum (0x13) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x01, // Report Size (1) + 0x95, 0x0D, // Report Count (13) + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: 32 bit integer, where 0:18 are buttons and 19:31 are reserved + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0xFF, 0x00, // Logical Maximum (255) + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x09, 0x01, // Usage (Pointer) + 0xA1, 0x00, // Collection (Undefined) + 0x75, 0x08, // Report Size (8) + 0x95, 0x04, // Report Count (4) + 0x35, 0x00, // Physical Minimum (0) + 0x46, 0xFF, 0x00, // Physical Maximum (255) + 0x09, 0x30, // Usage (X) + 0x09, 0x31, // Usage (Y) + 0x09, 0x32, // Usage (Z) + 0x09, 0x35, // Usage (Rz) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + // NOTE: four joysticks + 0xC0, // End Collection + 0x05, 0x01, // Usage Page (Generic Desktop Ctrls) + 0x75, 0x08, // Report Size (8) + 0x95, 0x27, // Report Count (39) + 0x09, 0x01, // Usage (Pointer) + 0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0x91, 0x02, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0x02, // Report ID (2) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0xEE, // Report ID (238) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xA1, 0x02, // Collection (Application) + 0x85, 0xEF, // Report ID (239) + 0x75, 0x08, // Report Size (8) + 0x95, 0x30, // Report Count (48) + 0x09, 0x01, // Usage (Pointer) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0xC0, // End Collection + 0xC0, // End Collection }; static const uint8_t ps3_hid_descriptor[] = { - 0x09, // bLength - 0x21, // bDescriptorType (HID) - 0x11, 0x01, // bcdHID 1.11 - 0x00, // bCountryCode - 0x01, // bNumDescriptors - 0x22, // bDescriptorType[0] (HID) - sizeof(ps3_report_descriptor), 0x00, // wDescriptorLength[0] 90 + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.17 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x94, 0x00, // wDescriptorLength[0] 148 }; -#define CONFIG1_DESC_SIZE (9+9+9+7) static const uint8_t ps3_configuration_descriptor[] = { - // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 - 9, // bLength; - 2, // bDescriptorType; - LSB(CONFIG1_DESC_SIZE), // wTotalLength - MSB(CONFIG1_DESC_SIZE), - 1, // bNumInterfaces - 1, // bConfigurationValue - 0, // iConfiguration - 0x80, // bmAttributes - 50, // bMaxPower - // interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12 - 9, // bLength - 4, // bDescriptorType - GAMEPAD_INTERFACE, // bInterfaceNumber - 0, // bAlternateSetting - 1, // bNumEndpoints - 0x03, // bInterfaceClass (0x03 = HID) - 0x00, // bInterfaceSubClass (0x00 = No Boot) - 0x00, // bInterfaceProtocol (0x00 = No Protocol) - 0, // iInterface - // HID interface descriptor, HID 1.11 spec, section 6.2.1 - 9, // bLength - 0x21, // bDescriptorType - 0x11, 0x01, // bcdHID - 0, // bCountryCode - 1, // bNumDescriptors - 0x22, // bDescriptorType - sizeof(ps3_report_descriptor), // wDescriptorLength - 0, - // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 - 7, // bLength - 5, // bDescriptorType - GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress - 0x03, // bmAttributes (0x03=intr) - GAMEPAD_SIZE, 0, // wMaxPacketSize - 1 // bInterval (1 ms) + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x29, 0x00, // wTotalLength 41 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0x80, // bmAttributes + 0xFA, // bMaxPower 500mA + + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x03, // bInterfaceClass + 0x00, // bInterfaceSubClass + 0x00, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + 0x09, // bLength + 0x21, // bDescriptorType (HID) + 0x11, 0x01, // bcdHID 1.17 + 0x00, // bCountryCode + 0x01, // bNumDescriptors + 0x22, // bDescriptorType[0] (HID) + 0x94, 0x00, // wDescriptorLength[0] 148 + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x02, // bEndpointAddress (OUT/H2D) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x01, // bInterval 1 (unit depends on device speed) + + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x81, // bEndpointAddress (IN/D2H) + 0x03, // bmAttributes (Interrupt) + 0x40, 0x00, // wMaxPacketSize 64 + 0x01, // bInterval 1 (unit depends on device speed) }; diff --git a/headers/drivers/ps3/PS3Driver.h b/headers/drivers/ps3/PS3Driver.h index 9c32deeee..33f502d4a 100644 --- a/headers/drivers/ps3/PS3Driver.h +++ b/headers/drivers/ps3/PS3Driver.h @@ -12,7 +12,7 @@ class PS3Driver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); @@ -28,6 +28,13 @@ class PS3Driver : public GPDriver { private: uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; PS3Report ps3Report; + PS3Features ps3Features; + uint8_t lastFeatures[PS3_FEATURES_SIZE] = { }; + PS3BTInfo ps3BTInfo; + + // this is an identification byte from the H2D 0xEF feature report that needs to be the same + // in multiple D2H reports for the controller to function + uint8_t efByte; }; #endif // _PS3_DRIVER_H_ diff --git a/headers/drivers/ps4/PS4Descriptors.h b/headers/drivers/ps4/PS4Descriptors.h index 050dafdf7..2a3016fe6 100644 --- a/headers/drivers/ps4/PS4Descriptors.h +++ b/headers/drivers/ps4/PS4Descriptors.h @@ -10,17 +10,21 @@ #define PS4_ENDPOINT_SIZE 64 // Mayflash -//#define PS4_VENDOR_ID 0x33df -//#define PS4_PRODUCT_ID 0x0011 +//#define PS4_VENDOR_ID 0x33df +//#define PS4_PRODUCT_ID 0x0011 // Razer Panthera -#define PS4_VENDOR_ID 0x1532 -#define PS4_PRODUCT_ID 0x0401 +#define PS4_VENDOR_ID 0x1532 +#define PS4_PRODUCT_ID 0x0401 // Madcatz Fightstick Alpha PS4 //#define PS4_VENDOR_ID 0x0738 //#define PS4_PRODUCT_ID 0x8180 +// DS4 +#define DS4_VENDOR_ID 0x054C +#define DS4_PRODUCT_ID 0x09CC + /************************************************************************** * * Endpoint Buffer Configuration @@ -29,6 +33,8 @@ #define ENDPOINT0_SIZE 64 +#define PS4_FEATURES_SIZE 32 + #define GAMEPAD_INTERFACE 0 #define GAMEPAD_ENDPOINT 1 #define GAMEPAD_SIZE 64 @@ -74,6 +80,13 @@ #define PS4_TP_Y_MIN 0 #define PS4_TP_Y_MAX 943 +#define PS4_TP_MAX_COUNT 128 + +#define PS4_ACCEL_RES 8192 +#define PS4_ACCEL_RANGE (PS4_ACCEL_RES * 4) +#define PS4_GYRO_RES 1024 +#define PS4_GYRO_RANGE (PS4_GYRO_RES * 2048) + struct TouchpadXY { uint8_t counter : 7; uint8_t unpressed : 1; @@ -98,6 +111,92 @@ struct TouchpadData { TouchpadXY p2; }; +struct PSSensor { + int16_t x; + int16_t y; + int16_t z; +}; + +struct PSSensorData { + uint16_t battery; + PSSensor gyroscope; + PSSensor accelerometer; + uint8_t misc[4]; + uint8_t powerLevel : 4; + uint8_t charging : 1; + uint8_t headphones : 1; + uint8_t microphone : 1; + uint8_t extension : 1; + uint8_t extData0 : 1; + uint8_t extData1 : 1; + uint8_t notConnected : 1; + uint8_t extData3 : 5; + uint8_t misc2; +} __attribute__((packed)); + +typedef struct __attribute__((packed)) { + // 0 + uint8_t reportID; + + // 1 + uint8_t enableUpdateRumble : 1; + uint8_t enableUpdateLED : 1; + uint8_t enableUpdateLEDBlink : 1; + uint8_t enableUpdateExtData : 1; + uint8_t enableUpdateVolLeft : 1; + uint8_t enableUpdateVolRight : 1; + uint8_t enableUpdateVolMic : 1; + uint8_t enableUpdateVolSpeaker : 1; + + // 2 + uint8_t : 8; + + // 3 + uint8_t unknown0; + + // 4 + uint8_t rumbleRight; + + // 5 + uint8_t rumbleLeft; + + // 6 + uint8_t ledRed; + + // 7 + uint8_t ledGreen; + + // 8 + uint8_t ledBlue; + + // 9 + uint8_t ledBlinkOn; + + // 10 + uint8_t ledBlinkOff; + + // 11 + uint8_t extData[8]; + + // 19 + uint8_t volumeLeft; // 0x00-0x4F + + // 20 + uint8_t volumeRight; // 0x00-0x4F + + // 21 + uint8_t volumeMic; // 0x01-0x4F, 0x00 is special state + + // 22 + uint8_t volumeSpeaker; // 0x00-0x4F + + // 23 + uint8_t unknownAudio; + + // 24 + uint8_t padding[8]; +} PS4FeatureOutputReport; + typedef struct __attribute__((packed)) { uint8_t report_id; uint8_t left_stick_x; @@ -133,7 +232,8 @@ typedef struct __attribute__((packed)) { // 16 bit timing counter uint16_t axis_timing; - uint8_t gyro_accel_misc[21]; + PSSensorData sensor_data; + uint8_t touchpad_active : 2; uint8_t padding : 6; uint8_t tpad_increment; @@ -237,6 +337,166 @@ static const uint8_t ps4_report_descriptor[] = 0x0A, 0x21, 0x27, // Usage (0x2721) 0x95, 0x2F, // Report Count (47) 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + + 0x85, 0x02, // Report ID (2) + 0x09, 0x24, // Usage (0x24) + 0x95, 0x24, // Report Count (36) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x08, // Report ID (8) + 0x09, 0x25, // Usage (0x25) + 0x95, 0x03, // Report Count (3) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x10, // Report ID (16) + 0x09, 0x26, // Usage (0x26) + 0x95, 0x04, // Report Count (4) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x11, // Report ID (17) + 0x09, 0x27, // Usage (0x27) + 0x95, 0x02, // Report Count (2) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x12, // Report ID (18) + 0x06, 0x02, 0xFF, // Usage Page (Vendor Defined 0xFF02) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x0F, // Report Count (15) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x13, // Report ID (19) + 0x09, 0x22, // Usage (0x22) + 0x95, 0x16, // Report Count (22) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x14, // Report ID (20) + 0x06, 0x05, 0xFF, // Usage Page (Vendor Defined 0xFF05) + 0x09, 0x20, // Usage (0x20) + 0x95, 0x10, // Report Count (16) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x15, // Report ID (21) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x2C, // Report Count (44) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x06, 0x80, 0xFF, // Usage Page (Vendor Defined 0xFF80) + 0x85, 0x80, // Report ID (128) + 0x09, 0x20, // Usage (0x20) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x81, // Report ID (129) + 0x09, 0x21, // Usage (0x21) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x82, // Report ID (130) + 0x09, 0x22, // Usage (0x22) + 0x95, 0x05, // Report Count (5) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x83, // Report ID (131) + 0x09, 0x23, // Usage (0x23) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x84, // Report ID (132) + 0x09, 0x24, // Usage (0x24) + 0x95, 0x04, // Report Count (4) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x85, // Report ID (133) + 0x09, 0x25, // Usage (0x25) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x86, // Report ID (134) + 0x09, 0x26, // Usage (0x26) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x87, // Report ID (135) + 0x09, 0x27, // Usage (0x27) + 0x95, 0x23, // Report Count (35) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x88, // Report ID (136) + 0x09, 0x28, // Usage (0x28) + 0x95, 0x22, // Report Count (34) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x89, // Report ID (137) + 0x09, 0x29, // Usage (0x29) + 0x95, 0x02, // Report Count (2) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x90, // Report ID (144) + 0x09, 0x30, // Usage (0x30) + 0x95, 0x05, // Report Count (5) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x91, // Report ID (145) + 0x09, 0x31, // Usage (0x31) + 0x95, 0x03, // Report Count (3) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x92, // Report ID (146) + 0x09, 0x32, // Usage (0x32) + 0x95, 0x03, // Report Count (3) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0x93, // Report ID (147) + 0x09, 0x33, // Usage (0x33) + 0x95, 0x0C, // Report Count (12) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA0, // Report ID (160) + 0x09, 0x40, // Usage (0x40) + 0x95, 0x06, // Report Count (6) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA1, // Report ID (161) + 0x09, 0x41, // Usage (0x41) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA2, // Report ID (162) + 0x09, 0x42, // Usage (0x42) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA3, // Report ID (163) + 0x09, 0x43, // Usage (0x43) + 0x95, 0x30, // Report Count (48) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA4, // Report ID (164) + 0x09, 0x44, // Usage (0x44) + 0x95, 0x0D, // Report Count (13) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA5, // Report ID (165) + 0x09, 0x45, // Usage (0x45) + 0x95, 0x15, // Report Count (21) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA6, // Report ID (166) + 0x09, 0x46, // Usage (0x46) + 0x95, 0x15, // Report Count (21) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA7, // Report ID (247) + 0x09, 0x4A, // Usage (0x4A) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA8, // Report ID (250) + 0x09, 0x4B, // Usage (0x4B) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xA9, // Report ID (251) + 0x09, 0x4C, // Usage (0x4C) + 0x95, 0x08, // Report Count (8) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAA, // Report ID (252) + 0x09, 0x4E, // Usage (0x4E) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAB, // Report ID (253) + 0x09, 0x4F, // Usage (0x4F) + 0x95, 0x39, // Report Count (57) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAC, // Report ID (254) + 0x09, 0x50, // Usage (0x50) + 0x95, 0x39, // Report Count (57) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAD, // Report ID (255) + 0x09, 0x51, // Usage (0x51) + 0x95, 0x0B, // Report Count (11) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAE, // Report ID (256) + 0x09, 0x52, // Usage (0x52) + 0x95, 0x01, // Report Count (1) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xAF, // Report ID (175) + 0x09, 0x53, // Usage (0x53) + 0x95, 0x02, // Report Count (2) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + 0x85, 0xB0, // Report ID (176) + 0x09, 0x54, // Usage (0x54) + 0x95, 0x3F, // Report Count (63) + 0xB1, 0x02, // Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) 0xC0, // End Collection 0x06, 0xF0, 0xFF, // Usage Page (Vendor Defined 0xFFF0) @@ -269,17 +529,18 @@ static const uint8_t ps4_hid_descriptor[] = 0x00, // bCountryCode 0x01, // bNumDescriptors 0x22, // bDescriptorType[0] (HID) - sizeof(ps4_report_descriptor), 0x00, // wDescriptorLength[0] 90 + //sizeof(ps4_report_descriptor), 0x00, // wDescriptorLength[0] 90 + LSB(sizeof(ps4_report_descriptor)), MSB(sizeof(ps4_report_descriptor)) }; -#define CONFIG1_DESC_SIZE (9+9+9+7) +#define PS4_CONFIG1_DESC_SIZE (9+9+9+7+7) static const uint8_t ps4_configuration_descriptor[] = { // configuration descriptor, USB spec 9.6.3, page 264-266, Table 9-10 9, // bLength; 2, // bDescriptorType; - LSB(CONFIG1_DESC_SIZE), // wTotalLength - MSB(CONFIG1_DESC_SIZE), + LSB(PS4_CONFIG1_DESC_SIZE), // wTotalLength + MSB(PS4_CONFIG1_DESC_SIZE), 1, // bNumInterfaces 1, // bConfigurationValue 0, // iConfiguration @@ -290,7 +551,7 @@ static const uint8_t ps4_configuration_descriptor[] = 4, // bDescriptorType GAMEPAD_INTERFACE, // bInterfaceNumber 0, // bAlternateSetting - 1, // bNumEndpoints + 2, // bNumEndpoints 0x03, // bInterfaceClass (0x03 = HID) 0x00, // bInterfaceSubClass (0x00 = No Boot) 0x00, // bInterfaceProtocol (0x00 = No Protocol) @@ -302,13 +563,14 @@ static const uint8_t ps4_configuration_descriptor[] = 0, // bCountryCode 1, // bNumDescriptors 0x22, // bDescriptorType - sizeof(ps4_report_descriptor), // wDescriptorLength - 0, + LSB(sizeof(ps4_report_descriptor)), // wDescriptorLength + MSB(sizeof(ps4_report_descriptor)), // endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13 7, // bLength 5, // bDescriptorType GAMEPAD_ENDPOINT | 0x80, // bEndpointAddress 0x03, // bmAttributes (0x03=intr) GAMEPAD_SIZE, 0, // wMaxPacketSize - 1 // bInterval (1 ms) + 1, // bInterval (1 ms) + 0x07, 0x05, 0x03, 0x03, 0x40, 0x00, 0x01 }; diff --git a/headers/drivers/ps4/PS4Driver.h b/headers/drivers/ps4/PS4Driver.h index 02cfe0fcf..d13d65e5c 100644 --- a/headers/drivers/ps4/PS4Driver.h +++ b/headers/drivers/ps4/PS4Driver.h @@ -23,7 +23,13 @@ typedef enum { typedef enum { + PS4_GET_CALIBRATION = 0x02, // PS4 Controller Calibration PS4_DEFINITION = 0x03, // PS4 Controller Definition + PS4_SET_FEATURE_STATE = 0x05, // PS4 Controller Features + PS4_GET_MAC_ADDRESS = 0x12, // PS4 Controller MAC + PS4_SET_HOST_MAC = 0x13, // Set Host MAC + PS4_SET_USB_BT_CONTROL = 0x14, // Set USB/BT Control Mode + PS4_GET_VERSION_DATE = 0xA3, // PS4 Controller Version & Date PS4_SET_AUTH_PAYLOAD = 0xF0, // Set Auth Payload PS4_GET_SIGNATURE_NONCE = 0xF1, // Get Signature Nonce PS4_GET_SIGNING_STATE = 0xF2, // Get Signing State @@ -43,7 +49,7 @@ class PS4Driver : public GPDriver { public: PS4Driver(uint32_t type): controllerType(type) {} virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux(); virtual void processAux(); virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); @@ -67,10 +73,19 @@ class PS4Driver : public GPDriver { uint8_t cur_nonce_id; PS4Report ps4Report; TouchpadData touchpadData; + PSSensorData sensorData; uint32_t last_report_timer; uint8_t send_nonce_part; uint32_t controllerType; GPAuthDriver * authDriver; + bool pointOneTouched = false; + bool pointTwoTouched = false; + uint8_t touchCounter; + + PS4FeatureOutputReport ps4Features; + uint8_t lastFeatures[PS4_FEATURES_SIZE] = { }; + + uint8_t deviceDescriptor[sizeof(ps4_device_descriptor)]; PS4State ps4State; bool authsent; diff --git a/headers/drivers/psclassic/PSClassicDriver.h b/headers/drivers/psclassic/PSClassicDriver.h index ea17bbf97..a8983d704 100644 --- a/headers/drivers/psclassic/PSClassicDriver.h +++ b/headers/drivers/psclassic/PSClassicDriver.h @@ -12,7 +12,7 @@ class PSClassicDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/switch/SwitchDriver.h b/headers/drivers/switch/SwitchDriver.h index 9b47dfa36..1fe0819f3 100644 --- a/headers/drivers/switch/SwitchDriver.h +++ b/headers/drivers/switch/SwitchDriver.h @@ -12,7 +12,7 @@ class SwitchDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/xbone/XBOneDriver.h b/headers/drivers/xbone/XBOneDriver.h index da5c2075e..2a568e5bb 100644 --- a/headers/drivers/xbone/XBOneDriver.h +++ b/headers/drivers/xbone/XBOneDriver.h @@ -14,7 +14,7 @@ class XBOneDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux(); virtual void processAux(); virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); diff --git a/headers/drivers/xboxog/XboxOriginalDescriptors.h b/headers/drivers/xboxog/XboxOriginalDescriptors.h index 6709f3a29..9bb9aa04b 100644 --- a/headers/drivers/xboxog/XboxOriginalDescriptors.h +++ b/headers/drivers/xboxog/XboxOriginalDescriptors.h @@ -4,6 +4,7 @@ #include "drivers/xboxog/xid/xid_driver.h" #define XboxOriginalReport USB_XboxGamepad_InReport_t +#define XboxOriginalReportOut USB_XboxGamepad_OutReport_t static const uint8_t xboxoriginal_string_language[] = { 0x09, 0x04 }; static const uint8_t xboxoriginal_string_manufacturer[] = ""; diff --git a/headers/drivers/xboxog/XboxOriginalDriver.h b/headers/drivers/xboxog/XboxOriginalDriver.h index ad37f1017..7e04d413c 100644 --- a/headers/drivers/xboxog/XboxOriginalDriver.h +++ b/headers/drivers/xboxog/XboxOriginalDriver.h @@ -12,7 +12,7 @@ class XboxOriginalDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux() {} virtual void processAux() {} virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); @@ -28,6 +28,7 @@ class XboxOriginalDriver : public GPDriver { private: uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; XboxOriginalReport xboxOriginalReport; + XboxOriginalReportOut xboxOriginalReportOut; }; #endif // _XBOX_ORIGINAL_DRIVER_H_ diff --git a/headers/drivers/xinput/XInputDriver.h b/headers/drivers/xinput/XInputDriver.h index aa08b1b02..f22016f24 100644 --- a/headers/drivers/xinput/XInputDriver.h +++ b/headers/drivers/xinput/XInputDriver.h @@ -11,10 +11,12 @@ #include "drivers/shared/gpauthdriver.h" #include "drivers/xinput/XInputDescriptors.h" +#define XINPUT_OUT_SIZE 32 + class XInputDriver : public GPDriver { public: virtual void initialize(); - virtual void process(Gamepad * gamepad, uint8_t * outBuffer); + virtual void process(Gamepad * gamepad); virtual void initializeAux(); virtual void processAux(); virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen); @@ -31,6 +33,7 @@ class XInputDriver : public GPDriver { uint8_t last_report[CFG_TUD_ENDPOINT0_SIZE] = { }; XInputReport xinputReport; GPAuthDriver * authDriver; + uint8_t featureBuffer[XINPUT_OUT_SIZE]; }; #endif diff --git a/headers/gamepad.h b/headers/gamepad.h index 5552f7ba7..a3a0c6d83 100644 --- a/headers/gamepad.h +++ b/headers/gamepad.h @@ -7,6 +7,7 @@ #include "enums.pb.h" #include "gamepad/GamepadState.h" +#include "gamepad/GamepadAuxState.h" #include "pico/stdlib.h" @@ -136,7 +137,7 @@ class Gamepad { GamepadState rawState; GamepadState state; GamepadState turboState; - GamepadRumbleState rumbleState; + GamepadAuxState auxState; GamepadButtonMapping *mapDpadUp; GamepadButtonMapping *mapDpadDown; GamepadButtonMapping *mapDpadLeft; diff --git a/headers/gamepad/GamepadAuxState.h b/headers/gamepad/GamepadAuxState.h new file mode 100644 index 000000000..d6e34fb67 --- /dev/null +++ b/headers/gamepad/GamepadAuxState.h @@ -0,0 +1,145 @@ +#pragma once + +#include +#include +using namespace std; +#include "GamepadEnums.h" +#include "enums.pb.h" + +#define GAMEPAD_AUX_MAX_TOUCHPADS 2 + +struct GamepadAuxColor +{ + uint8_t alpha = 0; + uint8_t red = 0; + uint8_t green = 0; + uint8_t blue = 0; +}; + +struct GamepadAuxPlayerID +{ + bool enabled = false; + bool active = false; + uint32_t value = 0; + uint32_t ledValue = 0; + uint32_t ledBlinkOn = 0; + uint32_t ledBlinkOff = 0; +}; + +struct GamepadAux1DSensor +{ + bool enabled = false; + bool active = false; + uint16_t x = 0; +}; + +struct GamepadAux1DRelativeSensor +{ + bool enabled = false; + bool active = false; + int16_t x = 0; +}; + +struct GamepadAux2DSensor +{ + bool enabled = false; + bool active = false; + uint16_t x = 0; + uint16_t y = 0; +}; + +struct GamepadAux2DRelativeSensor +{ + bool enabled = false; + bool active = false; + int16_t x = 0; + int16_t y = 0; +}; + +struct GamepadAux3DSensor +{ + bool enabled = false; + bool active = false; + uint16_t x = 0; + uint16_t y = 0; + uint16_t z = 0; +}; + +struct GamepadAux3DRelativeSensor +{ + bool enabled = false; + bool active = false; + int16_t x = 0; + int16_t y = 0; + int16_t z = 0; +}; + +struct GamepadAux4DSensor +{ + bool enabled = false; + bool active = false; + uint16_t x = 0; + uint16_t y = 0; + uint16_t z = 0; + uint16_t t = 0; +}; + +struct GamepadAux4DRelativeSensor +{ + bool enabled = false; + bool active = false; + int16_t x = 0; + int16_t y = 0; + int16_t z = 0; + int16_t t = 0; +}; + +struct GamepadAuxRGBSensor +{ + bool enabled = false; + bool active = false; + GamepadAuxColor color; + uint8_t durationOn = 0; + uint8_t durationOff = 0; +}; + +struct GamepadAuxHapticChannel +{ + bool enabled = false; + bool active = false; + uint16_t intensity = 0; +}; + +struct GamepadAuxSensors +{ + GamepadAux3DRelativeSensor mouse; + + GamepadAux3DSensor touchpad[GAMEPAD_AUX_MAX_TOUCHPADS]; + GamepadAux3DSensor gyroscope; + GamepadAux3DSensor accelerometer; + GamepadAux3DSensor magnetometer; + GamepadAux4DSensor timeOfFlight; + + GamepadAuxRGBSensor statusLight; +}; + +struct GamepadAuxHaptics +{ + GamepadAuxHapticChannel leftActuator; + GamepadAuxHapticChannel leftTrigger; + + GamepadAuxHapticChannel rightActuator; + GamepadAuxHapticChannel rightTrigger; +}; + +struct GamepadAuxState +{ + GamepadAuxPlayerID playerID; + + GamepadAuxColor primaryColor; + GamepadAuxColor secondaryColor; + + GamepadAuxSensors sensors; + + GamepadAuxHaptics haptics; +}; diff --git a/headers/gamepad/GamepadState.h b/headers/gamepad/GamepadState.h index 470aa3da8..c858edb34 100644 --- a/headers/gamepad/GamepadState.h +++ b/headers/gamepad/GamepadState.h @@ -133,16 +133,6 @@ const uint32_t buttonMasks[] = GAMEPAD_MASK_E12, }; -struct GamepadRumbleState -{ - // XInput General Motors - uint8_t leftMotor {0}; - uint8_t rightMotor {0}; - // GameInput Trigger Motors (XBOne) - uint8_t leftTrigger {0}; - uint8_t rightTrigger {0}; -}; - struct GamepadState { uint8_t dpad {0}; diff --git a/headers/gpdriver.h b/headers/gpdriver.h index b1a60697d..0ff75a2e5 100644 --- a/headers/gpdriver.h +++ b/headers/gpdriver.h @@ -27,7 +27,7 @@ class GPDriver { public: virtual void initialize() = 0; virtual void initializeAux() = 0; - virtual void process(Gamepad * gamepad, uint8_t * outBuffer) = 0; + virtual void process(Gamepad * gamepad) = 0; virtual void processAux() = 0; virtual uint16_t get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) = 0; virtual void set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) = 0; diff --git a/headers/interfaces/i2c/wiiextension/wiiextension_dev.h b/headers/interfaces/i2c/wiiextension/wiiextension_dev.h index e388337d4..182beff87 100644 --- a/headers/interfaces/i2c/wiiextension/wiiextension_dev.h +++ b/headers/interfaces/i2c/wiiextension/wiiextension_dev.h @@ -13,7 +13,7 @@ class WiiExtensionDevice : public WiiExtension, public I2CDeviceBase { WiiExtensionDevice(PeripheralI2C *i2cController, uint8_t addr = WII_EXTENSION_I2C_ADDR) : WiiExtension(i2cController, addr) {} std::vector getDeviceAddresses() const override { - return {WII_EXTENSION_I2C_ADDR}; + return {WII_EXTENSION_I2C_ADDR,WII_MOTIONPLUS_I2C_ADDR}; } }; diff --git a/headers/storagemanager.h b/headers/storagemanager.h index d332d1196..36a2d7e31 100644 --- a/headers/storagemanager.h +++ b/headers/storagemanager.h @@ -64,10 +64,6 @@ class Storage { void SetProcessedGamepad(Gamepad *); // MPGS Processed Gamepad Get/Set Gamepad * GetProcessedGamepad(); - void SetFeatureData(uint8_t *); // USB Feature Data Get/Set - void ClearFeatureData(); - uint8_t * GetFeatureData(); - void setProfile(const uint32_t); // profile support for multiple mappings void nextProfile(); void setFunctionalPinMappings(); diff --git a/lib/PlayerLEDs/src/PlayerLEDs.cpp b/lib/PlayerLEDs/src/PlayerLEDs.cpp index d107370c2..df3c99d5c 100644 --- a/lib/PlayerLEDs/src/PlayerLEDs.cpp +++ b/lib/PlayerLEDs/src/PlayerLEDs.cpp @@ -31,6 +31,10 @@ void PlayerLEDs::animate(PLEDAnimationState animationState) handleFade(); break; + case PLED_ANIM_BLINK_CUSTOM: + handleBlinkCustom(animationState.speedOn, animationState.speedOff); + break; + default: break; } diff --git a/lib/PlayerLEDs/src/PlayerLEDs.h b/lib/PlayerLEDs/src/PlayerLEDs.h index 3226f4018..07150579f 100644 --- a/lib/PlayerLEDs/src/PlayerLEDs.h +++ b/lib/PlayerLEDs/src/PlayerLEDs.h @@ -2,6 +2,7 @@ #define PLAYER_LEDS_H_ #include +#include #include #include "pico/time.h" @@ -26,6 +27,7 @@ typedef enum PLED_ANIM_BLINK, PLED_ANIM_CYCLE, PLED_ANIM_FADE, + PLED_ANIM_BLINK_CUSTOM, } PLEDAnimationType; const PLEDAnimationType ANIMATION_TYPES[] = @@ -36,22 +38,27 @@ const PLEDAnimationType ANIMATION_TYPES[] = PLED_ANIM_BLINK, PLED_ANIM_CYCLE, PLED_ANIM_FADE, + PLED_ANIM_BLINK_CUSTOM, }; typedef enum { - PLED_SPEED_OFF = 0, - PLED_SPEED_LUDICROUS = 20, - PLED_SPEED_FASTER = 100, - PLED_SPEED_FAST = 250, - PLED_SPEED_NORMAL = 500, - PLED_SPEED_SLOW = 1000, + PLED_SPEED_OFF = 0, + PLED_SPEED_PLAID = 10, + PLED_SPEED_LUDICROUS = 20, + PLED_SPEED_RIDICULOUS = 50, + PLED_SPEED_FASTER = 100, + PLED_SPEED_FAST = 250, + PLED_SPEED_NORMAL = 500, + PLED_SPEED_SLOW = 1000, } PLEDAnimationSpeed; const PLEDAnimationSpeed ANIMATION_SPEEDS[] = { PLED_SPEED_OFF, + PLED_SPEED_PLAID, PLED_SPEED_LUDICROUS, + PLED_SPEED_RIDICULOUS, PLED_SPEED_FASTER, PLED_SPEED_FAST, PLED_SPEED_NORMAL, @@ -63,6 +70,8 @@ struct PLEDAnimationState uint8_t state = 0; PLEDAnimationType animation; PLEDAnimationSpeed speed; + uint32_t speedOn = 0; + uint32_t speedOff = 0; }; class PlayerLEDs @@ -99,6 +108,29 @@ class PlayerLEDs nextAnimationTime = make_timeout_time_ms(speed); } + inline void handleBlinkCustom(uint32_t speed, uint32_t speedOff) + { + uint32_t nextSpeed = 0; + for (int i = 0; i < PLED_COUNT; i++) + { + if (speed > 0 && speedOff == 0) { + if (lastPledState[i]) { + currentPledState[i] = true; + nextSpeed = speed; + } + } else { + if (lastPledState[i]) { + currentPledState[i] = false; + nextSpeed = speed; + } else { + currentPledState[i] = true; + nextSpeed = speedOff; + } + } + } + nextAnimationTime = make_timeout_time_ms(nextSpeed); + } + inline void handleCycle(PLEDAnimationSpeed speed) { for (int i = 0; i < PLED_COUNT; i++) diff --git a/lib/WiiExtension/CMakeLists.txt b/lib/WiiExtension/CMakeLists.txt index 5dd20a2cc..6387dc526 100644 --- a/lib/WiiExtension/CMakeLists.txt +++ b/lib/WiiExtension/CMakeLists.txt @@ -4,10 +4,12 @@ add_library(WiiExtension extensions/ClassicExtension.cpp extensions/DrumExtension.cpp extensions/GuitarExtension.cpp + extensions/MotionPlusExtension.cpp extensions/NunchuckExtension.cpp extensions/TaikoExtension.cpp extensions/TurntableExtension.cpp + extensions/UDrawExtension.cpp ) -target_link_libraries(WiiExtension PUBLIC pico_stdlib PicoPeripherals) +target_link_libraries(WiiExtension PUBLIC pico_stdlib PicoPeripherals CRC32) target_include_directories(WiiExtension INTERFACE .) -target_include_directories(WiiExtension PUBLIC . PicoPeripherals) +target_include_directories(WiiExtension PUBLIC . PicoPeripherals CRC32) diff --git a/lib/WiiExtension/WiiExtension.cpp b/lib/WiiExtension/WiiExtension.cpp index 944297b97..5da384d29 100644 --- a/lib/WiiExtension/WiiExtension.cpp +++ b/lib/WiiExtension/WiiExtension.cpp @@ -13,162 +13,197 @@ void WiiExtension::begin() { #if WII_EXTENSION_DEBUG==true printf("WiiExtension::begin\n"); #endif + isReady = false; - reset(); } -void WiiExtension::start(){ +void WiiExtension::start() { uint8_t idRead[32]; uint8_t regWrite[16]; - int8_t result; + bool canContinue = true; + int8_t result, retryCtr; + // we need to determine which address gets used + if (isMotionPlus && !isExtension) { + // Motion Plus only #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::start\n"); - printf("WiiExtension::start isReady? %1d\n", isReady); + printf("WiiExtension::start Motion Plus detected\n"); #endif - - if (!isReady) return; - - regWrite[0] = 0xFA; - result = doI2CWrite(®Write[0], 1); - - extensionType = WII_EXTENSION_NONE; - - // continue if the write was successful - if (result > -1) { - doI2CRead(idRead, 6); - - if (idRead[2] != 0xA4 || idRead[3] != 0x20) return; - - if (idRead[5] == 0x00) { - extensionType = WII_EXTENSION_NUNCHUCK; - extensionController = new NunchuckExtension(); - } else if (idRead[5] == 0x01) { - extensionType = WII_EXTENSION_CLASSIC; - //if (idRead[0] == 0x01) { - // extensionType = WII_EXTENSION_CLASSIC_PRO; - //} - extensionController = new ClassicExtension(); - } else if (idRead[5] == 0x03) { - extensionType = WII_EXTENSION_GUITAR; - if (idRead[0] == 0x01) { - extensionType = WII_EXTENSION_DRUMS; - extensionController = new DrumExtension(); - } else if (idRead[0] == 0x03) { - extensionType = WII_EXTENSION_TURNTABLE; - extensionController = new TurntableExtension(); - } else { - extensionController = new GuitarExtension(); - } - } else if (idRead[5] == 0x11) { - extensionType = WII_EXTENSION_TAIKO; - extensionController = new TaikoExtension(); - } - - // in certain situations (eg. Nunchuck), setting the data type in reset() does not affect what this value will be - dataType = idRead[4]; - if (dataType == WII_DATA_TYPE_0) dataType = WII_DATA_TYPE_1; - extensionController->init(dataType); - extensionController->setExtensionType(extensionType); - + address = WII_MOTIONPLUS_I2C_ADDR; + } else if (!isMotionPlus && isExtension) { + // Extension only #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::Extension ID: %02x%02x %02x%02x %02x%02x\n", idRead[0], idRead[1], idRead[2], idRead[3], idRead[4], idRead[5]); - printf("WiiExtension::Data Format: %02x\n",idRead[4]); + printf("WiiExtension::start Extension detected\n"); #endif - - if (extensionType != WII_EXTENSION_NONE) { -#if WII_EXTENSION_CALIBRATION==true + address = WII_EXTENSION_I2C_ADDR; + } else if (isMotionPlus && isExtension) { + // Both attached #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::Calibration Data\n"); -#endif - regWrite[0] = 0x20; - doI2CWrite(regWrite, 1); - - doI2CRead(idRead, 16); - extensionController->calibrate(idRead); + printf("WiiExtension::start Motion Plus & Extension detected\n"); #endif - } else { + address = WII_MOTIONPLUS_I2C_ADDR; + } else { + // Nothing attached #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::Unknown Extension: %02x%02x %02x%02x %02x%02x\n", idRead[0], idRead[1], idRead[2], idRead[3], idRead[4], idRead[5]); + printf("WiiExtension::start No Extension devices detected\n"); #endif - } - - regWrite[0] = 0x00; - result = doI2CWrite(regWrite, 1); + canContinue = false; + isReady = false; + return; } -} -void WiiExtension::reset(){ - uint8_t regWrite[16]; - int8_t result; - bool canContinue = true; + if (!isReady) { +#if WII_EXTENSION_ENCRYPTION==false + if (canContinue) { + regWrite[0] = 0xF0; + regWrite[1] = 0x55; + result = doI2CWrite(regWrite, 2); + canContinue = (result > -1); #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::reset\n"); + printf("WiiExtension::start 0xF0? %1d\n", result); #endif + } else { + canContinue = false; + } + result = doI2CRead(regWrite, 1); - if (canContinue) { - result = doI2CTest(); - canContinue = (result == 1); - } + if (canContinue) { + regWrite[0] = 0xFB; + regWrite[1] = 0x00; + result = doI2CWrite(regWrite, 2); + canContinue = (result > -1); #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::i2C tested? %1d\n", result); + printf("WiiExtension::start 0xFB? %1d\n", result); +#endif + } else { + canContinue = false; + } #endif -#if WII_EXTENSION_ENCRYPTION==true - if (canContinue) { - regWrite[0] = 0x40; - regWrite[1] = 0x00; - result = doI2CWrite(regWrite, 2); - canContinue = (result > -1); - } + result = doI2CRead(regWrite, 1); + + if (canContinue) { + for (retryCtr = 0; retryCtr < 3; retryCtr++) { + // set data format + regWrite[0] = 0xFE; + if (isMotionPlus) { + //regWrite[1] = 0x04; + regWrite[1] = 0x05; + } else { + regWrite[1] = 0x03; + } + result = doI2CWrite(regWrite, 2); + +#if WII_EXTENSION_DEBUG==true + printf("WiiExtension::start 0xFE? %1d\n", result); #endif -#if WII_EXTENSION_ENCRYPTION==false - if (canContinue) { - regWrite[0] = 0xF0; - regWrite[1] = 0x55; - result = doI2CWrite(regWrite, 2); - canContinue = (result > -1); - } + // no error returned, check the device ID + if (result > -1) { + if (isMotionPlus) { + // switch address back + address = WII_EXTENSION_I2C_ADDR; + } + + result = doI2CRead(idRead, 2); + isReady = true; #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::reset 0xF0? %1d\n", result); + printf("WiiExtension::start 0xFE Check %02x %02x\n", idRead[0], idRead[1]); #endif + break; + } + } + } - if (canContinue) { - regWrite[0] = 0xFB; - regWrite[1] = 0x00; - result = doI2CWrite(regWrite, 2); - canContinue = (result > -1); + result = doI2CRead(regWrite, 1); } + #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::reset 0xFB? %1d\n", result); + printf("WiiExtension::start Is Ready? %01d\n", isReady); #endif + + if (isReady) { + // fetch the extension ID + regWrite[0] = 0xFA; + result = doI2CWrite(®Write[0], 1); + +#if WII_EXTENSION_DEBUG==true + printf("WiiExtension::start Extension Check? %1d\n", result); #endif - if (canContinue) { - // set data format - regWrite[0] = 0xFE; - regWrite[1] = 0x03; - result = doI2CWrite(regWrite, 2); - canContinue = (result > -1); - } + extensionType = WII_EXTENSION_NONE; + + // continue if the write was successful + if (result > -1) { + result = doI2CRead(idRead, 6); + + if (idRead[2] != 0xA4 || idRead[3] != 0x20) return; + + if (idRead[5] == 0x00) { + extensionType = WII_EXTENSION_NUNCHUCK; + extensionController = new NunchuckExtension(); + } else if (idRead[5] == 0x01) { + extensionType = WII_EXTENSION_CLASSIC; + //if (idRead[0] == 0x01) { + // extensionType = WII_EXTENSION_CLASSIC_PRO; + //} + extensionController = new ClassicExtension(); + } else if (idRead[5] == 0x03) { + extensionType = WII_EXTENSION_GUITAR; + if (idRead[0] == 0x01) { + extensionType = WII_EXTENSION_DRUMS; + extensionController = new DrumExtension(); + } else if (idRead[0] == 0x03) { + extensionType = WII_EXTENSION_TURNTABLE; + extensionController = new TurntableExtension(); + } else { + extensionController = new GuitarExtension(); + } + } else if (idRead[5] == 0x05) { + extensionType = WII_EXTENSION_MOTION_PLUS; + extensionController = new MotionPlusExtension(); + } else if (idRead[5] == 0x11) { + extensionType = WII_EXTENSION_TAIKO; + extensionController = new TaikoExtension(); + } else if (idRead[5] == 0x12) { + extensionType = WII_EXTENSION_UDRAW; + extensionController = new UDrawExtension(); + } + + // in certain situations (eg. Nunchuck), setting the data type in reset() does not affect what this value will be + dataType = idRead[4]; + if (dataType == WII_DATA_TYPE_0) dataType = WII_DATA_TYPE_1; + extensionController->init(dataType); + extensionController->setExtensionType(extensionType); #if WII_EXTENSION_DEBUG==true - printf("WiiExtension::reset 0xFE? %1d\n", result); + printf("WiiExtension::Extension ID: %02x%02x %02x%02x %02x%02x\n", idRead[0], idRead[1], idRead[2], idRead[3], idRead[4], idRead[5]); + printf("WiiExtension::Data Format: %02x\n",idRead[4]); #endif - if (canContinue) { + if (extensionType != WII_EXTENSION_NONE) { +#if WII_EXTENSION_CALIBRATION==true #if WII_EXTENSION_DEBUG==true - //printf("Reset Sent\n"); + printf("WiiExtension::Calibration Data\n"); #endif - isReady = true; - } else { + regWrite[0] = 0x20; + doI2CWrite(regWrite, 1); + + doI2CRead(idRead, 32); + extensionController->calibrate(idRead); +#endif + } else { #if WII_EXTENSION_DEBUG==true - //printf("Device not found\n"); + printf("WiiExtension::Unknown Extension: %02x%02x %02x%02x %02x%02x\n", idRead[0], idRead[1], idRead[2], idRead[3], idRead[4], idRead[5]); #endif + } + + regWrite[0] = 0x00; + result = doI2CWrite(regWrite, 1); + } } } @@ -195,6 +230,13 @@ void WiiExtension::poll() { case WII_DATA_TYPE_3: result = doI2CRead(regRead, 8); break; + // Motion Plus data types + case WII_DATA_TYPE_4: + case WII_DATA_TYPE_5: + case WII_DATA_TYPE_6: + case WII_DATA_TYPE_7: + result = doI2CRead(regRead, 16); + break; default: // unknown. TBD result = -1; @@ -206,7 +248,7 @@ void WiiExtension::poll() { if (result > 0) { extensionController->process(regRead); - extensionController->postProcess(); + if (!extensionController->skipPostProcess) extensionController->postProcess(); #if WII_EXTENSION_DEBUG==true for (int i = 0; i < result; ++i) { @@ -235,6 +277,10 @@ void WiiExtension::poll() { } } +void WiiExtension::reset() { + isReady = false; +} + int WiiExtension::doI2CWrite(uint8_t *pData, int iLen) { int result = i2c->write(address, pData, iLen, false); waitUntil_us(WII_EXTENSION_DELAY); @@ -263,6 +309,18 @@ uint8_t WiiExtension::doI2CTest() { } void WiiExtension::doI2CInit() { + isMotionPlus = false; + isExtension = false; + + bool extensionCheck = i2c->test(WII_EXTENSION_I2C_ADDR); + waitUntil_us(WII_EXTENSION_DELAY); + + bool motionPlusCheck = i2c->test(WII_MOTIONPLUS_I2C_ADDR); + waitUntil_us(WII_EXTENSION_DELAY); + + // since init is unused, let's use this to detect normal or MotionPlus mode + if (extensionCheck) isExtension = true; + if (motionPlusCheck) isMotionPlus = true; } void WiiExtension::waitUntil_us(uint64_t us) { diff --git a/lib/WiiExtension/WiiExtension.h b/lib/WiiExtension/WiiExtension.h index 80a55860e..bd67b11fd 100644 --- a/lib/WiiExtension/WiiExtension.h +++ b/lib/WiiExtension/WiiExtension.h @@ -31,6 +31,11 @@ typedef enum { #define WII_DATA_TYPE_1 1 #define WII_DATA_TYPE_2 2 #define WII_DATA_TYPE_3 3 +// Motion Plus specific +#define WII_DATA_TYPE_4 4 +#define WII_DATA_TYPE_5 5 +#define WII_DATA_TYPE_6 6 +#define WII_DATA_TYPE_7 7 #define WII_ANALOG_PRECISION_0 32 #define WII_ANALOG_PRECISION_1 64 @@ -80,6 +85,10 @@ typedef enum { #define WII_EXTENSION_I2C_ADDR 0x52 #endif +#ifndef WII_MOTIONPLUS_I2C_ADDR +#define WII_MOTIONPLUS_I2C_ADDR 0x53 +#endif + #define WII_ALARM_NUM 0 #define WII_ALARM_IRQ TIMER_IRQ_0 @@ -141,6 +150,9 @@ class WiiExtension { void waitUntil_us(uint64_t us); static void alarmIRQ(); + + bool isMotionPlus = false; + bool isExtension = false; }; #endif diff --git a/lib/WiiExtension/extensions/ExtensionBase.cpp b/lib/WiiExtension/extensions/ExtensionBase.cpp index cf404a485..abeb9916b 100644 --- a/lib/WiiExtension/extensions/ExtensionBase.cpp +++ b/lib/WiiExtension/extensions/ExtensionBase.cpp @@ -66,7 +66,6 @@ void ExtensionBase::postProcess() { for (i = 0; i < WiiAnalogs::WII_MAX_ANALOGS; ++i) { // scale calibration values before using if (i != WiiAnalogs::WII_ANALOG_CALIBRATION_PRECISION) { - outVal = applyCalibration(analogState[i], _analogCalibration[i].minimum, _analogCalibration[i].maximum, _analogCalibration[i].center); minVal = map(_analogCalibration[i].minimum, 0, _analogPrecision[WiiAnalogs::WII_ANALOG_CALIBRATION_PRECISION].origin-1, 0, _analogPrecision[WiiAnalogs::WII_ANALOG_CALIBRATION_PRECISION].destination-1); diff --git a/lib/WiiExtension/extensions/ExtensionBase.h b/lib/WiiExtension/extensions/ExtensionBase.h index 208f21b0e..6e0f9103c 100644 --- a/lib/WiiExtension/extensions/ExtensionBase.h +++ b/lib/WiiExtension/extensions/ExtensionBase.h @@ -44,9 +44,16 @@ typedef enum { } WiiJoystickModes; typedef enum { - WII_MOTION_X, - WII_MOTION_Y, - WII_MOTION_Z, + WII_ACCELEROMETER_X, + WII_ACCELEROMETER_Y, + WII_ACCELEROMETER_Z, + WII_GYROSCOPE_ROLL, + WII_GYROSCOPE_PITCH, + WII_GYROSCOPE_YAW, + WII_TOUCH_X, + WII_TOUCH_Y, + WII_TOUCH_Z, + WII_TOUCH_PRESSED, WII_MAX_MOTIONS } WiiMotions; @@ -78,10 +85,11 @@ class ExtensionBase { public: bool buttons[WiiButtons::WII_MAX_BUTTONS]; uint16_t analogState[WiiAnalogs::WII_MAX_ANALOGS]; - uint16_t motionState[WiiMotions::WII_MAX_MOTIONS]; + int16_t motionState[WiiMotions::WII_MAX_MOTIONS]; uint16_t initialAnalogState[WiiAnalogs::WII_MAX_ANALOGS]; bool isFirstRead = true; + bool skipPostProcess = false; virtual void init(uint8_t dataType); virtual bool calibrate(uint8_t *calibrationData); diff --git a/lib/WiiExtension/extensions/Extensions.h b/lib/WiiExtension/extensions/Extensions.h index 1d439e599..a17538174 100644 --- a/lib/WiiExtension/extensions/Extensions.h +++ b/lib/WiiExtension/extensions/Extensions.h @@ -5,8 +5,10 @@ #include "ClassicExtension.h" #include "DrumExtension.h" #include "GuitarExtension.h" +#include "MotionPlusExtension.h" #include "NunchuckExtension.h" #include "TaikoExtension.h" #include "TurntableExtension.h" +#include "UDrawExtension.h" #endif diff --git a/lib/WiiExtension/extensions/MotionPlusExtension.cpp b/lib/WiiExtension/extensions/MotionPlusExtension.cpp new file mode 100644 index 000000000..eda082ccf --- /dev/null +++ b/lib/WiiExtension/extensions/MotionPlusExtension.cpp @@ -0,0 +1,166 @@ +#include +#include "CRC32.h" +#include "ExtensionBase.h" +#include "MotionPlusExtension.h" + +#include "WiiExtension.h" + +void MotionPlusExtension::init(uint8_t dataType) { + ExtensionBase::init(dataType); + + yawValue = 0; + rollValue = 0; + pitchValue = 0; + + _analogPrecision[WiiAnalogs::WII_ANALOG_LEFT_X].origin = WII_ANALOG_PRECISION_2; + _analogPrecision[WiiAnalogs::WII_ANALOG_LEFT_X].destination = WII_ANALOG_PRECISION_3; + _analogPrecision[WiiAnalogs::WII_ANALOG_LEFT_Y].origin = WII_ANALOG_PRECISION_2; + _analogPrecision[WiiAnalogs::WII_ANALOG_LEFT_Y].destination = WII_ANALOG_PRECISION_3; + + // preseed calibration data with max ranges + _analogCalibration[WiiAnalogs::WII_ANALOG_LEFT_X].minimum = WII_NUNCHUCK_GATE_CENTER-WII_NUNCHUCK_GATE_SIZE; + _analogCalibration[WiiAnalogs::WII_ANALOG_LEFT_X].center = WII_NUNCHUCK_GATE_CENTER; + _analogCalibration[WiiAnalogs::WII_ANALOG_LEFT_X].maximum = WII_NUNCHUCK_GATE_CENTER+WII_NUNCHUCK_GATE_SIZE; + + _analogCalibration[WiiAnalogs::WII_ANALOG_LEFT_Y].minimum = WII_NUNCHUCK_GATE_CENTER-WII_NUNCHUCK_GATE_SIZE; + _analogCalibration[WiiAnalogs::WII_ANALOG_LEFT_Y].center = WII_NUNCHUCK_GATE_CENTER; + _analogCalibration[WiiAnalogs::WII_ANALOG_LEFT_Y].maximum = WII_NUNCHUCK_GATE_CENTER+WII_NUNCHUCK_GATE_SIZE; + + _analogPrecision[WiiAnalogs::WII_ANALOG_CALIBRATION_PRECISION].origin = WII_ANALOG_PRECISION_2; + _analogPrecision[WiiAnalogs::WII_ANALOG_CALIBRATION_PRECISION].destination = WII_ANALOG_PRECISION_3; +} + +bool MotionPlusExtension::calibrate(uint8_t *calibrationData) { + bool result = false; + // Motion Plus bypasses the base calibration since it does its own +#if WII_EXTENSION_CALIBRATION==true + uint32_t crc32; + uint8_t calibrationCheck[28]; + + // copy the parts minus their CRC32 bytes for checksum validation + memcpy(&calibrationCheck[0], &calibrationData[0], 14); + memcpy(&calibrationCheck[14], &calibrationData[16], 14); + + initialYawValue = 0; + initialRollValue = 0; + initialPitchValue = 0; + + calibration = { + .fastCalibration = { + .yawZero = (calibrationData[0] << 8) | (calibrationData[1] << 0), + .rollZero = (calibrationData[2] << 8) | (calibrationData[3] << 0), + .pitchZero = (calibrationData[4] << 8) | (calibrationData[5] << 0), + .yawScale = (calibrationData[6] << 8) | (calibrationData[7] << 0), + .rollScale = (calibrationData[8] << 8) | (calibrationData[9] << 0), + .pitchScale = (calibrationData[10] << 8) | (calibrationData[11] << 0), + .degreeScale = calibrationData[12], + }, + .fastUID = calibrationData[13], + .crc32MSB = (calibrationData[14] << 8) | (calibrationData[15] << 0), + .slowCalibration = { + .yawZero = (calibrationData[16] << 8) | (calibrationData[17] << 0), + .rollZero = (calibrationData[18] << 8) | (calibrationData[19] << 0), + .pitchZero = (calibrationData[20] << 8) | (calibrationData[21] << 0), + .yawScale = (calibrationData[22] << 8) | (calibrationData[23] << 0), + .rollScale = (calibrationData[24] << 8) | (calibrationData[25] << 0), + .pitchScale = (calibrationData[26] << 8) | (calibrationData[27] << 0), + .degreeScale = calibrationData[28], + }, + .slowUID = calibrationData[29], + .crc32LSB = (calibrationData[30] << 8) | (calibrationData[31] << 0) + }; + + crc32 = CRC32::calculate(calibrationCheck, 28); + result = (((calibration.crc32MSB << 16) | calibration.crc32LSB) == crc32); + +#if WII_EXTENSION_DEBUG==true +// for (uint8_t i = 0; i < 32; i++) { +// printf("%02x ", calibrationData[i]); +// if (((i+1) % 8) == 0) printf("\n"); +// } +// printf("Fast (%d):\n", calibration.fastUID); +// printf("Yaw 0=%d Scale=%d\n", calibration.fastCalibration.yawZero, calibration.fastCalibration.yawScale); +// printf("Roll 0=%d Scale=%d\n", calibration.fastCalibration.rollZero, calibration.fastCalibration.rollScale); +// printf("Pitch 0=%d Scale=%d\n", calibration.fastCalibration.pitchZero, calibration.fastCalibration.pitchScale); +// printf("Degree Scale=%d\n", calibration.fastCalibration.degreeScale); +// printf("Slow (%d):\n", calibration.slowUID); +// printf("Yaw 0=%d Scale=%d\n", calibration.slowCalibration.yawZero, calibration.slowCalibration.yawScale); +// printf("Roll 0=%d Scale=%d\n", calibration.slowCalibration.rollZero, calibration.slowCalibration.rollScale); +// printf("Pitch 0=%d Scale=%d\n", calibration.slowCalibration.pitchZero, calibration.slowCalibration.pitchScale); +// printf("Degree Scale=%d\n", calibration.slowCalibration.degreeScale); +// printf("%08x = %08x\n", (calibration.crc32MSB << 16) | calibration.crc32LSB, crc32); +#endif +#endif + return result; +} + +void MotionPlusExtension::process(uint8_t *inputData) { + bool readMotionPlusData = ((inputData[5] & 0x02) >> 1); + + extensionConnected = ((inputData[4] & 0x01) >> 0); + + if (readMotionPlusData) { + skipPostProcess = true; + yawFastMode = ((inputData[3] & 0x01) >> 0); + rollFastMode = ((inputData[3] & 0x02) >> 1); + pitchFastMode = ((inputData[4] & 0x02) >> 1); + + yawValue = inputData[0] | ((inputData[3] >> 2) << 8); + rollValue = inputData[1] | ((inputData[4] >> 2) << 8); + pitchValue = inputData[2] | ((inputData[5] >> 2) << 8); + + if (((rollValue > 5000) && (pitchValue > 5000) && (yawValue > 5000) && (rollValue < 0x3FFF) && (pitchValue < 0x3FFF) && (yawValue < 0x3FFF) && !initialRollValue && !initialPitchValue && !initialYawValue)) { + initialYawValue = yawValue; + initialRollValue = rollValue; + initialPitchValue = pitchValue; + } else { + motionState[WiiMotions::WII_GYROSCOPE_YAW] = yawValue - initialYawValue; + motionState[WiiMotions::WII_GYROSCOPE_ROLL] = rollValue - initialRollValue; + motionState[WiiMotions::WII_GYROSCOPE_PITCH] = pitchValue - initialPitchValue; + } +#if WII_EXTENSION_DEBUG==true +// printf("\x1B[0;0H"); +// printf(" Roll Pitch Yaw\n"); +// printf("Calib - %6d %6d %6d\n", (rollFastMode ? calibration.fastCalibration.rollZero : calibration.slowCalibration.rollZero), (pitchFastMode ? calibration.fastCalibration.pitchZero : calibration.slowCalibration.pitchZero), (yawFastMode ? calibration.fastCalibration.yawZero : calibration.slowCalibration.yawZero)); +// printf("Calib Scale - %6d %6d %6d\n", (rollFastMode ? calibration.fastCalibration.rollScale : calibration.slowCalibration.rollScale), (pitchFastMode ? calibration.fastCalibration.pitchScale : calibration.slowCalibration.pitchScale), (yawFastMode ? calibration.fastCalibration.yawScale : calibration.slowCalibration.yawScale)); +// printf("Initial - %6d %6d %6d\n", initialRollValue, initialPitchValue, initialYawValue); +// printf("Curr - %6d %6d %6d\n", rollValue, pitchValue, yawValue); +// printf("Output - %6d %6d %6d", motionState[WiiMotions::WII_GYROSCOPE_ROLL], motionState[WiiMotions::WII_GYROSCOPE_PITCH], motionState[WiiMotions::WII_GYROSCOPE_YAW]); +// printf("\x1B[0J"); +#endif + } else { + if (extensionConnected) { + skipPostProcess = false; +#if WII_EXTENSION_DEBUG==true +// printf("MotionPlusExtension::process\n"); +// for (uint8_t i = 0; i < 16; i++) { +// printf("%02x ", inputData[i]); +// if (((i+1) % 8) == 0) printf("\n"); +// } + //printf("inputData[5] "BYTE_TO_BINARY_PATTERN" \n", BYTE_TO_BINARY(inputData[5])); +#endif + if (getDataType() == WII_DATA_TYPE_4) { + // no extension attached + } else if (getDataType() == WII_DATA_TYPE_5) { + // nunchuck attached + analogState[WiiAnalogs::WII_ANALOG_LEFT_X] = (inputData[0] & 0xFF); + analogState[WiiAnalogs::WII_ANALOG_LEFT_Y] = (inputData[1] & 0xFF); + + buttons[WiiButtons::WII_BUTTON_Z] = (!((inputData[5] & 0x04) >> 2)); + buttons[WiiButtons::WII_BUTTON_C] = (!((inputData[5] & 0x08) >> 3)); + + //printf("X: %d, Y: %d\n", analogState[WiiAnalogs::WII_ANALOG_LEFT_X], analogState[WiiAnalogs::WII_ANALOG_LEFT_Y]); + + motionState[WiiMotions::WII_ACCELEROMETER_X] = (((inputData[2] << 2) | ((inputData[5] >> 4) & 0x01))); + motionState[WiiMotions::WII_ACCELEROMETER_Y] = (((inputData[3] << 2) | ((inputData[5] >> 5) & 0x01))); + motionState[WiiMotions::WII_ACCELEROMETER_Z] = ((((inputData[4] & 0xFE) << 3) | ((inputData[5] >> 6) & 0x03))); + } else if (getDataType() == WII_DATA_TYPE_7) { + // classic/other attached + } + } + } + +#if WII_EXTENSION_DEBUG==true +// printf("Roll: %5d Pitch: %5d Yaw: %5d\n", motionState[WiiMotions::WII_GYROSCOPE_ROLL], motionState[WiiMotions::WII_GYROSCOPE_PITCH], motionState[WiiMotions::WII_GYROSCOPE_YAW]); +#endif +} \ No newline at end of file diff --git a/lib/WiiExtension/extensions/MotionPlusExtension.h b/lib/WiiExtension/extensions/MotionPlusExtension.h new file mode 100644 index 000000000..d3db8d697 --- /dev/null +++ b/lib/WiiExtension/extensions/MotionPlusExtension.h @@ -0,0 +1,51 @@ +#ifndef _MOTIONPLUSEXTENSION_H_ +#define _MOTIONPLUSEXTENSION_H_ + +#include "ExtensionBase.h" + +class MotionPlusExtension : public ExtensionBase { + public: + void init(uint8_t dataType) override; + bool calibrate(uint8_t *calibrationData) override; + void process(uint8_t *inputData) override; + + private: + struct CalibrationBlock { + uint16_t yawZero = 0; + uint16_t rollZero = 0; + uint16_t pitchZero = 0; + uint16_t yawScale = 1; + uint16_t rollScale = 1; + uint16_t pitchScale = 1; + uint16_t degreeScale = 1; + } __attribute__((packed)); + + struct CalibrationData { + CalibrationBlock fastCalibration; + uint8_t fastUID; + uint16_t crc32MSB; + CalibrationBlock slowCalibration; + uint8_t slowUID; + uint16_t crc32LSB; + } __attribute__((packed)); + + int16_t initialYawValue; + int16_t initialRollValue; + int16_t initialPitchValue; + bool initialRead = true; + + int16_t yawValue; + int16_t rollValue; + int16_t pitchValue; + + bool yawFastMode = false; + bool rollFastMode = false; + bool pitchFastMode = false; + bool extensionConnected = false; + + CalibrationData calibration; + + uint8_t sampleSize = 10; +}; + +#endif \ No newline at end of file diff --git a/lib/WiiExtension/extensions/NunchuckExtension.cpp b/lib/WiiExtension/extensions/NunchuckExtension.cpp index 0615d6664..49aa26a47 100644 --- a/lib/WiiExtension/extensions/NunchuckExtension.cpp +++ b/lib/WiiExtension/extensions/NunchuckExtension.cpp @@ -71,9 +71,9 @@ void NunchuckExtension::process(uint8_t *inputData) { buttons[WiiButtons::WII_BUTTON_Z] = (!(inputData[5] & 0x01)); buttons[WiiButtons::WII_BUTTON_C] = (!(inputData[5] & 0x02)); - motionState[WiiMotions::WII_MOTION_X] = (((inputData[2] << 2) | ((inputData[5] >> 2) & 0x03))); - motionState[WiiMotions::WII_MOTION_Y] = (((inputData[3] << 2) | ((inputData[5] >> 4) & 0x03))); - motionState[WiiMotions::WII_MOTION_Z] = (((inputData[4] << 2) | ((inputData[5] >> 6) & 0x03))); + motionState[WiiMotions::WII_ACCELEROMETER_X] = (((inputData[2] << 2) | ((inputData[5] >> 2) & 0x03))); + motionState[WiiMotions::WII_ACCELEROMETER_Y] = (((inputData[3] << 2) | ((inputData[5] >> 4) & 0x03))); + motionState[WiiMotions::WII_ACCELEROMETER_Z] = (((inputData[4] << 2) | ((inputData[5] >> 6) & 0x03))); #if WII_EXTENSION_DEBUG==true //printf("Joy X=%4d Y=%4d Acc X=%4d Y=%4d Z=%4d Btn Z=%1d C=%1d\n", analogState[WiiAnalogs::ANALOG_LEFT_X], analogState[WiiAnalogs::ANALOG_LEFT_Y], motionState[WiiMotions::MOTION_X], motionState[WiiMotions::MOTION_Y], motionState[WiiMotions::MOTION_Z], buttons[WiiButtons::BUTTON_Z], buttons[WiiButtons::BUTTON_C]); diff --git a/lib/WiiExtension/extensions/UDrawExtension.cpp b/lib/WiiExtension/extensions/UDrawExtension.cpp new file mode 100644 index 000000000..785da92e7 --- /dev/null +++ b/lib/WiiExtension/extensions/UDrawExtension.cpp @@ -0,0 +1,32 @@ +#include "ExtensionBase.h" +#include "UDrawExtension.h" + +#include "WiiExtension.h" + +void UDrawExtension::process(uint8_t *inputData) { + uint16_t xPosition = (uint16_t)((inputData[2] & 0x0F) << 8) | (uint16_t)((inputData[0] >> 4) << 4) | (uint16_t)(inputData[0] & 0x0F); + uint16_t yPosition = (uint16_t)((inputData[2] >> 4) << 8) | (uint16_t)((inputData[1] >> 4) << 4) | (uint16_t)(inputData[1] & 0x0F); + uint16_t pressure = ((inputData[3] & 0xFF)); + bool button0 = !((inputData[5] & 0x01)); + bool button1 = !((inputData[5] & 0x02) >> 1); + bool button2 = ((inputData[5] & 0x04) >> 1); + + motionState[WiiMotions::WII_TOUCH_X] = (xPosition != 0xFFF ? map(xPosition,UDRAW_MIN_X, UDRAW_MAX_X, UDRAW_MIN_X, UDRAW_MAX_X) : 0); + motionState[WiiMotions::WII_TOUCH_Y] = (yPosition != 0xFFF ? map(yPosition,UDRAW_MIN_Y, UDRAW_MAX_Y, UDRAW_MAX_Y, UDRAW_MIN_Y) : 0); + motionState[WiiMotions::WII_TOUCH_Z] = pressure; + motionState[WiiMotions::WII_TOUCH_PRESSED] = !(xPosition == 0xFFF && yPosition == 0xFFF); + + buttons[WiiButtons::WII_BUTTON_A] = button2; + buttons[WiiButtons::WII_BUTTON_L] = button1; + buttons[WiiButtons::WII_BUTTON_R] = button0; + +#if WII_EXTENSION_DEBUG==true + printf("\x1B[15;0H" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(inputData[0])); + printf("\x1B[16;0H" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(inputData[1])); + printf("\x1B[17;0H" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(inputData[2])); + printf("\x1B[18;0H" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(inputData[3])); + printf("\x1B[19;0H" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(inputData[4])); + printf("\x1B[20;0H" BYTE_TO_BINARY_PATTERN "\n", BYTE_TO_BINARY(inputData[5])); + printf("\x1B[21;0HX=%5d Y=%5d B0=%1d B1=%1d B2=%1d\n", motionState[WiiMotions::WII_TOUCH_X], motionState[WiiMotions::WII_TOUCH_Y], buttons[WiiButtons::WII_BUTTON_A], buttons[WiiButtons::WII_BUTTON_L], buttons[WiiButtons::WII_BUTTON_R]); +#endif +} \ No newline at end of file diff --git a/lib/WiiExtension/extensions/UDrawExtension.h b/lib/WiiExtension/extensions/UDrawExtension.h new file mode 100644 index 000000000..a1504d9b4 --- /dev/null +++ b/lib/WiiExtension/extensions/UDrawExtension.h @@ -0,0 +1,16 @@ +#ifndef _UDRAWEXTENSION_H_ +#define _UDRAWEXTENSION_H_ + +#include "ExtensionBase.h" + +class UDrawExtension : public ExtensionBase { + public: + void process(uint8_t *inputData) override; + private: + const uint16_t UDRAW_MIN_X = 80; + const uint16_t UDRAW_MAX_X = 1955; + const uint16_t UDRAW_MIN_Y = 95; + const uint16_t UDRAW_MAX_Y = 1450; +}; + +#endif \ No newline at end of file diff --git a/proto/config.proto b/proto/config.proto index b0f96d39d..05511c0a1 100644 --- a/proto/config.proto +++ b/proto/config.proto @@ -28,6 +28,7 @@ message GamepadOptions optional InputModeAuthType ps4AuthType = 21; optional InputModeAuthType ps5AuthType = 22; optional InputModeAuthType xinputAuthType = 23; + optional PS4ControllerIDMode ps4ControllerIDMode = 24; } message KeyboardMapping @@ -50,6 +51,8 @@ message KeyboardMapping optional uint32 keyButtonR3 = 16; optional uint32 keyButtonA1 = 17; optional uint32 keyButtonA2 = 18; + optional uint32 keyButtonA3 = 19; + optional uint32 keyButtonA4 = 20; } message HotkeyEntry @@ -664,6 +667,9 @@ message KeyboardHostOptions optional int32 deprecatedPinDplus = 2 [deprecated = true]; optional KeyboardMapping mapping = 3; optional int32 deprecatedPin5V = 4 [deprecated = true]; + optional uint32 mouseLeft = 5; + optional uint32 mouseMiddle = 6; + optional uint32 mouseRight = 7; } message FocusModeOptions diff --git a/proto/enums.proto b/proto/enums.proto index d1eeb06bb..f1531f4b6 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -414,3 +414,11 @@ enum ReactiveLEDMode REACTIVE_LED_FADE_IN = 2; REACTIVE_LED_FADE_OUT = 3; }; + +enum PS4ControllerIDMode +{ + option (nanopb_enumopt).long_names = false; + + PS4_ID_CONSOLE = 0; + PS4_ID_EMULATION = 1; +}; diff --git a/src/addons/drv8833_rumble.cpp b/src/addons/drv8833_rumble.cpp index 05e9bd663..61745d05f 100644 --- a/src/addons/drv8833_rumble.cpp +++ b/src/addons/drv8833_rumble.cpp @@ -17,6 +17,8 @@ bool DRV8833RumbleAddon::available() { void DRV8833RumbleAddon::setup() { const DRV8833RumbleOptions& options = Storage::getInstance().getAddonOptions().drv8833RumbleOptions; + Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); + leftMotorPin = options.leftMotorPin; rightMotorPin = options.rightMotorPin; motorSleepPin = options.motorSleepPin; @@ -30,16 +32,25 @@ void DRV8833RumbleAddon::setup() { else sysClock = 125000000; - gpio_set_function(leftMotorPin, GPIO_FUNC_PWM); - gpio_set_function(rightMotorPin, GPIO_FUNC_PWM); - leftMotorPinSlice = pwm_gpio_to_slice_num (leftMotorPin); - leftMotorPinChannel = pwm_gpio_to_channel (leftMotorPin); - rightMotorPinSlice = pwm_gpio_to_slice_num (rightMotorPin); - rightMotorPinChannel = pwm_gpio_to_channel (rightMotorPin); - pwmSetFreqDuty(leftMotorPinSlice, leftMotorPinChannel, pwmFrequency, 0); - pwmSetFreqDuty(rightMotorPinSlice, rightMotorPinChannel, pwmFrequency, 0); - pwm_set_enabled(leftMotorPinSlice, true); - pwm_set_enabled(rightMotorPinSlice, true); + + // enable haptics in Aux sensors depending on pin assignments + if(isValidPin(leftMotorPin)) { + gpio_set_function(leftMotorPin, GPIO_FUNC_PWM); + leftMotorPinSlice = pwm_gpio_to_slice_num (leftMotorPin); + leftMotorPinChannel = pwm_gpio_to_channel (leftMotorPin); + pwmSetFreqDuty(leftMotorPinSlice, leftMotorPinChannel, pwmFrequency, 0); + pwm_set_enabled(leftMotorPinSlice, true); + gamepad->auxState.haptics.leftActuator.enabled = true; + } + + if(isValidPin(rightMotorPin)) { + gpio_set_function(rightMotorPin, GPIO_FUNC_PWM); + rightMotorPinSlice = pwm_gpio_to_slice_num (rightMotorPin); + rightMotorPinChannel = pwm_gpio_to_channel (rightMotorPin); + pwmSetFreqDuty(rightMotorPinSlice, rightMotorPinChannel, pwmFrequency, 0); + pwm_set_enabled(rightMotorPinSlice, true); + gamepad->auxState.haptics.rightActuator.enabled = true; + } if(isValidPin(motorSleepPin)) { gpio_init(motorSleepPin); @@ -50,7 +61,10 @@ void DRV8833RumbleAddon::setup() { } bool DRV8833RumbleAddon::compareRumbleState(Gamepad * gamepad) { - if (currentRumbleState.leftMotor == gamepad->rumbleState.leftMotor && currentRumbleState.rightMotor == gamepad->rumbleState.rightMotor) + if (currentRumbleState.leftActuator.active == gamepad->auxState.haptics.leftActuator.active && + currentRumbleState.leftActuator.intensity == gamepad->auxState.haptics.leftActuator.intensity && + currentRumbleState.rightActuator.active == gamepad->auxState.haptics.rightActuator.active && + currentRumbleState.rightActuator.intensity == gamepad->auxState.haptics.rightActuator.intensity) return true; return false; @@ -58,8 +72,10 @@ bool DRV8833RumbleAddon::compareRumbleState(Gamepad * gamepad) { } void DRV8833RumbleAddon::setRumbleState(Gamepad * gamepad) { - currentRumbleState.leftMotor = gamepad->rumbleState.leftMotor; - currentRumbleState.rightMotor = gamepad->rumbleState.rightMotor; + currentRumbleState.leftActuator.active = gamepad->auxState.haptics.leftActuator.active; + currentRumbleState.leftActuator.intensity = gamepad->auxState.haptics.leftActuator.intensity; + currentRumbleState.rightActuator.active = gamepad->auxState.haptics.rightActuator.active; + currentRumbleState.rightActuator.intensity = gamepad->auxState.haptics.rightActuator.intensity; } void DRV8833RumbleAddon::disableMotors() { @@ -72,8 +88,8 @@ void DRV8833RumbleAddon::disableMotors() { } void DRV8833RumbleAddon::enableMotors(Gamepad * gamepad) { - pwmSetFreqDuty(leftMotorPinSlice, leftMotorPinChannel, pwmFrequency, (gamepad->rumbleState.leftMotor == 0) ? 0 : scaleDuty(motorToDuty(gamepad->rumbleState.leftMotor), dutyMin, dutyMax)); - pwmSetFreqDuty(rightMotorPinSlice, rightMotorPinChannel, pwmFrequency, (gamepad->rumbleState.rightMotor == 0) ? 0 : scaleDuty(motorToDuty(gamepad->rumbleState.rightMotor), dutyMin, dutyMax)); + pwmSetFreqDuty(leftMotorPinSlice, leftMotorPinChannel, pwmFrequency, (gamepad->auxState.haptics.leftActuator.intensity == 0) ? 0 : scaleDuty(motorToDuty(gamepad->auxState.haptics.leftActuator.intensity), dutyMin, dutyMax)); + pwmSetFreqDuty(rightMotorPinSlice, rightMotorPinChannel, pwmFrequency, (gamepad->auxState.haptics.rightActuator.intensity == 0) ? 0 : scaleDuty(motorToDuty(gamepad->auxState.haptics.rightActuator.intensity), dutyMin, dutyMax)); // if motorSleepPin set and any motors are on, disable motor driver sleep mode if (isValidPin(motorSleepPin)) @@ -81,11 +97,11 @@ void DRV8833RumbleAddon::enableMotors(Gamepad * gamepad) { } void DRV8833RumbleAddon::process() { - Gamepad * gamepad = Storage::getInstance().GetGamepad(); + Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); if (!compareRumbleState(gamepad)) { setRumbleState(gamepad); - if (!(gamepad->rumbleState.leftMotor || gamepad->rumbleState.rightMotor)) { + if (!(gamepad->auxState.haptics.leftActuator.active || gamepad->auxState.haptics.rightActuator.active)) { disableMotors(); return; } diff --git a/src/addons/keyboard_host_listener.cpp b/src/addons/keyboard_host_listener.cpp index f4c8821a3..4734c48a4 100644 --- a/src/addons/keyboard_host_listener.cpp +++ b/src/addons/keyboard_host_listener.cpp @@ -43,24 +43,49 @@ void KeyboardHostListener::setup() { _keyboard_host_mapButtonR3.setKey(keyboardMapping.keyButtonR3); _keyboard_host_mapButtonA1.setKey(keyboardMapping.keyButtonA1); _keyboard_host_mapButtonA2.setKey(keyboardMapping.keyButtonA2); + _keyboard_host_mapButtonA3.setKey(keyboardMapping.keyButtonA3); + _keyboard_host_mapButtonA4.setKey(keyboardMapping.keyButtonA4); + + mouseLeftMapping = keyboardHostOptions.mouseLeft; + mouseMiddleMapping = keyboardHostOptions.mouseMiddle; + mouseRightMapping = keyboardHostOptions.mouseRight; _keyboard_host_enabled = false; _keyboard_dev_addr = 0; _keyboard_instance = 0; + + _mouse_host_enabled = false; + _mouse_dev_addr = 0; + _mouse_instance = 0; + + mouseX = 0; + mouseY = 0; + mouseZ = 0; } void KeyboardHostListener::process() { Gamepad *gamepad = Storage::getInstance().GetGamepad(); - gamepad->state.dpad |= _keyboard_host_state.dpad; - gamepad->state.buttons |= _keyboard_host_state.buttons; - gamepad->state.lx |= _keyboard_host_state.lx; - gamepad->state.ly |= _keyboard_host_state.ly; - gamepad->state.rx |= _keyboard_host_state.rx; - gamepad->state.ry |= _keyboard_host_state.ry; - if (!gamepad->hasAnalogTriggers) { - gamepad->state.lt |= _keyboard_host_state.lt; - gamepad->state.rt |= _keyboard_host_state.rt; + if (_keyboard_host_enabled || _mouse_host_enabled) { + gamepad->state.dpad |= _keyboard_host_state.dpad; + gamepad->state.buttons |= _keyboard_host_state.buttons; + gamepad->state.lx |= _keyboard_host_state.lx; + gamepad->state.ly |= _keyboard_host_state.ly; + gamepad->state.rx |= _keyboard_host_state.rx; + gamepad->state.ry |= _keyboard_host_state.ry; + if (!gamepad->hasAnalogTriggers) { + gamepad->state.lt |= _keyboard_host_state.lt; + gamepad->state.rt |= _keyboard_host_state.rt; + } + } + + gamepad->auxState.sensors.mouse.enabled = _mouse_host_enabled; + gamepad->auxState.sensors.mouse.active = mouseActive; + if (_mouse_host_enabled && mouseActive) { + gamepad->auxState.sensors.mouse.x = mouseX; + gamepad->auxState.sensors.mouse.y = mouseY; + gamepad->auxState.sensors.mouse.z = mouseZ; } + mouseActive = false; } void KeyboardHostListener::mount(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len) { @@ -68,12 +93,17 @@ void KeyboardHostListener::mount(uint8_t dev_addr, uint8_t instance, uint8_t con uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); // tuh_hid_report_received_cb() will be invoked when report is available - if (itf_protocol != HID_ITF_PROTOCOL_KEYBOARD) + if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { + _keyboard_dev_addr = dev_addr; + _keyboard_instance = instance; + _keyboard_host_enabled = true; + } else if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) { + _mouse_dev_addr = dev_addr; + _mouse_instance = instance; + _mouse_host_enabled = true; + } else { return; - - _keyboard_dev_addr = dev_addr; - _keyboard_instance = instance; - _keyboard_host_enabled = true; + } } void KeyboardHostListener::unmount(uint8_t dev_addr) { @@ -81,22 +111,34 @@ void KeyboardHostListener::unmount(uint8_t dev_addr) { _keyboard_host_enabled = false; _keyboard_dev_addr = 0; _keyboard_instance = 0; + } else if ( _mouse_dev_addr == dev_addr ) { + _mouse_host_enabled = false; + _mouse_dev_addr = 0; + _mouse_instance = 0; } } void KeyboardHostListener::report_received(uint8_t dev_addr, uint8_t instance, uint8_t const* report, uint16_t len){ - if ( _keyboard_host_enabled == false || - _keyboard_dev_addr != dev_addr || _keyboard_instance != instance ) + if ( + ( _keyboard_host_enabled == false || _keyboard_dev_addr != dev_addr || _keyboard_instance != instance ) + && + ( _mouse_host_enabled == false || _mouse_dev_addr != dev_addr || _mouse_instance != instance ) + ) return; // do nothing if we haven't mounted // Interface protocol (hid_interface_protocol_enum_t) uint8_t const itf_protocol = tuh_hid_interface_protocol(dev_addr, instance); + preprocess_report(); + // tuh_hid_report_received_cb() will be invoked when report is available - if (itf_protocol != HID_ITF_PROTOCOL_KEYBOARD) + if (itf_protocol == HID_ITF_PROTOCOL_KEYBOARD) { + process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report ); + } else if (itf_protocol == HID_ITF_PROTOCOL_MOUSE) { + process_mouse_report(dev_addr, (hid_mouse_report_t const*) report ); + } else { return; - - process_kbd_report(dev_addr, (hid_keyboard_report_t const*) report ); + } } uint8_t KeyboardHostListener::getKeycodeFromModifier(uint8_t modifier) { @@ -114,8 +156,7 @@ uint8_t KeyboardHostListener::getKeycodeFromModifier(uint8_t modifier) { return 0; } -// convert hid keycode to ascii and print via usb device CDC (ignore non-printable) -void KeyboardHostListener::process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report) +void KeyboardHostListener::preprocess_report() { uint16_t joystickMid = GAMEPAD_JOYSTICK_MID; if ( DriverManager::getInstance().getDriver() != nullptr ) { @@ -131,6 +172,11 @@ void KeyboardHostListener::process_kbd_report(uint8_t dev_addr, hid_keyboard_rep _keyboard_host_state.lt = 0; _keyboard_host_state.rt = 0; +} + +// convert hid keycode to ascii and print via usb device CDC (ignore non-printable) +void KeyboardHostListener::process_kbd_report(uint8_t dev_addr, hid_keyboard_report_t const *report) +{ // make this 13 instead of 7 to include modifier bitfields from hid_keyboard_modifier_bm_t for(uint8_t i=0; i<13; i++) { @@ -168,7 +214,25 @@ void KeyboardHostListener::process_kbd_report(uint8_t dev_addr, hid_keyboard_rep | ((keycode == _keyboard_host_mapButtonR3.key) ? _keyboard_host_mapButtonR3.buttonMask : _keyboard_host_state.buttons) | ((keycode == _keyboard_host_mapButtonA1.key) ? _keyboard_host_mapButtonA1.buttonMask : _keyboard_host_state.buttons) | ((keycode == _keyboard_host_mapButtonA2.key) ? _keyboard_host_mapButtonA2.buttonMask : _keyboard_host_state.buttons) + | ((keycode == _keyboard_host_mapButtonA3.key) ? _keyboard_host_mapButtonA3.buttonMask : _keyboard_host_state.buttons) + | ((keycode == _keyboard_host_mapButtonA4.key) ? _keyboard_host_mapButtonA4.buttonMask : _keyboard_host_state.buttons) ; } } -} \ No newline at end of file +} + +void KeyboardHostListener::process_mouse_report(uint8_t dev_addr, hid_mouse_report_t const * report) +{ + //------------- button state -------------// + _keyboard_host_state.buttons |= + (report->buttons & MOUSE_BUTTON_LEFT ? mouseLeftMapping : _keyboard_host_state.buttons) + | (report->buttons & MOUSE_BUTTON_MIDDLE ? mouseMiddleMapping : _keyboard_host_state.buttons) + | (report->buttons & MOUSE_BUTTON_RIGHT ? mouseRightMapping : _keyboard_host_state.buttons) + ; + + //------------- cursor movement -------------// + mouseX = report->x; + mouseY = report->y; + mouseZ = report->wheel; + mouseActive = true; +} diff --git a/src/addons/neopicoleds.cpp b/src/addons/neopicoleds.cpp index 94725a3ff..fd9e65fd3 100644 --- a/src/addons/neopicoleds.cpp +++ b/src/addons/neopicoleds.cpp @@ -60,7 +60,7 @@ typedef enum // TODO: Make this a helper function // Animation Helper for Player LEDs -PLEDAnimationState getXInputAnimationNEOPICO(uint8_t *data) +PLEDAnimationState getXInputAnimationNEOPICO(uint16_t ledState) { PLEDAnimationState animationState = { @@ -69,52 +69,108 @@ PLEDAnimationState getXInputAnimationNEOPICO(uint8_t *data) .speed = PLED_SPEED_OFF, }; - // Check first byte for LED payload - if (data[0] == 0x01) + switch (ledState) { - switch (data[2]) - { - case XINPUT_PLED_BLINKALL: - case XINPUT_PLED_ROTATE: - case XINPUT_PLED_BLINK: - case XINPUT_PLED_SLOWBLINK: - case XINPUT_PLED_ALTERNATE: - animationState.state = (PLED_STATE_LED1 | PLED_STATE_LED2 | PLED_STATE_LED3 | PLED_STATE_LED4); - animationState.animation = PLED_ANIM_BLINK; - animationState.speed = PLED_SPEED_FAST; - break; - - case XINPUT_PLED_FLASH1: - case XINPUT_PLED_ON1: - animationState.state = PLED_STATE_LED1; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - case XINPUT_PLED_FLASH2: - case XINPUT_PLED_ON2: - animationState.state = PLED_STATE_LED2; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - case XINPUT_PLED_FLASH3: - case XINPUT_PLED_ON3: - animationState.state = PLED_STATE_LED3; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - case XINPUT_PLED_FLASH4: - case XINPUT_PLED_ON4: - animationState.state = PLED_STATE_LED4; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - default: - break; - } + case XINPUT_PLED_BLINKALL: + case XINPUT_PLED_ROTATE: + case XINPUT_PLED_BLINK: + case XINPUT_PLED_SLOWBLINK: + case XINPUT_PLED_ALTERNATE: + animationState.state = (PLED_STATE_LED1 | PLED_STATE_LED2 | PLED_STATE_LED3 | PLED_STATE_LED4); + animationState.animation = PLED_ANIM_BLINK; + animationState.speed = PLED_SPEED_FAST; + break; + + case XINPUT_PLED_FLASH1: + case XINPUT_PLED_ON1: + animationState.state = PLED_STATE_LED1; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + case XINPUT_PLED_FLASH2: + case XINPUT_PLED_ON2: + animationState.state = PLED_STATE_LED2; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + case XINPUT_PLED_FLASH3: + case XINPUT_PLED_ON3: + animationState.state = PLED_STATE_LED3; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + case XINPUT_PLED_FLASH4: + case XINPUT_PLED_ON4: + animationState.state = PLED_STATE_LED4; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + default: + break; + } + + return animationState; +} + +PLEDAnimationState getPS3AnimationNEOPICO(uint16_t ledState) +{ + const uint8_t ps3LEDs[10][4] = { + { 0x01, 0x00, 0x00, 0x00 }, + { 0x00, 0x01, 0x00, 0x00 }, + { 0x00, 0x00, 0x01, 0x00 }, + { 0x00, 0x00, 0x00, 0x01 }, + { 0x01, 0x00, 0x00, 0x01 }, + { 0x00, 0x01, 0x00, 0x01 }, + { 0x00, 0x00, 0x01, 0x01 }, + { 0x01, 0x00, 0x01, 0x01 }, + { 0x00, 0x01, 0x01, 0x01 }, + { 0x01, 0x01, 0x01, 0x01 } + }; + + PLEDAnimationState animationState = + { + .state = 0, + .animation = PLED_ANIM_NONE, + .speed = PLED_SPEED_OFF, + }; + + if (ledState != 0) { + uint8_t ledNumber = ledState & 0x0F; + if (ps3LEDs[ledNumber-1][0] == 0x01) animationState.state |= PLED_STATE_LED1; + if (ps3LEDs[ledNumber-1][1] == 0x01) animationState.state |= PLED_STATE_LED2; + if (ps3LEDs[ledNumber-1][2] == 0x01) animationState.state |= PLED_STATE_LED3; + if (ps3LEDs[ledNumber-1][3] == 0x01) animationState.state |= PLED_STATE_LED4; + } + + if (animationState.state != 0) { + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + } else { + animationState.state = 0; + animationState.animation = PLED_ANIM_OFF; + animationState.speed = PLED_SPEED_OFF; + } + + return animationState; +} + +PLEDAnimationState getPS4AnimationNEOPICO(uint32_t flashOn, uint32_t flashOff) +{ + PLEDAnimationState animationState = + { + .state = (PLED_STATE_LED1 | PLED_STATE_LED2 | PLED_STATE_LED3 | PLED_STATE_LED4), + .animation = PLED_ANIM_SOLID, + .speed = PLED_SPEED_OFF, + }; + + if (flashOn > 0 || flashOff > 0) { + animationState.animation = PLED_ANIM_BLINK_CUSTOM; + animationState.speedOn = flashOn; + animationState.speedOff = flashOff; } return animationState; @@ -131,6 +187,10 @@ void NeoPicoLEDAddon::setup() const LEDOptions& ledOptions = Storage::getInstance().getLedOptions(); turnOffWhenSuspended = ledOptions.turnOffWhenSuspended; + Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); + gamepad->auxState.playerID.enabled = true; + gamepad->auxState.sensors.statusLight.enabled = true; + if ( ledOptions.pledType == PLED_TYPE_RGB ) { neoPLEDs = new NeoPicoPlayerLEDs(); } @@ -151,14 +211,28 @@ void NeoPicoLEDAddon::process() return; Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); - uint8_t * featureData = Storage::getInstance().GetFeatureData(); AnimationHotkey action = animationHotkeys(gamepad); if (ledOptions.pledType == PLED_TYPE_RGB) { inputMode = gamepad->getOptions().inputMode; // HACK - if (inputMode == INPUT_MODE_XINPUT) { - animationState = getXInputAnimationNEOPICO(featureData); - if (neoPLEDs != nullptr && animationState.animation != PLED_ANIM_NONE) - neoPLEDs->animate(animationState); + if (gamepad->auxState.playerID.enabled && gamepad->auxState.playerID.active) { + switch (inputMode) { + case INPUT_MODE_XINPUT: + animationState = getXInputAnimationNEOPICO(gamepad->auxState.playerID.ledValue); + break; + case INPUT_MODE_PS3: + animationState = getPS3AnimationNEOPICO(gamepad->auxState.playerID.ledValue); + break; + case INPUT_MODE_PS4: + case INPUT_MODE_PS5: + animationState = getPS4AnimationNEOPICO(gamepad->auxState.playerID.ledBlinkOn, gamepad->auxState.playerID.ledBlinkOff); + break; + default: + break; + } + } + + if (neoPLEDs != nullptr && animationState.animation != PLED_ANIM_NONE) { + neoPLEDs->animate(animationState); } } @@ -193,18 +267,20 @@ void NeoPicoLEDAddon::process() // Apply the player LEDs to our first 4 leds if we're in NEOPIXEL mode if (ledOptions.pledType == PLED_TYPE_RGB) { - if (inputMode == INPUT_MODE_XINPUT) { // HACK - LEDOptions & ledOptions = Storage::getInstance().getLedOptions(); - int32_t pledIndexes[] = { ledOptions.pledIndex1, ledOptions.pledIndex2, ledOptions.pledIndex3, ledOptions.pledIndex4 }; - for (int i = 0; i < PLED_COUNT; i++) { - if (pledIndexes[i] < 0) - continue; - - float level = (static_cast(PLED_MAX_LEVEL - neoPLEDs->getLedLevels()[i]) / static_cast(PLED_MAX_LEVEL)); - float brightness = as.GetBrightnessX() * level; + LEDOptions & ledOptions = Storage::getInstance().getLedOptions(); + int32_t pledIndexes[] = { ledOptions.pledIndex1, ledOptions.pledIndex2, ledOptions.pledIndex3, ledOptions.pledIndex4 }; + for (int i = 0; i < PLED_COUNT; i++) { + if (pledIndexes[i] < 0) + continue; + + float level = (static_cast(PLED_MAX_LEVEL - neoPLEDs->getLedLevels()[i]) / static_cast(PLED_MAX_LEVEL)); + float brightness = as.GetBrightnessX() * level; + if (gamepad->auxState.sensors.statusLight.enabled && gamepad->auxState.sensors.statusLight.active) { + rgbPLEDValues[i] = (RGB(gamepad->auxState.sensors.statusLight.color.red, gamepad->auxState.sensors.statusLight.color.green, gamepad->auxState.sensors.statusLight.color.blue)).value(neopico->GetFormat(), brightness); + } else { rgbPLEDValues[i] = ((RGB)ledOptions.pledColor).value(neopico->GetFormat(), brightness); - frame[pledIndexes[i]] = rgbPLEDValues[i]; } + frame[pledIndexes[i]] = rgbPLEDValues[i]; } } @@ -576,7 +652,7 @@ AnimationHotkey animationHotkeys(Gamepad *gamepad) { action = HOTKEY_LEDS_FADETIME_UP; gamepad->state.buttons &= ~(GAMEPAD_MASK_R3 | GAMEPAD_MASK_S1 | GAMEPAD_MASK_S2); - } + } } return action; diff --git a/src/addons/playerleds.cpp b/src/addons/playerleds.cpp index 5dc04ea92..13b9b9cbc 100644 --- a/src/addons/playerleds.cpp +++ b/src/addons/playerleds.cpp @@ -36,7 +36,7 @@ typedef enum // TODO: make this a helper function // Animation Helper for Player LEDs -PLEDAnimationState getXInputAnimationPWM(uint8_t *data) +PLEDAnimationState getXInputAnimationPWM(uint16_t ledState) { PLEDAnimationState animationState = { @@ -45,52 +45,48 @@ PLEDAnimationState getXInputAnimationPWM(uint8_t *data) .speed = PLED_SPEED_OFF, }; - // Check first byte for LED payload - if (data[0] == 0x01) + switch (ledState) { - switch (data[2]) - { - case XINPUT_PLED_BLINKALL: - case XINPUT_PLED_ROTATE: - case XINPUT_PLED_BLINK: - case XINPUT_PLED_SLOWBLINK: - case XINPUT_PLED_ALTERNATE: - animationState.state = (PLED_STATE_LED1 | PLED_STATE_LED2 | PLED_STATE_LED3 | PLED_STATE_LED4); - animationState.animation = PLED_ANIM_BLINK; - animationState.speed = PLED_SPEED_FAST; - break; - - case XINPUT_PLED_FLASH1: - case XINPUT_PLED_ON1: - animationState.state = PLED_STATE_LED1; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - case XINPUT_PLED_FLASH2: - case XINPUT_PLED_ON2: - animationState.state = PLED_STATE_LED2; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - case XINPUT_PLED_FLASH3: - case XINPUT_PLED_ON3: - animationState.state = PLED_STATE_LED3; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - case XINPUT_PLED_FLASH4: - case XINPUT_PLED_ON4: - animationState.state = PLED_STATE_LED4; - animationState.animation = PLED_ANIM_SOLID; - animationState.speed = PLED_SPEED_OFF; - break; - - default: - break; - } + case XINPUT_PLED_BLINKALL: + case XINPUT_PLED_ROTATE: + case XINPUT_PLED_BLINK: + case XINPUT_PLED_SLOWBLINK: + case XINPUT_PLED_ALTERNATE: + animationState.state = (PLED_STATE_LED1 | PLED_STATE_LED2 | PLED_STATE_LED3 | PLED_STATE_LED4); + animationState.animation = PLED_ANIM_BLINK; + animationState.speed = PLED_SPEED_FAST; + break; + + case XINPUT_PLED_FLASH1: + case XINPUT_PLED_ON1: + animationState.state = PLED_STATE_LED1; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + case XINPUT_PLED_FLASH2: + case XINPUT_PLED_ON2: + animationState.state = PLED_STATE_LED2; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + case XINPUT_PLED_FLASH3: + case XINPUT_PLED_ON3: + animationState.state = PLED_STATE_LED3; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + case XINPUT_PLED_FLASH4: + case XINPUT_PLED_ON4: + animationState.state = PLED_STATE_LED4; + animationState.animation = PLED_ANIM_SOLID; + animationState.speed = PLED_SPEED_OFF; + break; + + default: + break; } return animationState; @@ -104,6 +100,10 @@ void PlayerLEDAddon::setup() { const LEDOptions& ledOptions = Storage::getInstance().getLedOptions(); turnOffWhenSuspended = ledOptions.turnOffWhenSuspended; + Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); + gamepad->auxState.playerID.enabled = true; + gamepad->auxState.sensors.statusLight.enabled = true; + switch (ledOptions.pledType) { case PLED_TYPE_PWM: @@ -112,6 +112,8 @@ void PlayerLEDAddon::setup() { case PLED_TYPE_RGB: // Do not assign pwmLEDs (support later on?) break; + default: + break; } if (pwmLEDs != nullptr) @@ -126,13 +128,15 @@ void PlayerLEDAddon::process() const LEDOptions& ledOptions = Storage::getInstance().getLedOptions(); // Player LEDs can be PWM or driven by NeoPixel - uint8_t * featureData = Storage::getInstance().GetFeatureData(); if (ledOptions.pledType == PLED_TYPE_PWM) { // only process the feature queue if we're on PWM if (pwmLEDs != nullptr) pwmLEDs->display(); - if (gamepad->getOptions().inputMode == INPUT_MODE_XINPUT) - animationState = getXInputAnimationPWM(featureData); + if (gamepad->auxState.playerID.enabled && gamepad->auxState.playerID.active) { + if (gamepad->getOptions().inputMode == INPUT_MODE_XINPUT) { + animationState = getXInputAnimationPWM(gamepad->auxState.playerID.ledValue); + } + } if (pwmLEDs != nullptr && animationState.animation != PLED_ANIM_NONE) pwmLEDs->animate(animationState); diff --git a/src/addons/playernum.cpp b/src/addons/playernum.cpp index 6db4abf14..c9531080b 100644 --- a/src/addons/playernum.cpp +++ b/src/addons/playernum.cpp @@ -30,6 +30,7 @@ bool PlayerNumAddon::available() { void PlayerNumAddon::setup() { const PlayerNumberOptions& options = Storage::getInstance().getAddonOptions().playerNumberOptions; + xinputIDs[0] = XINPUT_PLED_ON1; xinputIDs[1] = XINPUT_PLED_ON2; xinputIDs[2] = XINPUT_PLED_ON3; @@ -47,17 +48,9 @@ void PlayerNumAddon::process() Gamepad * gamepad = Storage::getInstance().GetGamepad(); InputMode inputMode = static_cast(gamepad->getOptions().inputMode); if ( inputMode == INPUT_MODE_XINPUT ) { - uint8_t * featureData = Storage::getInstance().GetFeatureData(); - if (featureData[0] == 0x01) { - XInputPLEDPattern ledAction = (XInputPLEDPattern)featureData[2]; - if ( ledAction == XINPUT_PLED_ON1 ) - handleLED(1); - else if ( ledAction == XINPUT_PLED_ON2 ) - handleLED(2); - else if ( ledAction == XINPUT_PLED_ON3 ) - handleLED(3); - else if ( ledAction == XINPUT_PLED_ON4 ) - handleLED(4); + if (gamepad->auxState.playerID.enabled && gamepad->auxState.playerID.active) { + if ( gamepad->auxState.playerID.value != 0 ) + handleLED(gamepad->auxState.playerID.value); } } else { assigned = 1; diff --git a/src/addons/wiiext.cpp b/src/addons/wiiext.cpp index c86c8adeb..63b2d6285 100644 --- a/src/addons/wiiext.cpp +++ b/src/addons/wiiext.cpp @@ -86,6 +86,8 @@ void WiiExtensionInput::process() { setButtonState(dpadLeft, WiiButtons::WII_BUTTON_LEFT); setButtonState(dpadRight, WiiButtons::WII_BUTTON_RIGHT); + updateMotionState(); + if (lastLeftX != leftX) lastLeftX = leftX; if (lastLeftY != leftY) lastLeftY = leftY; if (lastRightX != rightX) lastRightX = rightX; @@ -118,6 +120,8 @@ void WiiExtensionInput::update() { //} isAnalogTriggers = false; + isAccelerometer = false; + isGyroscope = false; if (wii->extensionType == WII_EXTENSION_NUNCHUCK) { buttonZ = wii->getController()->buttons[WiiButtons::WII_BUTTON_Z]; @@ -128,6 +132,11 @@ void WiiExtensionInput::update() { rightX = joystickMid; rightY = joystickMid; + accelerometerX = wii->getController()->motionState[WiiMotions::WII_ACCELEROMETER_X]; + accelerometerY = wii->getController()->motionState[WiiMotions::WII_ACCELEROMETER_Y]; + accelerometerZ = wii->getController()->motionState[WiiMotions::WII_ACCELEROMETER_Z]; + isAccelerometer = true; + triggerLeft = 0; triggerRight = 0; } else if ((wii->extensionType == WII_EXTENSION_CLASSIC) || (wii->extensionType == WII_EXTENSION_CLASSIC_PRO)) { @@ -232,6 +241,38 @@ void WiiExtensionInput::update() { triggerRight = wii->getController()->analogState[TurntableAnalogs::TURNTABLE_CROSSFADE]; isAnalogTriggers = true; + } else if ((wii->extensionType == WII_EXTENSION_DRAWSOME) || (wii->extensionType == WII_EXTENSION_UDRAW)) { + buttonA = wii->getController()->buttons[WiiButtons::WII_BUTTON_A]; + buttonL = wii->getController()->buttons[WiiButtons::WII_BUTTON_L]; + buttonR = wii->getController()->buttons[WiiButtons::WII_BUTTON_R]; + + touchX = wii->getController()->motionState[WiiMotions::WII_TOUCH_X]; + touchY = wii->getController()->motionState[WiiMotions::WII_TOUCH_Y]; + touchZ = wii->getController()->motionState[WiiMotions::WII_TOUCH_Z]; + touchPressed = wii->getController()->motionState[WiiMotions::WII_TOUCH_PRESSED]; + + isTouch = true; + } else if (wii->extensionType == WII_EXTENSION_MOTION_PLUS) { + currentConfig = &extensionConfigs[WII_EXTENSION_NUNCHUCK]; + + gyroscopeX = wii->getController()->motionState[WiiMotions::WII_GYROSCOPE_YAW]; + gyroscopeY = wii->getController()->motionState[WiiMotions::WII_GYROSCOPE_ROLL]; + gyroscopeZ = wii->getController()->motionState[WiiMotions::WII_GYROSCOPE_PITCH]; + isGyroscope = true; + + // add logic to know if an attachment is detected. for now, just stream it. + buttonZ = wii->getController()->buttons[WiiButtons::WII_BUTTON_Z]; + buttonC = wii->getController()->buttons[WiiButtons::WII_BUTTON_C]; + + leftX = map(wii->getController()->analogState[WiiAnalogs::WII_ANALOG_LEFT_X],0,WII_ANALOG_PRECISION_3,GAMEPAD_JOYSTICK_MIN,GAMEPAD_JOYSTICK_MAX); + leftY = map(wii->getController()->analogState[WiiAnalogs::WII_ANALOG_LEFT_Y],WII_ANALOG_PRECISION_3,0,GAMEPAD_JOYSTICK_MIN,GAMEPAD_JOYSTICK_MAX); + rightX = joystickMid; + rightY = joystickMid; + + accelerometerX = wii->getController()->motionState[WiiMotions::WII_ACCELEROMETER_X]; + accelerometerY = wii->getController()->motionState[WiiMotions::WII_ACCELEROMETER_Y]; + accelerometerZ = wii->getController()->motionState[WiiMotions::WII_ACCELEROMETER_Z]; + isAccelerometer = true; } } else { currentConfig = NULL; @@ -521,7 +562,35 @@ void WiiExtensionInput::updateAnalogState() { gamepad->state.rt = getDelta(currAxis->second, GAMEPAD_TRIGGER_MID); break; } - } + } + } +} + +void WiiExtensionInput::updateMotionState() { + Gamepad * gamepad = Storage::getInstance().GetGamepad(); + + gamepad->auxState.sensors.accelerometer.enabled = isAccelerometer; + if (isAccelerometer) { + gamepad->auxState.sensors.accelerometer.x = accelerometerX; + gamepad->auxState.sensors.accelerometer.y = accelerometerY; + gamepad->auxState.sensors.accelerometer.z = accelerometerZ; + gamepad->auxState.sensors.accelerometer.active = true; + } + + gamepad->auxState.sensors.gyroscope.enabled = isGyroscope; + if (isGyroscope) { + gamepad->auxState.sensors.gyroscope.x = gyroscopeX; + gamepad->auxState.sensors.gyroscope.y = gyroscopeY; + gamepad->auxState.sensors.gyroscope.z = gyroscopeZ; + gamepad->auxState.sensors.gyroscope.active = true; + } + + gamepad->auxState.sensors.touchpad[0].enabled = isTouch; + if (isTouch) { + gamepad->auxState.sensors.touchpad[0].x = touchX; + gamepad->auxState.sensors.touchpad[0].y = touchY; + gamepad->auxState.sensors.touchpad[0].z = touchZ; + gamepad->auxState.sensors.touchpad[0].active = touchPressed; } } diff --git a/src/config_utils.cpp b/src/config_utils.cpp index fed18dcab..a6a64e3f3 100644 --- a/src/config_utils.cpp +++ b/src/config_utils.cpp @@ -141,6 +141,10 @@ #define DEFAULT_XINPUTAUTHENTICATION_TYPE INPUT_MODE_AUTH_TYPE_NONE #endif +#ifndef DEFAULT_PS4_ID_MODE + #define DEFAULT_PS4_ID_MODE PS4_ID_CONSOLE +#endif + #ifndef GPIO_PIN_00 #define GPIO_PIN_00 GpioAction::NONE #endif @@ -272,6 +276,7 @@ void ConfigUtils::initUnsetPropertiesWithDefaults(Config& config) INIT_UNSET_PROPERTY(config.gamepadOptions, ps4AuthType, DEFAULT_PS4AUTHENTICATION_TYPE); INIT_UNSET_PROPERTY(config.gamepadOptions, ps5AuthType, DEFAULT_PS5AUTHENTICATION_TYPE); INIT_UNSET_PROPERTY(config.gamepadOptions, xinputAuthType, DEFAULT_XINPUTAUTHENTICATION_TYPE); + INIT_UNSET_PROPERTY(config.gamepadOptions, ps4ControllerIDMode, DEFAULT_PS4_ID_MODE); // hotkeyOptions HotkeyOptions& hotkeyOptions = config.hotkeyOptions; diff --git a/src/configs/webconfig.cpp b/src/configs/webconfig.cpp index 24b766cba..d0f6c7643 100644 --- a/src/configs/webconfig.cpp +++ b/src/configs/webconfig.cpp @@ -639,6 +639,7 @@ std::string setGamepadOptions() readDoc(gamepadOptions.ps4AuthType, doc, "ps4AuthType"); readDoc(gamepadOptions.ps5AuthType, doc, "ps5AuthType"); readDoc(gamepadOptions.xinputAuthType, doc, "xinputAuthType"); + readDoc(gamepadOptions.ps4ControllerIDMode, doc, "ps4ControllerIDMode"); HotkeyOptions& hotkeyOptions = Storage::getInstance().getHotkeyOptions(); save_hotkey(&hotkeyOptions.hotkey01, doc, "hotkey01"); @@ -690,6 +691,7 @@ std::string getGamepadOptions() writeDoc(doc, "ps4AuthType", gamepadOptions.ps4AuthType); writeDoc(doc, "ps5AuthType", gamepadOptions.ps5AuthType); writeDoc(doc, "xinputAuthType", gamepadOptions.xinputAuthType); + writeDoc(doc, "ps4ControllerIDMode", gamepadOptions.ps4ControllerIDMode); writeDoc(doc, "fnButtonPin", -1); GpioMappingInfo* gpioMappings = Storage::getInstance().getGpioMappings().pins; @@ -1125,6 +1127,8 @@ std::string setKeyMappings() readDoc(keyboardMapping.keyButtonR3, doc, "R3"); readDoc(keyboardMapping.keyButtonA1, doc, "A1"); readDoc(keyboardMapping.keyButtonA2, doc, "A2"); + readDoc(keyboardMapping.keyButtonA3, doc, "A3"); + readDoc(keyboardMapping.keyButtonA4, doc, "A4"); Storage::getInstance().save(); @@ -1154,6 +1158,8 @@ std::string getKeyMappings() writeDoc(doc, "R3", keyboardMapping.keyButtonR3); writeDoc(doc, "A1", keyboardMapping.keyButtonA1); writeDoc(doc, "A2", keyboardMapping.keyButtonA2); + writeDoc(doc, "A3", keyboardMapping.keyButtonA3); + writeDoc(doc, "A4", keyboardMapping.keyButtonA4); return serialize_json(doc); } @@ -1528,6 +1534,11 @@ std::string setAddonOptions() docToValue(keyboardHostOptions.mapping.keyButtonR3, doc, "keyboardHostMap", "R3"); docToValue(keyboardHostOptions.mapping.keyButtonA1, doc, "keyboardHostMap", "A1"); docToValue(keyboardHostOptions.mapping.keyButtonA2, doc, "keyboardHostMap", "A2"); + docToValue(keyboardHostOptions.mapping.keyButtonA3, doc, "keyboardHostMap", "A3"); + docToValue(keyboardHostOptions.mapping.keyButtonA4, doc, "keyboardHostMap", "A4"); + docToValue(keyboardHostOptions.mouseLeft, doc, "keyboardHostMouseLeft"); + docToValue(keyboardHostOptions.mouseMiddle, doc, "keyboardHostMouseMiddle"); + docToValue(keyboardHostOptions.mouseRight, doc, "keyboardHostMouseRight"); RotaryOptions& rotaryOptions = Storage::getInstance().getAddonOptions().rotaryOptions; docToValue(rotaryOptions.enabled, doc, "RotaryAddonEnabled"); @@ -1947,6 +1958,11 @@ std::string getAddonOptions() writeDoc(doc, "keyboardHostMap", "R3", keyboardHostOptions.mapping.keyButtonR3); writeDoc(doc, "keyboardHostMap", "A1", keyboardHostOptions.mapping.keyButtonA1); writeDoc(doc, "keyboardHostMap", "A2", keyboardHostOptions.mapping.keyButtonA2); + writeDoc(doc, "keyboardHostMap", "A3", keyboardHostOptions.mapping.keyButtonA3); + writeDoc(doc, "keyboardHostMap", "A4", keyboardHostOptions.mapping.keyButtonA4); + writeDoc(doc, "keyboardHostMouseLeft", keyboardHostOptions.mouseLeft); + writeDoc(doc, "keyboardHostMouseMiddle", keyboardHostOptions.mouseMiddle); + writeDoc(doc, "keyboardHostMouseRight", keyboardHostOptions.mouseRight); AnalogADS1256Options& ads1256Options = Storage::getInstance().getAddonOptions().analogADS1256Options; writeDoc(doc, "Analog1256Enabled", ads1256Options.enabled); diff --git a/src/drivers/astro/AstroDriver.cpp b/src/drivers/astro/AstroDriver.cpp index 338f52514..7fb3d0689 100644 --- a/src/drivers/astro/AstroDriver.cpp +++ b/src/drivers/astro/AstroDriver.cpp @@ -25,7 +25,7 @@ void AstroDriver::initialize() { }; } -void AstroDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void AstroDriver::process(Gamepad * gamepad) { astroReport.lx = 0x7f; astroReport.ly = 0x7f; diff --git a/src/drivers/egret/EgretDriver.cpp b/src/drivers/egret/EgretDriver.cpp index 0e44af047..d85655270 100644 --- a/src/drivers/egret/EgretDriver.cpp +++ b/src/drivers/egret/EgretDriver.cpp @@ -21,7 +21,7 @@ void EgretDriver::initialize() { }; } -void EgretDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void EgretDriver::process(Gamepad * gamepad) { switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) { case GAMEPAD_MASK_UP: egretReport.lx = EGRET_JOYSTICK_MID; egretReport.ly = EGRET_JOYSTICK_MIN; break; diff --git a/src/drivers/hid/HIDDriver.cpp b/src/drivers/hid/HIDDriver.cpp index 2d54bae43..da79c4526 100644 --- a/src/drivers/hid/HIDDriver.cpp +++ b/src/drivers/hid/HIDDriver.cpp @@ -34,7 +34,7 @@ void HIDDriver::initialize() { } // Generate HID report from gamepad and send to TUSB Device -void HIDDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void HIDDriver::process(Gamepad * gamepad) { switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) { case GAMEPAD_MASK_UP: hidReport.direction = HID_HAT_UP; break; diff --git a/src/drivers/keyboard/KeyboardDriver.cpp b/src/drivers/keyboard/KeyboardDriver.cpp index 4d3a7991f..ccc39b283 100644 --- a/src/drivers/keyboard/KeyboardDriver.cpp +++ b/src/drivers/keyboard/KeyboardDriver.cpp @@ -51,7 +51,7 @@ uint8_t KeyboardDriver::getMultimedia(uint8_t code) { } -void KeyboardDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void KeyboardDriver::process(Gamepad * gamepad) { const KeyboardMapping& keyboardMapping = Storage::getInstance().getKeyboardMapping(); releaseAllKeys(); if(gamepad->pressedUp()) { pressKey(keyboardMapping.keyDpadUp); } diff --git a/src/drivers/mdmini/MDMiniDriver.cpp b/src/drivers/mdmini/MDMiniDriver.cpp index 0537490e6..f043e3c39 100644 --- a/src/drivers/mdmini/MDMiniDriver.cpp +++ b/src/drivers/mdmini/MDMiniDriver.cpp @@ -25,7 +25,7 @@ void MDMiniDriver::initialize() { }; } -void MDMiniDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void MDMiniDriver::process(Gamepad * gamepad) { mdminiReport.lx = 0x7f; mdminiReport.ly = 0x7f; diff --git a/src/drivers/neogeo/NeoGeoDriver.cpp b/src/drivers/neogeo/NeoGeoDriver.cpp index ed7cf850e..e955faed0 100644 --- a/src/drivers/neogeo/NeoGeoDriver.cpp +++ b/src/drivers/neogeo/NeoGeoDriver.cpp @@ -38,7 +38,7 @@ void NeoGeoDriver::initialize() { }; } -void NeoGeoDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void NeoGeoDriver::process(Gamepad * gamepad) { switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) { case GAMEPAD_MASK_UP: neogeoReport.hat = NEOGEO_HAT_UP; break; diff --git a/src/drivers/net/NetDriver.cpp b/src/drivers/net/NetDriver.cpp index c154fc320..36c3c647c 100644 --- a/src/drivers/net/NetDriver.cpp +++ b/src/drivers/net/NetDriver.cpp @@ -56,7 +56,7 @@ void NetDriver::initialize() { }; } -void NetDriver::process(Gamepad * gamepad, uint8_t * outBuffer) {} +void NetDriver::process(Gamepad * gamepad) {} // tud_hid_get_report_cb uint16_t NetDriver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { diff --git a/src/drivers/pcengine/PCEngineDriver.cpp b/src/drivers/pcengine/PCEngineDriver.cpp index 0fe4bee60..47afc2d7d 100644 --- a/src/drivers/pcengine/PCEngineDriver.cpp +++ b/src/drivers/pcengine/PCEngineDriver.cpp @@ -25,7 +25,7 @@ void PCEngineDriver::initialize() { }; } -void PCEngineDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void PCEngineDriver::process(Gamepad * gamepad) { switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) { case GAMEPAD_MASK_UP: pcengineReport.hat = PCENGINE_HAT_UP; break; diff --git a/src/drivers/ps3/PS3Driver.cpp b/src/drivers/ps3/PS3Driver.cpp index 5377f5677..439bba4ef 100644 --- a/src/drivers/ps3/PS3Driver.cpp +++ b/src/drivers/ps3/PS3Driver.cpp @@ -6,127 +6,287 @@ #include "drivers/ps3/PS3Driver.h" #include "drivers/ps3/PS3Descriptors.h" #include "drivers/shared/driverhelper.h" - -// Magic byte sequence to enable PS button on PS3 -static const uint8_t ps3_magic_init_bytes[8] = {0x21, 0x26, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00}; - -static bool ps3_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request) -{ - if ( request->bmRequestType == 0xA1 && - request->bRequest == HID_REQ_CONTROL_GET_REPORT && - request->wValue == 0x0300 ) { - return tud_control_xfer(rhport, request, (void *) ps3_magic_init_bytes, sizeof(ps3_magic_init_bytes)); - } else { - return hidd_control_xfer_cb(rhport, stage, request); - } -} +#include "storagemanager.h" +#include "pico/rand.h" void PS3Driver::initialize() { - ps3Report = { - .square_btn = 0, .cross_btn = 0, .circle_btn = 0, .triangle_btn = 0, - .l1_btn = 0, .r1_btn = 0, .l2_btn = 0, .r2_btn = 0, - .select_btn = 0, .start_btn = 0, .l3_btn = 0, .r3_btn = 0, .ps_btn = 0, .tp_btn = 0, - .direction = 0x08, - .l_x_axis = PS3_JOYSTICK_MID, - .l_y_axis = PS3_JOYSTICK_MID, - .r_x_axis = PS3_JOYSTICK_MID, - .r_y_axis = PS3_JOYSTICK_MID, - .right_axis = 0x00, .left_axis = 0x00, .up_axis = 0x00, .down_axis = 0x00, - .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, - .l1_axis = 0x00, .r1_axis = 0x00, .l2_axis = 0x00, .r2_axis = 0x00 - }; - - class_driver = { - #if CFG_TUSB_DEBUG >= 2 - .name = "PS3", - #endif - .init = hidd_init, - .reset = hidd_reset, - .open = hidd_open, - .control_xfer_cb = ps3_control_xfer_cb, - .xfer_cb = hidd_xfer_cb, - .sof = NULL - }; + ps3Report = { + .reportID = 1, + .reserved = 0, + .select_btn = 0, .l3_btn = 0, .r3_btn = 0, .start_btn = 0, + .dpad_up = 0, .dpad_right = 0, .dpad_down = 0, .dpad_left = 0, + .l2_btn = 0, .r2_btn = 0, .l1_btn = 0, .r1_btn = 0, + .triangle_btn = 0, .circle_btn = 0, .cross_btn = 0, .square_btn = 0, + .ps_btn = 0, .tp_btn = 0, + .l_x_axis = PS3_JOYSTICK_MID, + .l_y_axis = PS3_JOYSTICK_MID, + .r_x_axis = PS3_JOYSTICK_MID, + .r_y_axis = PS3_JOYSTICK_MID, + .movePowerStatus = 0, + .up_axis = 0x00, .right_axis = 0x00, .down_axis = 0x00, .left_axis = 0x00, + .l2_axis = 0x00, .r2_axis = 0x00, .l1_axis = 0x00, .r1_axis = 0x00, + .triangle_axis = 0x00, .circle_axis = 0x00, .cross_axis = 0x00, .square_axis = 0x00, + .reserved2 = {0x00,0x00,0x00}, + .plugged = PS3PluggedInState::PS3_PLUGGED, + .powerStatus = PS3PowerState::PS3_POWER_FULL, + .rumbleStatus = PS3WiredState::PS3_WIRED_RUMBLE, + .reserved3 = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}, + .accelerometer_x = PS3_CENTER_SIXAXIS, .accelerometer_y = PS3_CENTER_SIXAXIS, .accelerometer_z = PS3_CENTER_SIXAXIS, + .gyroscope_z = PS3_CENTER_SIXAXIS, + .reserved4 = PS3_CENTER_SIXAXIS + }; + + // generate addresses + ps3BTInfo = { + .reserved = {0xFF,0xFF}, + .deviceAddress = { 0x00, 0x20, 0x40, 0xCE, 0x00, 0x00, 0x00 }, + .hostAddress = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } + }; + + for (uint8_t addr = 0; addr < 3; addr++) { + ps3BTInfo.deviceAddress[4+addr] = (uint8_t)(get_rand_32() % 0xff); + } + + for (uint8_t addr = 0; addr < 6; addr++) { + ps3BTInfo.hostAddress[1+addr] = (uint8_t)(get_rand_32() % 0xff); + } + + class_driver = { + #if CFG_TUSB_DEBUG >= 2 + .name = "PS3", + #endif + .init = hidd_init, + .reset = hidd_reset, + .open = hidd_open, + .control_xfer_cb = hidd_control_xfer_cb, + .xfer_cb = hidd_xfer_cb, + .sof = NULL + }; } // Generate PS3 report from gamepad and send to TUSB Device -void PS3Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { - switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) - { - case GAMEPAD_MASK_UP: ps3Report.direction = PS3_HAT_UP; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_UPRIGHT; break; - case GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_RIGHT; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_RIGHT: ps3Report.direction = PS3_HAT_DOWNRIGHT; break; - case GAMEPAD_MASK_DOWN: ps3Report.direction = PS3_HAT_DOWN; break; - case GAMEPAD_MASK_DOWN | GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_DOWNLEFT; break; - case GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_LEFT; break; - case GAMEPAD_MASK_UP | GAMEPAD_MASK_LEFT: ps3Report.direction = PS3_HAT_UPLEFT; break; - default: ps3Report.direction = PS3_HAT_NOTHING; break; - } - - ps3Report.cross_btn = gamepad->pressedB1(); - ps3Report.circle_btn = gamepad->pressedB2(); - ps3Report.square_btn = gamepad->pressedB3(); - ps3Report.triangle_btn = gamepad->pressedB4(); - ps3Report.l1_btn = gamepad->pressedL1(); - ps3Report.r1_btn = gamepad->pressedR1(); - ps3Report.l2_btn = gamepad->pressedL2(); - ps3Report.r2_btn = gamepad->pressedR2(); - ps3Report.select_btn = gamepad->pressedS1(); - ps3Report.start_btn = gamepad->pressedS2(); - ps3Report.l3_btn = gamepad->pressedL3(); - ps3Report.r3_btn = gamepad->pressedR3(); - ps3Report.ps_btn = gamepad->pressedA1(); - ps3Report.tp_btn = gamepad->pressedA2(); - - ps3Report.l_x_axis = static_cast(gamepad->state.lx >> 8); - ps3Report.l_y_axis = static_cast(gamepad->state.ly >> 8); - ps3Report.r_x_axis = static_cast(gamepad->state.rx >> 8); - ps3Report.r_y_axis = static_cast(gamepad->state.ry >> 8); - - if (gamepad->hasAnalogTriggers) - { - ps3Report.l2_axis = gamepad->state.lt; - ps3Report.r2_axis = gamepad->state.rt; - } else { - ps3Report.l2_axis = gamepad->pressedL2() ? 0xFF : 0; - ps3Report.r2_axis = gamepad->pressedR2() ? 0xFF : 0; - } - - ps3Report.triangle_axis = gamepad->pressedB4() ? 0xFF : 0; - ps3Report.circle_axis = gamepad->pressedB2() ? 0xFF : 0; - ps3Report.cross_axis = gamepad->pressedB1() ? 0xFF : 0; - ps3Report.square_axis = gamepad->pressedB3() ? 0xFF : 0; - ps3Report.l1_axis = gamepad->pressedL1() ? 0xFF : 0; - ps3Report.r1_axis = gamepad->pressedR1() ? 0xFF : 0; - ps3Report.right_axis = gamepad->state.dpad & GAMEPAD_MASK_RIGHT ? 0xFF : 0; - ps3Report.left_axis = gamepad->state.dpad & GAMEPAD_MASK_LEFT ? 0xFF : 0; - ps3Report.up_axis = gamepad->state.dpad & GAMEPAD_MASK_UP ? 0xFF : 0; - ps3Report.down_axis = gamepad->state.dpad & GAMEPAD_MASK_DOWN ? 0xFF : 0; - - // Wake up TinyUSB device - if (tud_suspended()) - tud_remote_wakeup(); - - void * report = &ps3Report; - uint16_t report_size = sizeof(ps3Report); - if (memcmp(last_report, report, report_size) != 0) - { - // HID ready + report sent, copy previous report - if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { - memcpy(last_report, report, report_size); - } - } +void PS3Driver::process(Gamepad * gamepad) { + ps3Report.dpad_left = gamepad->pressedLeft(); + ps3Report.dpad_down = gamepad->pressedDown(); + ps3Report.dpad_right = gamepad->pressedRight(); + ps3Report.dpad_up = gamepad->pressedUp(); + + ps3Report.cross_btn = gamepad->pressedB1(); + ps3Report.circle_btn = gamepad->pressedB2(); + ps3Report.square_btn = gamepad->pressedB3(); + ps3Report.triangle_btn = gamepad->pressedB4(); + ps3Report.l1_btn = gamepad->pressedL1(); + ps3Report.r1_btn = gamepad->pressedR1(); + ps3Report.l2_btn = gamepad->pressedL2(); + ps3Report.r2_btn = gamepad->pressedR2(); + ps3Report.select_btn = gamepad->pressedS1(); + ps3Report.start_btn = gamepad->pressedS2(); + ps3Report.l3_btn = gamepad->pressedL3(); + ps3Report.r3_btn = gamepad->pressedR3(); + ps3Report.ps_btn = gamepad->pressedA1(); + ps3Report.tp_btn = gamepad->pressedA2(); + + ps3Report.l_x_axis = static_cast(gamepad->state.lx >> 8); + ps3Report.l_y_axis = static_cast(gamepad->state.ly >> 8); + ps3Report.r_x_axis = static_cast(gamepad->state.rx >> 8); + ps3Report.r_y_axis = static_cast(gamepad->state.ry >> 8); + + if (gamepad->hasAnalogTriggers) + { + ps3Report.l2_axis = gamepad->state.lt; + ps3Report.r2_axis = gamepad->state.rt; + } else { + ps3Report.l2_axis = gamepad->pressedL2() ? 0xFF : 0; + ps3Report.r2_axis = gamepad->pressedR2() ? 0xFF : 0; + } + + ps3Report.triangle_axis = gamepad->pressedB4() ? 0xFF : 0; + ps3Report.circle_axis = gamepad->pressedB2() ? 0xFF : 0; + ps3Report.cross_axis = gamepad->pressedB1() ? 0xFF : 0; + ps3Report.square_axis = gamepad->pressedB3() ? 0xFF : 0; + ps3Report.l1_axis = gamepad->pressedL1() ? 0xFF : 0; + ps3Report.r1_axis = gamepad->pressedR1() ? 0xFF : 0; + ps3Report.right_axis = gamepad->state.dpad & GAMEPAD_MASK_RIGHT ? 0xFF : 0; + ps3Report.left_axis = gamepad->state.dpad & GAMEPAD_MASK_LEFT ? 0xFF : 0; + ps3Report.up_axis = gamepad->state.dpad & GAMEPAD_MASK_UP ? 0xFF : 0; + ps3Report.down_axis = gamepad->state.dpad & GAMEPAD_MASK_DOWN ? 0xFF : 0; + + if (gamepad->auxState.sensors.accelerometer.enabled) { + ps3Report.accelerometer_x = ((gamepad->auxState.sensors.accelerometer.x & 0xFF) << 8) | ((gamepad->auxState.sensors.accelerometer.x & 0xFF00) >> 8); + ps3Report.accelerometer_y = ((gamepad->auxState.sensors.accelerometer.y & 0xFF) << 8) | ((gamepad->auxState.sensors.accelerometer.y & 0xFF00) >> 8); + ps3Report.accelerometer_z = ((gamepad->auxState.sensors.accelerometer.z & 0xFF) << 8) | ((gamepad->auxState.sensors.accelerometer.z & 0xFF00) >> 8); + } else { + ps3Report.accelerometer_x = PS3_CENTER_SIXAXIS; + ps3Report.accelerometer_y = PS3_CENTER_SIXAXIS; + ps3Report.accelerometer_z = PS3_CENTER_SIXAXIS; + } + + if (gamepad->auxState.sensors.gyroscope.enabled) { + ps3Report.gyroscope_z = ((gamepad->auxState.sensors.gyroscope.z & 0xFF) << 8) | ((gamepad->auxState.sensors.gyroscope.z & 0xFF00) >> 8); + ps3Report.reserved4 = PS3_CENTER_SIXAXIS; + } else { + ps3Report.gyroscope_z = PS3_CENTER_SIXAXIS; + ps3Report.reserved4 = PS3_CENTER_SIXAXIS; + } + + // Wake up TinyUSB device + if (tud_suspended()) + tud_remote_wakeup(); + + void * report = &ps3Report; + uint16_t report_size = sizeof(ps3Report); + if (memcmp(last_report, report, report_size) != 0) + { + // HID ready + report sent, copy previous report + if (tud_hid_ready() && tud_hid_report(0, report, report_size) == true ) { + memcpy(last_report, report, report_size); + } + } + + uint16_t featureSize = sizeof(PS3Features); + if (memcmp(lastFeatures, &ps3Features, featureSize) != 0) { + memcpy(lastFeatures, &ps3Features, featureSize); + Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); + + if (gamepad->auxState.haptics.leftActuator.enabled) { + gamepad->auxState.haptics.leftActuator.active = (ps3Features.leftMotorPower > 0); + gamepad->auxState.haptics.leftActuator.intensity = ps3Features.leftMotorPower; + } + + if (gamepad->auxState.haptics.rightActuator.enabled) { + gamepad->auxState.haptics.rightActuator.active = (ps3Features.rightMotorPower > 0); + gamepad->auxState.haptics.rightActuator.intensity = ps3Features.rightMotorPower; + } + + gamepad->auxState.playerID.active = true; + gamepad->auxState.playerID.ledValue = ps3Features.playerLED; + gamepad->auxState.playerID.value = (ps3Features.playerLED & 0x0F); + } } +// unknown +static constexpr uint8_t output_ps3_0x01[] = { + 0x01, 0x04, 0x00, 0x0b, 0x0c, 0x01, 0x02, 0x18, + 0x18, 0x18, 0x18, 0x09, 0x0a, 0x10, 0x11, 0x12, + 0x13, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x02, + 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x04, 0x04, + 0x04, 0x04, 0x00, 0x00, 0x04, 0x00, 0x01, 0x02, + 0x07, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// calibration data +static constexpr uint8_t output_ps3_0xef[] = { + 0xef, 0x04, 0x00, 0x0b, 0x03, 0x01, 0xa0, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, + 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, 0x01, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, +}; + +// unknown +static constexpr uint8_t output_ps3_0xf5[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // host address - must match 0xf2 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// unknown +static constexpr uint8_t output_ps3_0xf7[] = { + 0x02, 0x01, 0xf8, 0x02, 0xe2, 0x01, 0x05, 0xff, + 0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +// unknown +static constexpr uint8_t output_ps3_0xf8[] = { + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + // tud_hid_get_report_cb uint16_t PS3Driver::get_report(uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen) { - memcpy(buffer, &ps3Report, sizeof(PS3Report)); - return sizeof(PS3Report); + if ( report_type == HID_REPORT_TYPE_INPUT ) { + memcpy(buffer, &ps3Report, sizeof(PS3Report)); + return sizeof(PS3Report); + } else if ( report_type == HID_REPORT_TYPE_FEATURE ) { + uint16_t responseLen = 0; + uint8_t ctr = 0; + switch(report_id) { + case PS3ReportTypes::PS3_FEATURE_01: + responseLen = reqlen; + memcpy(buffer, output_ps3_0x01, responseLen); + return responseLen; + case PS3ReportTypes::PS3_FEATURE_EF: + responseLen = reqlen; + memcpy(buffer, output_ps3_0xef, responseLen); + buffer[6] = efByte; + return responseLen; + case PS3ReportTypes::PS3_GET_PAIRING_INFO: + responseLen = reqlen; + memcpy(buffer, &ps3BTInfo, responseLen); + return responseLen; + case PS3ReportTypes::PS3_FEATURE_F5: + responseLen = reqlen; + memcpy(buffer, output_ps3_0xf5, responseLen); + for (ctr = 0; ctr < 6; ctr++) { + buffer[1+ctr] = ps3BTInfo.hostAddress[ctr]; + } + return responseLen; + case PS3ReportTypes::PS3_FEATURE_F7: + responseLen = reqlen; + memcpy(buffer, output_ps3_0xf7, responseLen); + return responseLen; + case PS3ReportTypes::PS3_FEATURE_F8: + responseLen = reqlen; + memcpy(buffer, output_ps3_0xf8, responseLen); + buffer[6] = efByte; + return responseLen; + } + } + return -1; } -// Only PS4 does anything with set report -void PS3Driver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) {} +void PS3Driver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { + if ( report_type == HID_REPORT_TYPE_FEATURE ) { + switch(report_id) { + case PS3ReportTypes::PS3_FEATURE_EF: + efByte = buffer[6]; + break; + } + } else if (report_type == HID_REPORT_TYPE_OUTPUT ) { + // DS3 command + uint8_t const *buf = buffer; + if (report_id == 0 && bufsize > 0) { + report_id = buffer[0]; + bufsize = bufsize - 1; + buf = &buffer[1]; + } + switch(report_id) { + case PS3ReportTypes::PS3_FEATURE_01: + memcpy(&ps3Features, buf, bufsize); + break; + } + } +} // Only XboxOG and Xbox One use vendor control xfer cb bool PS3Driver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { diff --git a/src/drivers/ps4/PS4Driver.cpp b/src/drivers/ps4/PS4Driver.cpp index b89c11391..e25b460d0 100644 --- a/src/drivers/ps4/PS4Driver.cpp +++ b/src/drivers/ps4/PS4Driver.cpp @@ -17,6 +17,28 @@ #define PS4_KEEPALIVE_TIMER 5 void PS4Driver::initialize() { + Gamepad * gamepad = Storage::getInstance().GetGamepad(); + const GamepadOptions & options = gamepad->getOptions(); + + // set up device descriptor IDs depending on mode + uint8_t descSize = sizeof(ps4_device_descriptor); + memcpy(deviceDescriptor, &ps4_device_descriptor, descSize); + + bool isDeviceEmulated = options.ps4ControllerIDMode == PS4ControllerIDMode::PS4_ID_EMULATION; + + if (!isDeviceEmulated) { + deviceDescriptor[8] = LSB(PS4_VENDOR_ID); + deviceDescriptor[9] = MSB(PS4_VENDOR_ID); + deviceDescriptor[10] = LSB(PS4_PRODUCT_ID); + deviceDescriptor[11] = MSB(PS4_PRODUCT_ID); + } else { + deviceDescriptor[8] = LSB(DS4_VENDOR_ID); + deviceDescriptor[9] = MSB(DS4_VENDOR_ID); + deviceDescriptor[10] = LSB(DS4_PRODUCT_ID); + deviceDescriptor[11] = MSB(DS4_PRODUCT_ID); + } + + // init feature data touchpadData.p1.unpressed = 1; touchpadData.p1.set_x(PS4_TP_X_MAX / 2); touchpadData.p1.set_y(PS4_TP_Y_MAX / 2); @@ -24,6 +46,26 @@ void PS4Driver::initialize() { touchpadData.p2.set_x(PS4_TP_X_MAX / 2); touchpadData.p2.set_y(PS4_TP_Y_MAX / 2); + sensorData.powerLevel = 0xB; // 0x00-0x0A, 0x00-0x0B if charging + sensorData.charging = 1; // set this to 1 to show as plugged in + sensorData.headphones = 0; + sensorData.microphone = 0; + sensorData.extension = 0; + sensorData.gyroscope.x = 0; + sensorData.gyroscope.y = 0; + sensorData.gyroscope.z = 0; + sensorData.accelerometer.x = 0; + sensorData.accelerometer.y = 0; + sensorData.accelerometer.z = 0; + + // preseed touchpad sensors with center position values + gamepad->auxState.sensors.touchpad[0].x = PS4_TP_X_MAX/2; + gamepad->auxState.sensors.touchpad[0].y = PS4_TP_Y_MAX/2; + gamepad->auxState.sensors.touchpad[1].x = PS4_TP_X_MAX/2; + gamepad->auxState.sensors.touchpad[1].y = PS4_TP_Y_MAX/2; + + touchCounter = 0; + ps4Report = { .report_id = 0x01, .left_stick_x = PS4_JOYSTICK_MID, @@ -34,7 +76,7 @@ void PS4Driver::initialize() { .button_west = 0, .button_south = 0, .button_east = 0, .button_north = 0, .button_l1 = 0, .button_r1 = 0, .button_l2 = 0, .button_r2 = 0, .button_select = 0, .button_start = 0, .button_l3 = 0, .button_r3 = 0, .button_home = 0, - .gyro_accel_misc = { }, .touchpad_active = 0, .padding = 0, .tpad_increment = 0, + .sensor_data = sensorData, .touchpad_active = 0, .padding = 0, .tpad_increment = 0, .touchpad_data = touchpadData, .mystery_2 = { } }; @@ -78,7 +120,7 @@ void PS4Driver::initializeAux() { } } -void PS4Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void PS4Driver::process(Gamepad * gamepad) { const GamepadOptions & options = gamepad->getOptions(); switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) { @@ -128,6 +170,8 @@ void PS4Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { touchpadData.p1.unpressed = ps4Report.button_touchpad ? 0 : 1; ps4Report.touchpad_active = ps4Report.button_touchpad ? 0x01 : 0x00; if (ps4Report.button_touchpad) { + // make the assumption that since touchpad button is already being pressed, + // the first touch position is in use and no other "touches" will be present if (gamepad->pressedA3()) { touchpadData.p1.set_x(PS4_TP_X_MIN); } else if (gamepad->pressedA4()) { @@ -135,9 +179,54 @@ void PS4Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { } else { touchpadData.p1.set_x(PS4_TP_X_MAX / 2); } + } else { + // if more than one touch pad sensor, sensors will never be used out of order + if (gamepad->auxState.sensors.touchpad[0].enabled) { + touchpadData.p1.unpressed = !gamepad->auxState.sensors.touchpad[0].active; + ps4Report.touchpad_active = gamepad->auxState.sensors.touchpad[0].active; + touchpadData.p1.set_x(gamepad->auxState.sensors.touchpad[0].x); + touchpadData.p1.set_y(gamepad->auxState.sensors.touchpad[0].y); + + if (gamepad->auxState.sensors.touchpad[1].enabled) { + touchpadData.p2.unpressed = !gamepad->auxState.sensors.touchpad[1].active; + touchpadData.p2.set_x(gamepad->auxState.sensors.touchpad[1].x); + touchpadData.p2.set_y(gamepad->auxState.sensors.touchpad[1].y); + } + } + } + // check if any of the points are recently touched, rather than still being touched + if (!pointOneTouched && !touchpadData.p1.unpressed) { + touchCounter = (touchCounter < PS4_TP_MAX_COUNT ? touchCounter+1 : 0); + + touchpadData.p1.counter = touchCounter; + + pointOneTouched = true; + } else if (pointOneTouched && touchpadData.p1.unpressed) { + pointOneTouched = false; + } + if (!pointTwoTouched && touchpadData.p2.unpressed) { + touchCounter = (touchCounter < PS4_TP_MAX_COUNT ? touchCounter+1 : 0); + + touchpadData.p2.counter = touchCounter; + + pointTwoTouched = true; + } else if (pointTwoTouched && touchpadData.p1.unpressed) { + pointTwoTouched = false; } ps4Report.touchpad_data = touchpadData; + if (gamepad->auxState.sensors.accelerometer.enabled) { + ps4Report.sensor_data.accelerometer.x = ((gamepad->auxState.sensors.accelerometer.x & 0xFF) << 8) | ((gamepad->auxState.sensors.accelerometer.x & 0xFF00) >> 8); + ps4Report.sensor_data.accelerometer.y = ((gamepad->auxState.sensors.accelerometer.y & 0xFF) << 8) | ((gamepad->auxState.sensors.accelerometer.y & 0xFF00) >> 8); + ps4Report.sensor_data.accelerometer.z = ((gamepad->auxState.sensors.accelerometer.z & 0xFF) << 8) | ((gamepad->auxState.sensors.accelerometer.z & 0xFF00) >> 8); + } + + if (gamepad->auxState.sensors.gyroscope.enabled) { + ps4Report.sensor_data.gyroscope.x = ((gamepad->auxState.sensors.gyroscope.x & 0xFF) << 8) | ((gamepad->auxState.sensors.gyroscope.x & 0xFF00) >> 8); + ps4Report.sensor_data.gyroscope.y = ((gamepad->auxState.sensors.gyroscope.y & 0xFF) << 8) | ((gamepad->auxState.sensors.gyroscope.y & 0xFF00) >> 8); + ps4Report.sensor_data.gyroscope.z = ((gamepad->auxState.sensors.gyroscope.z & 0xFF) << 8) | ((gamepad->auxState.sensors.gyroscope.z & 0xFF00) >> 8); + } + // Wake up TinyUSB device if (tud_suspended()) tud_remote_wakeup(); @@ -167,6 +256,51 @@ void PS4Driver::process(Gamepad * gamepad, uint8_t * outBuffer) { // the *next* process() will be a forced report (or real user input) } } + + uint16_t featureSize = sizeof(PS4FeatureOutputReport); + if (memcmp(lastFeatures, &ps4Features, featureSize) != 0) { + memcpy(lastFeatures, &ps4Features, featureSize); + Gamepad * gamepad = Storage::getInstance().GetProcessedGamepad(); + + if (gamepad->auxState.haptics.leftActuator.enabled) { + gamepad->auxState.haptics.leftActuator.active = (ps4Features.rumbleLeft > 0); + gamepad->auxState.haptics.leftActuator.intensity = ps4Features.rumbleLeft; + } + + if (gamepad->auxState.haptics.rightActuator.enabled) { + gamepad->auxState.haptics.rightActuator.active = (ps4Features.rumbleRight > 0); + gamepad->auxState.haptics.rightActuator.intensity = ps4Features.rumbleRight; + } + + if (gamepad->auxState.sensors.statusLight.enabled) { + uint32_t rgbColor = 0; + + gamepad->auxState.sensors.statusLight.active = true; + gamepad->auxState.sensors.statusLight.color.red = ps4Features.ledRed; + gamepad->auxState.sensors.statusLight.color.green = ps4Features.ledGreen; + gamepad->auxState.sensors.statusLight.color.blue = ps4Features.ledBlue; + + rgbColor = (ps4Features.ledRed << 16) | (ps4Features.ledGreen << 8) | (ps4Features.ledBlue << 0); + + // set player ID based on color combos + gamepad->auxState.playerID.active = true; + gamepad->auxState.playerID.ledBlinkOn = (ps4Features.ledBlinkOn * 10); // centiseconds to milliseconds + gamepad->auxState.playerID.ledBlinkOff = (ps4Features.ledBlinkOff * 10); // centiseconds to milliseconds + if (rgbColor == 0x000040) { + gamepad->auxState.playerID.value = 1; + gamepad->auxState.playerID.ledValue = 1; + } else if (rgbColor == 0x400000) { + gamepad->auxState.playerID.value = 2; + gamepad->auxState.playerID.ledValue = 2; + } else if (rgbColor == 0x004000) { + gamepad->auxState.playerID.value = 3; + gamepad->auxState.playerID.ledValue = 3; + } else if (rgbColor == 0x200020) { + gamepad->auxState.playerID.value = 4; + gamepad->auxState.playerID.ledValue = 4; + } + } + } } // Called by Core1, PS4 key signing will lock the CPU @@ -184,6 +318,14 @@ USBListener * PS4Driver::get_usb_auth_listener() { return nullptr; } +// Controller calibration +static constexpr uint8_t output_0x02[] = { + 0xfe, 0xff, 0x0e, 0x00, 0x04, 0x00, 0xd4, 0x22, + 0x2a, 0xdd, 0xbb, 0x22, 0x5e, 0xdd, 0x81, 0x22, + 0x84, 0xdd, 0x1c, 0x02, 0x1c, 0x02, 0x85, 0x1f, + 0xb0, 0xe0, 0xc6, 0x20, 0xb5, 0xe0, 0xb1, 0x20, + 0x83, 0xdf, 0x0c, 0x00 +}; // Controller descriptor (byte[4] = 0x00 for ps4, 0x07 for ps5) static constexpr uint8_t output_0x03[] = { @@ -195,6 +337,23 @@ static constexpr uint8_t output_0x03[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +// Bluetooth device and host details +static constexpr uint8_t output_0x12[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // device MAC address + 0x08, 0x25, 0x00, // BT device class + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // host MAC address +}; + +// Controller firmware version and datestamp +static constexpr uint8_t output_0xa3[] = { + 0x4a, 0x75, 0x6e, 0x20, 0x20, 0x39, 0x20, 0x32, + 0x30, 0x31, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x31, 0x32, 0x3a, 0x33, 0x36, 0x3a, 0x34, 0x31, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x08, 0xb4, 0x01, 0x00, 0x00, 0x00, + 0x07, 0xa0, 0x10, 0x20, 0x00, 0xa0, 0x02, 0x00 +}; + // Nonce Page Size: 0x38 (56) // Response Page Size: 0x38 (56) static constexpr uint8_t output_0xf3[] = { 0x0, 0x38, 0x38, 0, 0, 0, 0 }; @@ -211,16 +370,39 @@ uint16_t PS4Driver::get_report(uint8_t report_id, hid_report_type_t report_type, bool ps4_auth_buffer_ready = ps4AuthDriver->getAuthReady(); uint8_t data[64] = {}; uint32_t crc32; + uint16_t responseLen = 0; //ps4_out_buffer[0] = report_id; switch(report_id) { // Controller Definition Report + case PS4AuthReport::PS4_GET_CALIBRATION: + if (reqlen < sizeof(output_0x02)) { + return -1; + } + responseLen = MAX(reqlen, sizeof(output_0x02)); + memcpy(buffer, output_0x02, responseLen); + return responseLen; case PS4AuthReport::PS4_DEFINITION: - if (reqlen != sizeof(output_0x03)) { + if (reqlen < sizeof(output_0x03)) { return -1; } - memcpy(buffer, output_0x03, reqlen); + responseLen = MAX(reqlen, sizeof(output_0x03)); + memcpy(buffer, output_0x03, responseLen); buffer[4] = (uint8_t)controllerType; // Change controller type in definition - return reqlen; + return responseLen; + case PS4AuthReport::PS4_GET_MAC_ADDRESS: + if (reqlen < sizeof(output_0x12)) { + return -1; + } + responseLen = MAX(reqlen, sizeof(output_0x12)); + memcpy(buffer, output_0x12, responseLen); + return responseLen; + case PS4AuthReport::PS4_GET_VERSION_DATE: + if (reqlen < sizeof(output_0xa3)) { + return -1; + } + responseLen = MAX(reqlen, sizeof(output_0xa3)); + memcpy(buffer, output_0xa3, responseLen); + return responseLen; // Use our private RSA key to sign the nonce and return chunks case PS4AuthReport::PS4_GET_SIGNATURE_NONCE: // We send 56 byte chunks back to the PS4, we've already calculated these @@ -253,16 +435,18 @@ uint16_t PS4Driver::get_report(uint8_t report_id, hid_report_type_t report_type, memcpy(buffer, &data[1], 15); // move data over to buffer return 15; case PS4AuthReport::PS4_RESET_AUTH: // Reset the Authentication - if (reqlen != sizeof(output_0xf3)) { + if (reqlen < sizeof(output_0xf3)) { return -1; } - memcpy(buffer, output_0xf3, reqlen); + responseLen = MAX(reqlen, sizeof(output_0xf3)); + memcpy(buffer, output_0xf3, responseLen); ps4State = PS4State::no_nonce; if ( authDriver != nullptr ) { ((PS4Auth*)authDriver)->resetAuth(); // reset the auth driver if it exists } - return reqlen; + return responseLen; default: + //printf("[Data Undefined]\n"); break; }; return -1; @@ -270,49 +454,59 @@ uint16_t PS4Driver::get_report(uint8_t report_id, hid_report_type_t report_type, // Only PS4 does anything with set report void PS4Driver::set_report(uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize) { - if ( report_type != HID_REPORT_TYPE_FEATURE ) + if (( report_type != HID_REPORT_TYPE_FEATURE ) && ( report_type != HID_REPORT_TYPE_OUTPUT )) return; - uint8_t nonce_id; - uint8_t nonce_page; - uint32_t crc32; - uint8_t sendBuffer[64]; - uint8_t nonce[56]; // max nonce data - uint16_t noncelen; - uint16_t buflen; - - if (report_id == PS4AuthReport::PS4_SET_AUTH_PAYLOAD) { - if (bufsize != 63 ) { - return; + if (report_type == HID_REPORT_TYPE_OUTPUT) { + if (report_id == 0) { + memcpy(&ps4Features, buffer, bufsize); } + } else if (report_type == HID_REPORT_TYPE_FEATURE) { + uint8_t nonce_id; + uint8_t nonce_page; + uint32_t crc32; + uint8_t sendBuffer[64]; + uint8_t nonce[56]; // max nonce data + uint16_t noncelen; + uint16_t buflen; + + if (report_id == PS4AuthReport::PS4_SET_HOST_MAC) { + // + } else if (report_id == PS4AuthReport::PS4_SET_USB_BT_CONTROL) { + // + } else if (report_id == PS4AuthReport::PS4_SET_AUTH_PAYLOAD) { + if (bufsize != 63 ) { + return; + } - // Setup CRC32 buffer - sendBuffer[0] = report_id; - memcpy(&sendBuffer[1], buffer, bufsize); - buflen = bufsize + 1; + // Setup CRC32 buffer + sendBuffer[0] = report_id; + memcpy(&sendBuffer[1], buffer, bufsize); + buflen = bufsize + 1; - nonce_id = buffer[0]; - nonce_page = buffer[1]; - // data[2] is zero padding + nonce_id = buffer[0]; + nonce_page = buffer[1]; + // data[2] is zero padding - crc32 = CRC32::calculate(sendBuffer, buflen-sizeof(uint32_t)); - if ( crc32 != *((unsigned int*)&sendBuffer[buflen-sizeof(uint32_t)])) { - return; // CRC32 failed on set report - } + crc32 = CRC32::calculate(sendBuffer, buflen-sizeof(uint32_t)); + if ( crc32 != *((unsigned int*)&sendBuffer[buflen-sizeof(uint32_t)])) { + return; // CRC32 failed on set report + } - // 256 byte nonce, with 56 byte packets leaves 24 extra bytes on the last packet? - if ( nonce_page == 4 ) { - // Copy/append data from buffer[4:64-28] into our nonce - noncelen = 32; // from 4 to 64 - 24 - 4 - nonce_id = nonce_id; // for pass-through only - } else { - // Copy/append data from buffer[4:64-4] into our nonce - noncelen = 56; - // from 4 to 64 - 4 - } + // 256 byte nonce, with 56 byte packets leaves 24 extra bytes on the last packet? + if ( nonce_page == 4 ) { + // Copy/append data from buffer[4:64-28] into our nonce + noncelen = 32; // from 4 to 64 - 24 - 4 + nonce_id = nonce_id; // for pass-through only + } else { + // Copy/append data from buffer[4:64-4] into our nonce + noncelen = 56; + // from 4 to 64 - 4 + } - memcpy(nonce, &sendBuffer[4], noncelen); - save_nonce(nonce_id, nonce_page, nonce, noncelen); + memcpy(nonce, &sendBuffer[4], noncelen); + save_nonce(nonce_id, nonce_page, nonce, noncelen); + } } } @@ -342,7 +536,7 @@ const uint16_t * PS4Driver::get_descriptor_string_cb(uint8_t index, uint16_t lan } const uint8_t * PS4Driver::get_descriptor_device_cb() { - return ps4_device_descriptor; + return deviceDescriptor; } const uint8_t * PS4Driver::get_hid_descriptor_report_cb(uint8_t itf) { diff --git a/src/drivers/psclassic/PSClassicDriver.cpp b/src/drivers/psclassic/PSClassicDriver.cpp index aa6baea46..2117e09ea 100644 --- a/src/drivers/psclassic/PSClassicDriver.cpp +++ b/src/drivers/psclassic/PSClassicDriver.cpp @@ -19,7 +19,7 @@ void PSClassicDriver::initialize() { }; } -void PSClassicDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void PSClassicDriver::process(Gamepad * gamepad) { psClassicReport.buttons = PSCLASSIC_MASK_CENTER; switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) diff --git a/src/drivers/switch/SwitchDriver.cpp b/src/drivers/switch/SwitchDriver.cpp index 8a50e6c34..cd943637f 100644 --- a/src/drivers/switch/SwitchDriver.cpp +++ b/src/drivers/switch/SwitchDriver.cpp @@ -25,7 +25,7 @@ void SwitchDriver::initialize() { }; } -void SwitchDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void SwitchDriver::process(Gamepad * gamepad) { switch (gamepad->state.dpad & GAMEPAD_MASK_DPAD) { case GAMEPAD_MASK_UP: switchReport.hat = SWITCH_HAT_UP; break; diff --git a/src/drivers/xbone/XBOneDriver.cpp b/src/drivers/xbone/XBOneDriver.cpp index 5b86bab6b..41dff9cc8 100644 --- a/src/drivers/xbone/XBOneDriver.cpp +++ b/src/drivers/xbone/XBOneDriver.cpp @@ -364,7 +364,7 @@ USBListener * XBOneDriver::get_usb_auth_listener() { return nullptr; } -void XBOneDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void XBOneDriver::process(Gamepad * gamepad) { // Do nothing if we couldn't setup our auth listener if ( xboxOneAuthData == nullptr) { return; diff --git a/src/drivers/xboxog/XboxOriginalDriver.cpp b/src/drivers/xboxog/XboxOriginalDriver.cpp index 7a58de6c8..cc39972c0 100644 --- a/src/drivers/xboxog/XboxOriginalDriver.cpp +++ b/src/drivers/xboxog/XboxOriginalDriver.cpp @@ -23,7 +23,7 @@ void XboxOriginalDriver::initialize() { memcpy(&class_driver, xid_get_driver(), sizeof(usbd_class_driver_t)); } -void XboxOriginalDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void XboxOriginalDriver::process(Gamepad * gamepad) { // digital buttons xboxOriginalReport.dButtons = 0 | (gamepad->pressedUp() ? XID_DUP : 0) @@ -68,6 +68,22 @@ void XboxOriginalDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { memcpy(last_report, &xboxOriginalReport, sizeof(XboxOriginalReport)); } } + + if (xid_get_report(xIndex, &xboxOriginalReportOut, sizeof(xboxOriginalReportOut))) + { + uint8_t leftValue = (xboxOriginalReportOut.lValue >> 8); + uint8_t rightValue = (xboxOriginalReportOut.rValue >> 8); + + if (gamepad->auxState.haptics.leftActuator.enabled) { + gamepad->auxState.haptics.leftActuator.active = (leftValue > 0); + gamepad->auxState.haptics.leftActuator.intensity = leftValue; + } + + if (gamepad->auxState.haptics.rightActuator.enabled) { + gamepad->auxState.haptics.rightActuator.active = (rightValue > 0); + gamepad->auxState.haptics.rightActuator.intensity = rightValue; + } + } } // tud_hid_get_report_cb diff --git a/src/drivers/xinput/XInputDriver.cpp b/src/drivers/xinput/XInputDriver.cpp index 3fc91c042..d8926bfe6 100644 --- a/src/drivers/xinput/XInputDriver.cpp +++ b/src/drivers/xinput/XInputDriver.cpp @@ -22,8 +22,6 @@ #define DESC_EXTENDED_COMPATIBLE_ID_DESCRIPTOR 0x0004 #define DESC_EXTENDED_PROPERTIES_DESCRIPTOR 0x0005 -#define XINPUT_OUT_SIZE 32 - uint8_t endpoint_in = 0; uint8_t endpoint_out = 0; uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {}; @@ -33,6 +31,25 @@ uint8_t xinput_out_buffer[XINPUT_OUT_SIZE] = {}; static bool authDriverPresent = false; +// Move to Proto Enums +typedef enum +{ + XINPUT_PLED_OFF = 0x00, // All off + XINPUT_PLED_BLINKALL = 0x01, // All blinking + XINPUT_PLED_FLASH1 = 0x02, // 1 flashes, then on + XINPUT_PLED_FLASH2 = 0x03, // 2 flashes, then on + XINPUT_PLED_FLASH3 = 0x04, // 3 flashes, then on + XINPUT_PLED_FLASH4 = 0x05, // 4 flashes, then on + XINPUT_PLED_ON1 = 0x06, // 1 on + XINPUT_PLED_ON2 = 0x07, // 2 on + XINPUT_PLED_ON3 = 0x08, // 3 on + XINPUT_PLED_ON4 = 0x09, // 4 on + XINPUT_PLED_ROTATE = 0x0A, // Rotating (e.g. 1-2-4-3) + XINPUT_PLED_BLINK = 0x0B, // Blinking* + XINPUT_PLED_SLOWBLINK = 0x0C, // Slow blinking* + XINPUT_PLED_ALTERNATE = 0x0D, // Alternating (e.g. 1+4-2+3), then back to previous* +} XInputPLEDPattern; + static void xinput_init(void) { } @@ -80,12 +97,12 @@ static bool xinput_device_control_request(uint8_t rhport, uint8_t stage, tusb_co switch(request->bRequest) { case 0x81: uint8_t serial[0x0B]; - return sizeof(id_data_ms_controller); + return sizeof(id_data_ms_controller); case 0x82: return 0; case 0x83: memcpy(requestBuffer, challenge_response, sizeof(challenge_response)); - return sizeof(challenge_response); + return sizeof(challenge_response); case 0x84: break; case 0x86: @@ -122,15 +139,6 @@ static bool xinput_xfer_callback(uint8_t rhport, uint8_t ep_addr, xfer_result_t return true; } -static void check_and_set_rumble(Gamepad * gamepad, uint8_t * buffer) { - // Check for rumble bytes - starts with 0x00 0x08 - if (!(buffer[0] == 0x00 && buffer[1] == 0x08)) - return; - - gamepad->rumbleState.leftMotor = buffer[3]; - gamepad->rumbleState.rightMotor = buffer[4]; -} - void XInputDriver::initialize() { xinputReport = { .report_id = 0, @@ -183,7 +191,9 @@ USBListener * XInputDriver::get_usb_auth_listener() { return nullptr; } -void XInputDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { +void XInputDriver::process(Gamepad * gamepad) { + Gamepad * processedGamepad = Storage::getInstance().GetProcessedGamepad(); + xinputReport.buttons1 = 0 | (gamepad->pressedUp() ? XBOX_MASK_UP : 0) | (gamepad->pressedDown() ? XBOX_MASK_DOWN : 0) @@ -242,11 +252,44 @@ void XInputDriver::process(Gamepad * gamepad, uint8_t * outBuffer) { usbd_edpt_release(0, endpoint_out); // Release control of OUT endpoint } - if (memcmp(xinput_out_buffer, outBuffer, XINPUT_OUT_SIZE) != 0) { // check if new write to xinput_out_buffer from xinput_xfer_callback - memcpy(outBuffer, xinput_out_buffer, XINPUT_OUT_SIZE); - // Check if this new write to endpoint_out is a rumble packet - check_and_set_rumble(gamepad, outBuffer); - } + //--------------- + if (memcmp(xinput_out_buffer, featureBuffer, XINPUT_OUT_SIZE) != 0) { // check if new write to xinput_out_buffer from xinput_xfer_callback + memcpy(featureBuffer, xinput_out_buffer, XINPUT_OUT_SIZE); + switch (featureBuffer[0]) { + case 0x00: + if (featureBuffer[1] == 0x08) { + if (processedGamepad->auxState.haptics.leftActuator.enabled) { + processedGamepad->auxState.haptics.leftActuator.active = (featureBuffer[3] > 0); + processedGamepad->auxState.haptics.leftActuator.intensity = featureBuffer[3]; + } + if (processedGamepad->auxState.haptics.rightActuator.enabled) { + processedGamepad->auxState.haptics.rightActuator.active = (featureBuffer[4] > 0); + processedGamepad->auxState.haptics.rightActuator.intensity = featureBuffer[4]; + } + } + break; + case 0x01: + // Player LED + if (featureBuffer[1] == 0x03) { + // determine the player ID based on LED status + processedGamepad->auxState.playerID.active = true; + processedGamepad->auxState.playerID.ledValue = featureBuffer[2]; + + if ( featureBuffer[2] == XINPUT_PLED_ON1 ) { + processedGamepad->auxState.playerID.value = 1; + } else if ( featureBuffer[2] == XINPUT_PLED_ON2 ) { + processedGamepad->auxState.playerID.value = 2; + } else if ( featureBuffer[2] == XINPUT_PLED_ON3 ) { + processedGamepad->auxState.playerID.value = 3; + } else if ( featureBuffer[2] == XINPUT_PLED_ON4 ) { + processedGamepad->auxState.playerID.value = 4; + } else { + processedGamepad->auxState.playerID.value = 0; + } + } + break; + } + } } void XInputDriver::processAux() { @@ -266,7 +309,7 @@ void XInputDriver::set_report(uint8_t report_id, hid_report_type_t report_type, // Only XboxOG and Xbox One use vendor control xfer cb bool XInputDriver::vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) { - return false; + return false; } const uint16_t * XInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t langid) { @@ -275,15 +318,15 @@ const uint16_t * XInputDriver::get_descriptor_string_cb(uint8_t index, uint16_t } const uint8_t * XInputDriver::get_descriptor_device_cb() { - return xinput_device_descriptor; + return xinput_device_descriptor; } const uint8_t * XInputDriver::get_hid_descriptor_report_cb(uint8_t itf) { - return nullptr; + return nullptr; } const uint8_t * XInputDriver::get_descriptor_configuration_cb(uint8_t index) { - return xinput_configuration_descriptor; + return xinput_configuration_descriptor; } const uint8_t * XInputDriver::get_descriptor_device_qualifier_cb() { diff --git a/src/gamepad.cpp b/src/gamepad.cpp index 65bf4cc2c..f34aaca93 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -355,10 +355,14 @@ void Gamepad::clearState() { } void Gamepad::clearRumbleState() { - rumbleState.leftMotor = 0; - rumbleState.rightMotor = 0; - rumbleState.leftTrigger = 0; - rumbleState.rightTrigger = 0; + auxState.haptics.leftActuator.active = false; + auxState.haptics.leftActuator.intensity = 0; + auxState.haptics.rightActuator.active = false; + auxState.haptics.rightActuator.intensity = 0; + auxState.haptics.leftTrigger.active = false; + auxState.haptics.leftTrigger.intensity = 0; + auxState.haptics.rightTrigger.active = false; + auxState.haptics.rightTrigger.intensity = 0; } /** diff --git a/src/gp2040.cpp b/src/gp2040.cpp index 6665a6f46..d1e03bc15 100644 --- a/src/gp2040.cpp +++ b/src/gp2040.cpp @@ -260,8 +260,6 @@ void GP2040::run() { Gamepad * gamepad = Storage::getInstance().GetGamepad(); Gamepad * processedGamepad = Storage::getInstance().GetProcessedGamepad(); bool configMode = Storage::getInstance().GetConfigMode(); - uint8_t * featureData = Storage::getInstance().GetFeatureData(); - memset(featureData, 0, 32); // X-Input is the only feature data currently supported while (1) { // LOOP this->getReinitGamepad(gamepad); @@ -299,7 +297,7 @@ void GP2040::run() { memcpy(&processedGamepad->state, &gamepad->state, sizeof(GamepadState)); // Process Input Driver - inputDriver->process(gamepad, featureData); + inputDriver->process(gamepad); // Process USB Report Addons addons.ProcessAddons(ADDON_PROCESS::CORE0_USBREPORT); diff --git a/src/storagemanager.cpp b/src/storagemanager.cpp index 845e94e37..0178ebe3a 100644 --- a/src/storagemanager.cpp +++ b/src/storagemanager.cpp @@ -178,21 +178,6 @@ Gamepad * Storage::GetProcessedGamepad() return processedGamepad; } -void Storage::SetFeatureData(uint8_t * newData) -{ - memcpy(newData, featureData, sizeof(uint8_t)*sizeof(featureData)); -} - -void Storage::ClearFeatureData() -{ - memset(featureData, 0, sizeof(uint8_t)*sizeof(featureData)); -} - -uint8_t * Storage::GetFeatureData() -{ - return featureData; -} - /* Animation stuffs */ AnimationOptions AnimationStorage::getAnimationOptions() { diff --git a/www/server/app.js b/www/server/app.js index ffb33d157..3e509263f 100644 --- a/www/server/app.js +++ b/www/server/app.js @@ -107,6 +107,7 @@ app.get('/api/getGamepadOptions', (req, res) => { ps4AuthType: 0, ps5AuthType: 0, xinputAuthType: 0, + ps4ControllerIDMode: 0, hotkey01: { auxMask: 32768, buttonsMask: 66304, @@ -465,6 +466,9 @@ app.get('/api/getAddonsOptions', (req, res) => { snesPadLatchPin: -1, snesPadDataPin: -1, keyboardHostMap: DEFAULT_KEYBOARD_MAPPING, + keyboardHostMouseLeft: 0, + keyboardHostMouseMiddle: 0, + keyboardHostMouseRight: 0, AnalogInputEnabled: 1, BoardLedAddonEnabled: 1, FocusModeAddonEnabled: 1, diff --git a/www/src/Addons/Keyboard.tsx b/www/src/Addons/Keyboard.tsx index 7ec48491f..36eaa4d7f 100644 --- a/www/src/Addons/Keyboard.tsx +++ b/www/src/Addons/Keyboard.tsx @@ -7,22 +7,58 @@ import * as yup from 'yup'; import Section from '../Components/Section'; import FormControl from '../Components/FormControl'; +import FormSelect from '../Components/FormSelect'; import KeyboardMapper, { validateMappings } from '../Components/KeyboardMapper'; import { baseButtonMappings } from '../Services/WebApi'; import { AppContext } from '../Contexts/AppContext'; +import { + BUTTON_ACTIONS, + PIN_DIRECTIONS, + PinActionValues, + PinDirectionValues, +} from '../Data/Pins'; +import { BUTTON_MASKS_OPTIONS } from '../Data/Buttons'; + export const keyboardScheme = { KeyboardHostAddonEnabled: yup .number() .required() .label('Keyboard Host Add-On Enabled'), + keyboardHostMouseLeft: yup + .number() + .label('Left Mouse Button') + .validateSelectionWhenValue('KeyboardHostAddonEnabled', BUTTON_MASKS_OPTIONS), + keyboardHostMouseMiddle: yup + .number() + .label('Middle Mouse Button') + .validateSelectionWhenValue('KeyboardHostAddonEnabled', BUTTON_MASKS_OPTIONS), + keyboardHostMouseRight: yup + .number() + .label('Right Mouse Button') + .validateSelectionWhenValue('KeyboardHostAddonEnabled', BUTTON_MASKS_OPTIONS), }; export const keyboardState = { keyboardHostMap: baseButtonMappings, + keyboardHostMouseLeft: 0, + keyboardHostMouseMiddle: 0, + keyboardHostMouseRight: 0, KeyboardHostAddonEnabled: 0, }; +const options = Object.entries(BUTTON_ACTIONS) + .map(([key, value]) => ({ + label: key, + value, + })); + +const excludedButtons = [ + 'E1','E2','E3','E4', + 'E5','E6','E7','E8', + 'E9','E10','E11','E12', +]; + const Keyboard = ({ values, errors, @@ -56,12 +92,84 @@ const Keyboard = ({ >

{t('AddonsConfig:keyboard-host-sub-header-text')}

- +
+ +
+
+ +

{t('AddonsConfig:keyboard-host-mouse-header-text')}

+
+ + {BUTTON_MASKS_OPTIONS.map((o, i) => ( + + ))} + +
+
+ + {BUTTON_MASKS_OPTIONS.map((o, i) => ( + + ))} + +
+
+ + {BUTTON_MASKS_OPTIONS.map((o, i) => ( + + ))} + +
{getAvailablePeripherals('usb') ? ( diff --git a/www/src/Components/KeyboardMapper.jsx b/www/src/Components/KeyboardMapper.jsx index 36adb8e93..f0c2103f5 100644 --- a/www/src/Components/KeyboardMapper.jsx +++ b/www/src/Components/KeyboardMapper.jsx @@ -11,6 +11,7 @@ const KeyboardMapper = ({ handleKeyChange, validated, getKeyMappingForButton, + excludeButtons, ...props }) => { const { buttonLabelType, swapTpShareLabels } = buttonLabels; @@ -30,6 +31,7 @@ const KeyboardMapper = ({ {Object.keys(BUTTONS[buttonLabelType]) ?.filter((btn) => !['label', 'value', 'Fn'].includes(btn)) + .filter((btn) => (!excludeButtons?.find(x => x === btn))) .map((button, i) => { let label = BUTTONS[buttonLabelType][button]; if ( diff --git a/www/src/Locales/en/AddonsConfig.jsx b/www/src/Locales/en/AddonsConfig.jsx index c1e9923a5..87981d0dd 100644 --- a/www/src/Locales/en/AddonsConfig.jsx +++ b/www/src/Locales/en/AddonsConfig.jsx @@ -123,9 +123,12 @@ export default { 'snes-extension-data-pin-label': 'Data Pin', 'focus-mode-header-text': 'Focus Mode Configuration', 'focus-mode-pin-label': 'Focus Mode Pin', - 'keyboard-host-header-text': 'Keyboard Host Configuration', - 'keyboard-host-sub-header-text': - 'Following set the data +, - and 5V (optional) pins. Only the + and 5V pin can be configured.', + 'keyboard-host-header-text': 'Keyboard/Mouse Host Configuration', + 'keyboard-host-sub-header-text': 'Keyboard Buttons', + 'keyboard-host-mouse-header-text': 'Mouse Buttons', + 'keyboard-host-left-mouse': 'Left', + 'keyboard-host-middle-mouse': 'Middle', + 'keyboard-host-right-mouse': 'Right', 'pin-config-moved-to-core-text': 'Note: the pins for this add-on are now configured on the Pin Mapping page.', 'input-history-header-text': 'Input History', diff --git a/www/src/Locales/en/LedConfig.jsx b/www/src/Locales/en/LedConfig.jsx index 37e188e28..97678639c 100644 --- a/www/src/Locales/en/LedConfig.jsx +++ b/www/src/Locales/en/LedConfig.jsx @@ -9,7 +9,7 @@ export default { 'led-brightness-steps-label': 'Brightness Steps', }, player: { - 'header-text': 'Player LEDs (XInput)', + 'header-text': 'Player LEDs', 'pwm-sub-header-text': 'For PWM LEDs, set each LED to a dedicated GPIO pin.', 'rgb-sub-header-text': diff --git a/www/src/Locales/en/SettingsPage.jsx b/www/src/Locales/en/SettingsPage.jsx index 2360e56db..6c4f2c425 100644 --- a/www/src/Locales/en/SettingsPage.jsx +++ b/www/src/Locales/en/SettingsPage.jsx @@ -63,6 +63,14 @@ export default { '⏳ WARNING ⏳: PS4 will timeout after 8 minutes without authentication.', 'ps4-usb-host-mode-text': 'INFO: Please ensure USB Peripheral is enabled and a PS4 compatible USB device is plugged in.', + 'ps4-id-mode-label': + 'Identification Mode', + 'ps4-id-mode-explanation-text': + '
  • Console mode is used when connecting primarily to a PS4 console.
  • Remote/Emulation mode should only be used when connecting to an emulation layer or remote playing environment that requires a DualShock 4-compatible controller.
', + 'ps4-id-mode-options': { + 'console': 'Console', + 'emulation': 'Remote/Emulation', + }, 'ps5-mode-explanation-text': 'PS5 mode allows GP2040-CE to run as an authenticated PS5 compatible arcade stick.', 'ps5-mode-warning-text': diff --git a/www/src/Pages/SettingsPage.jsx b/www/src/Pages/SettingsPage.jsx index d29c1e323..033c5eba9 100644 --- a/www/src/Pages/SettingsPage.jsx +++ b/www/src/Pages/SettingsPage.jsx @@ -6,6 +6,7 @@ import * as yup from 'yup'; import { Trans, useTranslation } from 'react-i18next'; import JSEncrypt from 'jsencrypt'; import isNil from 'lodash/isNil'; +import ContextualHelpOverlay from '../Components/ContextualHelpOverlay'; import { AppContext } from '../Contexts/AppContext'; import KeyboardMapper, { validateMappings } from '../Components/KeyboardMapper'; @@ -219,6 +220,11 @@ const PS4_MODES = [ { labelKey: 'ps4-mode-options.arcadestick', value: 7 }, ]; +const PS4_ID_MODES = [ + { labelKey: 'ps4-id-mode-options.console', value: 0 }, + { labelKey: 'ps4-id-mode-options.emulation', value: 1 }, +]; + const AUTHENTICATION_TYPES = [ { labelKey: 'input-mode-authentication.none', value: 0 }, { labelKey: 'input-mode-authentication.key', value: 1 }, @@ -332,6 +338,11 @@ const schema = yup.object().shape({ .number() .required() .label('Switch Touchpad and Share'), + ps4ControllerIDMode: yup + .number() + .required() + .oneOf(PS4_ID_MODES.map((o) => o.value)) + .label('PS4 Controller Identification Mode'), forcedSetupMode: yup .number() .required() @@ -431,6 +442,8 @@ const FormContext = ({ setButtonLabels, setKeyMappings }) => { if (!!values.ps5AuthType) values.ps5AuthType = parseInt(values.ps5AuthType); if (!!values.xinputAuthType) values.xinputAuthType = parseInt(values.xinputAuthType); + if (!!values.ps4ControllerIDMode) + values.ps4ControllerIDMode = parseInt(values.ps4ControllerIDMode); setButtonLabels({ swapTpShareLabels: @@ -716,6 +729,38 @@ export default function SettingsPage() { /> + + + + {t('SettingsPage:ps4-id-mode-label')} + , li:
  • }} + /> + } + /> + + + {PS4_ID_MODES.map((o) => ( + + ))} + + + {generateAuthSelection( inputMode, t('SettingsPage:auth-settings-label'), @@ -845,6 +890,38 @@ export default function SettingsPage() { /> + + + + {t('SettingsPage:ps4-id-mode-label')} + , li:
  • }} + /> + } + /> + + + {PS4_ID_MODES.map((o) => ( + + ))} + + + {generateAuthSelection( inputMode, t('SettingsPage:auth-settings-label'), From 37f31ac23a3f243353f9bd2f5946ea0a66f404db Mon Sep 17 00:00:00 2001 From: Shellever Date: Tue, 17 Sep 2024 09:09:35 +0800 Subject: [PATCH 2/8] Fixed RGB LED remains off when the usb disconnected and reconnected (#1105) * Fixed RGB LED remains off when the usb disconnected and reconnected * Update usbdriver.cpp Fixing this one as both of these should be false on mount and unmount --------- Co-authored-by: Luke A --- src/usbdriver.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/usbdriver.cpp b/src/usbdriver.cpp index c7c5d73c3..3710f1d3b 100644 --- a/src/usbdriver.cpp +++ b/src/usbdriver.cpp @@ -39,12 +39,14 @@ void tud_hid_set_report_cb(uint8_t itf, uint8_t report_id, hid_report_type_t rep void tud_mount_cb(void) { usb_mounted = true; + usb_suspended = false; } // Invoked when device is unmounted void tud_umount_cb(void) { usb_mounted = false; + usb_suspended = false; } // Invoked when usb bus is suspended @@ -97,4 +99,4 @@ uint8_t const* tud_descriptor_device_qualifier_cb() { return DriverManager::getInstance().getDriver()->get_descriptor_device_qualifier_cb(); } -#endif \ No newline at end of file +#endif From 6c97bc02ee83bdd5d35b5f4c6fe4565fa4b88118 Mon Sep 17 00:00:00 2001 From: Pelsin Date: Tue, 17 Sep 2024 03:10:49 +0200 Subject: [PATCH 3/8] Add hotkey for decrementing profile number (#1130) * Add hotkey for decrementing profile number * Code style change --- headers/storagemanager.h | 1 + proto/enums.proto | 1 + src/gamepad.cpp | 7 +++++++ src/storagemanager.cpp | 7 +++++++ www/src/Locales/en/SettingsPage.jsx | 1 + www/src/Pages/SettingsPage.jsx | 1 + 6 files changed, 18 insertions(+) diff --git a/headers/storagemanager.h b/headers/storagemanager.h index 36a2d7e31..a8908b54e 100644 --- a/headers/storagemanager.h +++ b/headers/storagemanager.h @@ -66,6 +66,7 @@ class Storage { void setProfile(const uint32_t); // profile support for multiple mappings void nextProfile(); + void previousProfile(); void setFunctionalPinMappings(); void ResetSettings(); // EEPROM Reset Feature diff --git a/proto/enums.proto b/proto/enums.proto index f1531f4b6..db76de54b 100644 --- a/proto/enums.proto +++ b/proto/enums.proto @@ -299,6 +299,7 @@ enum GamepadHotkey HOTKEY_DPAD_DOWN = 39; HOTKEY_DPAD_LEFT = 40; HOTKEY_DPAD_RIGHT = 41; + HOTKEY_PREVIOUS_PROFILE = 42; } // This has to be kept in sync with LEDFormat in NeoPico.hpp diff --git a/src/gamepad.cpp b/src/gamepad.cpp index f34aaca93..66af329c6 100644 --- a/src/gamepad.cpp +++ b/src/gamepad.cpp @@ -551,6 +551,13 @@ void Gamepad::processHotkeyAction(GamepadHotkey action) { reqSave = true; } break; + case HOTKEY_PREVIOUS_PROFILE: + if (action != lastAction) { + Storage::getInstance().previousProfile(); + userRequestedReinit = true; + reqSave = true; + } + break; default: // Unknown action return; } diff --git a/src/storagemanager.cpp b/src/storagemanager.cpp index 0178ebe3a..3eb0c25a2 100644 --- a/src/storagemanager.cpp +++ b/src/storagemanager.cpp @@ -123,6 +123,13 @@ void Storage::nextProfile() { this->config.gamepadOptions.profileNumber = (this->config.gamepadOptions.profileNumber % 4) + 1; } +void Storage::previousProfile() +{ + if (this->config.gamepadOptions.profileNumber == 1) + this->config.gamepadOptions.profileNumber = 4; + else + this->config.gamepadOptions.profileNumber -= 1; +} void Storage::setFunctionalPinMappings() { diff --git a/www/src/Locales/en/SettingsPage.jsx b/www/src/Locales/en/SettingsPage.jsx index 6c4f2c425..3e85ee61e 100644 --- a/www/src/Locales/en/SettingsPage.jsx +++ b/www/src/Locales/en/SettingsPage.jsx @@ -127,6 +127,7 @@ export default { 'load-profile-4': 'Load Profile #4', 'reboot-default': 'Reboot GP2040-CE', 'next-profile': 'Next Profile', + 'previous-profile': 'Previous Profile', }, 'forced-setup-mode-label': 'Forced Setup Mode', 'forced-setup-mode-options': { diff --git a/www/src/Pages/SettingsPage.jsx b/www/src/Pages/SettingsPage.jsx index 033c5eba9..c5c1273b9 100644 --- a/www/src/Pages/SettingsPage.jsx +++ b/www/src/Pages/SettingsPage.jsx @@ -253,6 +253,7 @@ const HOTKEY_ACTIONS = [ { labelKey: 'hotkey-actions.load-profile-3', value: 17 }, { labelKey: 'hotkey-actions.load-profile-4', value: 18 }, { labelKey: 'hotkey-actions.next-profile', value: 35 }, + { labelKey: 'hotkey-actions.previous-profile', value: 42 }, { labelKey: 'hotkey-actions.l3-button', value: 19 }, { labelKey: 'hotkey-actions.r3-button', value: 20 }, { labelKey: 'hotkey-actions.touchpad-button', value: 21 }, From ca3bac9324b9d24beda3c5f384688a65e0e85a2c Mon Sep 17 00:00:00 2001 From: Pelsin Date: Tue, 17 Sep 2024 03:23:17 +0200 Subject: [PATCH 4/8] Minor fixes (#1137) * Copy for pin viewer * Change turbo validation in ui to be the same as TURBO_SHOT_MIN in turbo addon --- www/src/Addons/Turbo.tsx | 2 +- www/src/Locales/en/PinMapping.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/www/src/Addons/Turbo.tsx b/www/src/Addons/Turbo.tsx index 56dd8d51e..1c596e981 100644 --- a/www/src/Addons/Turbo.tsx +++ b/www/src/Addons/Turbo.tsx @@ -58,7 +58,7 @@ export const turboScheme = { turboShotCount: yup .number() .label('Turbo Shot Count') - .validateRangeWhenValue('TurboInputEnabled', 5, 30), + .validateRangeWhenValue('TurboInputEnabled', 2, 30), shmupMode: yup .number() .label('Shmup Mode Enabled') diff --git a/www/src/Locales/en/PinMapping.jsx b/www/src/Locales/en/PinMapping.jsx index bd85b1f9b..2d27bdb69 100644 --- a/www/src/Locales/en/PinMapping.jsx +++ b/www/src/Locales/en/PinMapping.jsx @@ -1,6 +1,6 @@ export default { 'header-text': 'Pin Mapping', - 'sub-header-text': `If you're unsure what button is connect to what pin, try out the pin viewer.`, + 'sub-header-text': `Use Pin Viewer to see button to pin connection.`, 'alert-text': "Mapping buttons to pins that aren't connected or available can leave the device in non-functional state. To clear the invalid configuration go to the <2>Reset Settings page.", 'pin-viewer': 'Pin viewer', From 9e3d7a6059b9e8c2297b1e88227c159f71b0930f Mon Sep 17 00:00:00 2001 From: Luke A Date: Mon, 16 Sep 2024 22:08:08 -0400 Subject: [PATCH 5/8] Add board flash 0x9f SPI command to web config (#1075) * [ImgBot] Optimize images *Total -- 11,807.83kb -> 10,597.19kb (10.25%) /configs/MavercadeRev2/assets/Rev2_config_pic.jpg -- 1,148.71kb -> 1,001.39kb (12.83%) /configs/MavercadeRev2/assets/Rev2_thumbnail.png -- 4,501.00kb -> 3,984.05kb (11.49%) /configs/ZeroRhythm/Assets/ZeroThythm 2.jpg -- 2,954.52kb -> 2,669.00kb (9.66%) /configs/ZeroRhythm/Assets/ZeroRhythm 1.jpg -- 2,687.40kb -> 2,428.72kb (9.63%) /configs/MavercadeRev1/assets/Rev1_config_pic.png -- 516.19kb -> 514.02kb (0.42%) Signed-off-by: ImgBotApp * Added actual board flash info to homepage * Missing define * Bump up the TX/RX memory space even more * Last attempt at correctness * Updated system flash size to be a static int32_t only called once at start of web --------- Signed-off-by: ImgBotApp Co-authored-by: ImgBotApp --- headers/system.h | 4 +++- src/configs/webconfig.cpp | 5 +++++ src/system.cpp | 16 ++++++++++++++++ www/server/app.js | 9 +++++---- www/src/Locales/en/HomePage.jsx | 1 + www/src/Pages/HomePage.jsx | 6 +++++- 6 files changed, 35 insertions(+), 6 deletions(-) diff --git a/headers/system.h b/headers/system.h index 2154f970a..4319cf26d 100644 --- a/headers/system.h +++ b/headers/system.h @@ -4,10 +4,12 @@ #include namespace System { - // Returns the size of on-board flash memory in bytes + // Returns the size of on-board flash memory reserved by the config uint32_t getTotalFlash(); // Returns the amount of on-board flash memory used by the firmware in bytes uint32_t getUsedFlash(); + // Returns the amount of physical flash memory on the board + uint32_t getPhysicalFlash(); // Returns the amount of memory used for static allocations in bytes uint32_t getStaticAllocs(); // Returns the total size of heap memory in bytes diff --git a/src/configs/webconfig.cpp b/src/configs/webconfig.cpp index d0f6c7643..c10578b6f 100644 --- a/src/configs/webconfig.cpp +++ b/src/configs/webconfig.cpp @@ -214,7 +214,11 @@ static void __attribute__((noinline)) writeDoc(DynamicJsonDocument& doc, const K static int32_t cleanPin(int32_t pin) { return isValidPin(pin) ? pin : -1; } +static uint32_t systemFlashSize; + void WebConfig::setup() { + // System Flash Size must be called once + systemFlashSize = System::getPhysicalFlash(); rndis_init(); } @@ -2106,6 +2110,7 @@ std::string getMemoryReport() DynamicJsonDocument doc(LWIP_HTTPD_POST_MAX_PAYLOAD_LEN); writeDoc(doc, "totalFlash", System::getTotalFlash()); writeDoc(doc, "usedFlash", System::getUsedFlash()); + writeDoc(doc, "physicalFlash", systemFlashSize); writeDoc(doc, "staticAllocs", System::getStaticAllocs()); writeDoc(doc, "totalHeap", System::getTotalHeap()); writeDoc(doc, "usedHeap", System::getUsedHeap()); diff --git a/src/system.cpp b/src/system.cpp index d91caa70a..036e89741 100644 --- a/src/system.cpp +++ b/src/system.cpp @@ -28,6 +28,22 @@ uint32_t System::getUsedFlash() { return &__flash_binary_end - &__flash_binary_start; } +#define STORAGE_CMD_TOTAL_BYTES 3 + +// Standard Storage instruction: 9f command prefix, Manufacturer ID, Flash Type, Capacity +#define FLASH_STORAGE_CMD 0x9f +#define FLASH_STORAGE_DATA_BYTES 3 +#define FLASH_STORAGE_TOTAL_BYTES (1 + FLASH_STORAGE_DATA_BYTES) + +uint32_t System::getPhysicalFlash() { + + uint8_t txbuf[FLASH_STORAGE_TOTAL_BYTES] = {0}; + uint8_t rxbuf[FLASH_STORAGE_TOTAL_BYTES] = {0}; + txbuf[0] = FLASH_STORAGE_CMD; + flash_do_cmd(txbuf, rxbuf, FLASH_STORAGE_TOTAL_BYTES); + return 1 << rxbuf[3]; +} + uint32_t System::getStaticAllocs() { const uint32_t inMemorySegmentsSize = reinterpret_cast(&__bss_end__) - SRAM_BASE; const uint32_t stackSize = &__StackTop - &__StackLimit; diff --git a/www/server/app.js b/www/server/app.js index 3e509263f..aacb988b3 100644 --- a/www/server/app.js +++ b/www/server/app.js @@ -761,11 +761,12 @@ app.get('/api/reboot', (req, res) => { app.get('/api/getMemoryReport', (req, res) => { return res.send({ - totalFlash: 2048, - usedFlash: 1048, + totalFlash: 2048 * 1024, + usedFlash: 1048 * 1024, + physicalFlash: 2048 * 1024, staticAllocs: 200, - totalHeap: 2048, - usedHeap: 1048, + totalHeap: 2048 * 1024, + usedHeap: 1048 * 1024, }); }); diff --git a/www/src/Locales/en/HomePage.jsx b/www/src/Locales/en/HomePage.jsx index 4cc9b0044..1cc7eba8e 100644 --- a/www/src/Locales/en/HomePage.jsx +++ b/www/src/Locales/en/HomePage.jsx @@ -4,6 +4,7 @@ export default { 'header-text': 'Welcome to the GP2040-CE Web Configurator!', 'latest-text': 'Latest: {{version}}', 'memory-flash-text': 'Flash', + 'memory-board-text': 'Board Flash', 'memory-header-text': 'Memory (KB)', 'memory-heap-text': 'Heap', 'memory-static-allocations-text': 'Static Allocations', diff --git a/www/src/Pages/HomePage.jsx b/www/src/Pages/HomePage.jsx index e6ba5570c..5f4f08b6e 100644 --- a/www/src/Pages/HomePage.jsx +++ b/www/src/Pages/HomePage.jsx @@ -55,11 +55,12 @@ export default function HomePage() { WebApi.getMemoryReport(setLoading) .then((response) => { - const { totalFlash, usedFlash, staticAllocs, totalHeap, usedHeap } = + const { totalFlash, usedFlash, physicalFlash, staticAllocs, totalHeap, usedHeap } = response; setMemoryReport({ totalFlash: toKB(totalFlash), usedFlash: toKB(usedFlash), + physicalFlash: toKB(physicalFlash), staticAllocs: toKB(staticAllocs), totalHeap: toKB(totalHeap), usedHeap: toKB(usedHeap), @@ -111,6 +112,9 @@ export default function HomePage() { {t('HomePage:memory-static-allocations-text')}:{' '} {memoryReport.staticAllocs} +
    + {t('HomePage:memory-board-text')}: {memoryReport.physicalFlash} +
    )} From 96e97b28be0047b0b153ea158e473bd93b52309e Mon Sep 17 00:00:00 2001 From: brett ohland Date: Mon, 16 Sep 2024 20:24:42 -0600 Subject: [PATCH 6/8] Updates Flatbox Rev.5 Config & Header Documentation (#1099) - Adds missing switch label documentation to BoardConfig header for Flatbox Rev 5 - Adds labels and pinouts to Flatbox Rev 5 Readme Co-authored-by: Luke A --- configs/FlatboxRev5/BoardConfig.h | 41 ++++++++++++++++--------------- configs/FlatboxRev5/Readme.md | 41 ++++++++++++++++--------------- 2 files changed, 42 insertions(+), 40 deletions(-) diff --git a/configs/FlatboxRev5/BoardConfig.h b/configs/FlatboxRev5/BoardConfig.h index d4abb22f8..f48a50d46 100644 --- a/configs/FlatboxRev5/BoardConfig.h +++ b/configs/FlatboxRev5/BoardConfig.h @@ -13,25 +13,26 @@ // Main pin mapping Configuration // Mapping between Flatbox Rev4 switch number (as silkscreened) and GPIO pin listed under "Flatbox Rev4 SW#" -// // Flatbox Rev5 SW# | GP2040 | Xinput | Switch | PS3/4/5 | Dinput | Arcade | -#define GPIO_PIN_10 GpioAction::BUTTON_PRESS_UP // UP | UP | UP | UP | UP | UP | -#define GPIO_PIN_12 GpioAction::BUTTON_PRESS_DOWN // DOWN | DOWN | DOWN | DOWN | DOWN | DOWN | -#define GPIO_PIN_11 GpioAction::BUTTON_PRESS_RIGHT // RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | -#define GPIO_PIN_13 GpioAction::BUTTON_PRESS_LEFT // LEFT | LEFT | LEFT | LEFT | LEFT | LEFT | -#define GPIO_PIN_09 GpioAction::BUTTON_PRESS_B1 // B1 | A | B | Cross | 2 | K1 | -#define GPIO_PIN_07 GpioAction::BUTTON_PRESS_B2 // B2 | B | A | Circle | 3 | K2 | -#define GPIO_PIN_05 GpioAction::BUTTON_PRESS_R2 // R2 | RT | ZR | R2 | 8 | K3 | -#define GPIO_PIN_03 GpioAction::BUTTON_PRESS_L2 // L2 | LT | ZL | L2 | 7 | K4 | -#define GPIO_PIN_08 GpioAction::BUTTON_PRESS_B3 // B3 | X | Y | Square | 1 | P1 | -#define GPIO_PIN_06 GpioAction::BUTTON_PRESS_B4 // B4 | Y | X | Triangle | 4 | P2 | -#define GPIO_PIN_04 GpioAction::BUTTON_PRESS_R1 // R1 | RB | R | R1 | 6 | P3 | -#define GPIO_PIN_02 GpioAction::BUTTON_PRESS_L1 // L1 | LB | L | L1 | 5 | P4 | -#define GPIO_PIN_15 GpioAction::BUTTON_PRESS_S1 // S1 | Back | Minus | Select | 9 | Coin | -#define GPIO_PIN_14 GpioAction::BUTTON_PRESS_S2 // S2 | Start | Plus | Start | 10 | Start | -#define GPIO_PIN_28 GpioAction::BUTTON_PRESS_L3 // L3 | LS | LS | L3 | 11 | LS | -#define GPIO_PIN_29 GpioAction::BUTTON_PRESS_R3 // R3 | RS | RS | R3 | 12 | RS | -#define GPIO_PIN_26 GpioAction::BUTTON_PRESS_A1 // A1 | Guide | Home | PS | 13 | ~ | -#define GPIO_PIN_27 GpioAction::BUTTON_PRESS_A2 // A2 | ~ | Capture | ~ | 14 | ~ | +// // | Flatbox Rev5 SW# | GP2040 | Xinput | Switch | PS3/4/5 | Dinput | Arcade | +#define GPIO_PIN_14 GpioAction::BUTTON_PRESS_S2 // | S1 | S2 | Start | Plus | Start | 10 | Start | +#define GPIO_PIN_15 GpioAction::BUTTON_PRESS_S1 // | S2 | S1 | Back | Minus | Select | 9 | Coin | +#define GPIO_PIN_26 GpioAction::BUTTON_PRESS_A1 // | S3 | A1 | Guide | Home | PS | 13 | ~ | +#define GPIO_PIN_27 GpioAction::BUTTON_PRESS_A2 // | S4 | A2 | ~ | Capture | ~ | 14 | ~ | +#define GPIO_PIN_28 GpioAction::BUTTON_PRESS_L3 // | S5 | L3 | LS | LS | L3 | 11 | LS | +#define GPIO_PIN_29 GpioAction::BUTTON_PRESS_R3 // | S6 | R3 | RS | RS | R3 | 12 | RS | +#define GPIO_PIN_13 GpioAction::BUTTON_PRESS_LEFT // | S7 | LEFT | LEFT | LEFT | LEFT | LEFT | LEFT | +#define GPIO_PIN_12 GpioAction::BUTTON_PRESS_DOWN // | S8 | DOWN | DOWN | DOWN | DOWN | DOWN | DOWN | +#define GPIO_PIN_11 GpioAction::BUTTON_PRESS_RIGHT // | S9 | RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | +#define GPIO_PIN_08 GpioAction::BUTTON_PRESS_B3 // | S10 | B3 | X | Y | Square | 1 | P1 | +#define GPIO_PIN_06 GpioAction::BUTTON_PRESS_B4 // | S11 | B4 | Y | X | Triangle | 4 | P2 | +#define GPIO_PIN_04 GpioAction::BUTTON_PRESS_R1 // | S12 | R1 | RB | R | R1 | 6 | P3 | +#define GPIO_PIN_02 GpioAction::BUTTON_PRESS_L1 // | S13 | L1 | LB | L | L1 | 5 | P4 | +#define GPIO_PIN_09 GpioAction::BUTTON_PRESS_B1 // | S14 | B1 | A | B | Cross | 2 | K1 | +#define GPIO_PIN_07 GpioAction::BUTTON_PRESS_B2 // | S15 | B2 | B | A | Circle | 3 | K2 | +#define GPIO_PIN_05 GpioAction::BUTTON_PRESS_R2 // | S16 | R2 | RT | ZR | R2 | 8 | K3 | +#define GPIO_PIN_03 GpioAction::BUTTON_PRESS_L2 // | S17 | L2 | LT | ZL | L2 | 7 | K4 | +#define GPIO_PIN_10 GpioAction::BUTTON_PRESS_UP // | S18 | UP | UP | UP | UP | UP | UP | + // Keyboard Mapping Configuration // // GP2040 | Xinput | Switch | PS3/4/5 | Dinput | Arcade | @@ -55,4 +56,4 @@ #define KEY_BUTTON_A2 HID_KEY_F2 // A2 | ~ | Capture | ~ | 14 | ~ | #define KEY_BUTTON_FN -1 // Hotkey Function | -#endif \ No newline at end of file +#endif diff --git a/configs/FlatboxRev5/Readme.md b/configs/FlatboxRev5/Readme.md index e5f1167a6..db867b895 100644 --- a/configs/FlatboxRev5/Readme.md +++ b/configs/FlatboxRev5/Readme.md @@ -6,23 +6,24 @@ Configuration for the [Flatbox rev5](https://github.com/jfedor2/flatbox/tree/mas ## Main Pin Mapping Configuration -| RP2040 Pin | Action | GP2040 | Xinput | Switch | PS3/4/5 | Dinput | Arcade | -|------------|-------------------------------|--------|--------|--------|----------|--------|--------| -| GPIO_PIN_10| GpioAction::BUTTON_PRESS_UP | UP | UP | UP | UP | UP | UP | -| GPIO_PIN_12| GpioAction::BUTTON_PRESS_DOWN | DOWN | DOWN | DOWN | DOWN | DOWN | DOWN | -| GPIO_PIN_11| GpioAction::BUTTON_PRESS_RIGHT| RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | -| GPIO_PIN_13| GpioAction::BUTTON_PRESS_LEFT | LEFT | LEFT | LEFT | LEFT | LEFT | LEFT | -| GPIO_PIN_09| GpioAction::BUTTON_PRESS_B1 | B1 | A | B | Cross | 2 | K1 | -| GPIO_PIN_07| GpioAction::BUTTON_PRESS_B2 | B2 | B | A | Circle | 3 | K2 | -| GPIO_PIN_05| GpioAction::BUTTON_PRESS_R2 | R2 | RT | ZR | R2 | 8 | K3 | -| GPIO_PIN_03| GpioAction::BUTTON_PRESS_L2 | L2 | LT | ZL | L2 | 7 | K4 | -| GPIO_PIN_08| GpioAction::BUTTON_PRESS_B3 | B3 | X | Y | Square | 1 | P1 | -| GPIO_PIN_06| GpioAction::BUTTON_PRESS_B4 | B4 | Y | X | Triangle | 4 | P2 | -| GPIO_PIN_04| GpioAction::BUTTON_PRESS_R1 | R1 | RB | R | R1 | 6 | P3 | -| GPIO_PIN_02| GpioAction::BUTTON_PRESS_L1 | L1 | LB | L | L1 | 5 | P4 | -| GPIO_PIN_15| GpioAction::BUTTON_PRESS_S1 | S1 | Back | Minus | Select | 9 | Coin | -| GPIO_PIN_14| GpioAction::BUTTON_PRESS_S2 | S2 | Start | Plus | Start | 10 | Start | -| GPIO_PIN_28| GpioAction::BUTTON_PRESS_L3 | L3 | LS | LS | L3 | 11 | LS | -| GPIO_PIN_29| GpioAction::BUTTON_PRESS_R3 | R3 | RS | RS | R3 | 12 | RS | -| GPIO_PIN_26| GpioAction::BUTTON_PRESS_A1 | A1 | Guide | Home | PS | 13 | ~ | -| GPIO_PIN_27| GpioAction::BUTTON_PRESS_A2 | A2 | ~ | Capture| ~ | 14 | ~ | \ No newline at end of file +| RP2040 Pin | Action | Flatbox Rev5 SW# | GP2040 | Xinput | Switch | PS3/4/5 | Dinput | Arcade | +| ----------- | ------------------------------- | ---------------- | ------ | ------ | ------- | -------- | ------ | ------ | +| GPIO_PIN_14 | GpioAction::BUTTON_PRESS_S2 | S1 | S2 | Start | Plus | Start | 10 | Start | +| GPIO_PIN_15 | GpioAction::BUTTON_PRESS_S1 | S2 | S1 | Back | Minus | Select | 9 | Coin | +| GPIO_PIN_26 | GpioAction::BUTTON_PRESS_A1 | S3 | A1 | Guide | Home | PS | 13 | ~ | +| GPIO_PIN_27 | GpioAction::BUTTON_PRESS_A2 | S4 | A2 | ~ | Capture | ~ | 14 | ~ | +| GPIO_PIN_28 | GpioAction::BUTTON_PRESS_L3 | S5 | L3 | LS | LS | L3 | 11 | LS | +| GPIO_PIN_29 | GpioAction::BUTTON_PRESS_R3 | S6 | R3 | RS | RS | R3 | 12 | RS | +| GPIO_PIN_13 | GpioAction::BUTTON_PRESS_LEFT | S7 | LEFT | LEFT | LEFT | LEFT | LEFT | LEFT | +| GPIO_PIN_12 | GpioAction::BUTTON_PRESS_DOWN | S8 | DOWN | DOWN | DOWN | DOWN | DOWN | DOWN | +| GPIO_PIN_11 | GpioAction::BUTTON_PRESS_RIGHT | S9 | RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | RIGHT | +| GPIO_PIN_08 | GpioAction::BUTTON_PRESS_B3 | S10 | B3 | X | Y | Square | 1 | P1 | +| GPIO_PIN_06 | GpioAction::BUTTON_PRESS_B4 | S11 | B4 | Y | X | Triangle | 4 | P2 | +| GPIO_PIN_04 | GpioAction::BUTTON_PRESS_R1 | S12 | R1 | RB | R | R1 | 6 | P3 | +| GPIO_PIN_02 | GpioAction::BUTTON_PRESS_L1 | S13 | L1 | LB | L | L1 | 5 | P4 | +| GPIO_PIN_09 | GpioAction::BUTTON_PRESS_B1 | S14 | B1 | A | B | Cross | 2 | K1 | +| GPIO_PIN_07 | GpioAction::BUTTON_PRESS_B2 | S15 | B2 | B | A | Circle | 3 | K2 | +| GPIO_PIN_05 | GpioAction::BUTTON_PRESS_R2 | S16 | R2 | RT | ZR | R2 | 8 | K3 | +| GPIO_PIN_03 | GpioAction::BUTTON_PRESS_L2 | S17 | L2 | LT | ZL | L2 | 7 | K4 | +| GPIO_PIN_10 | GpioAction::BUTTON_PRESS_UP | S18 | UP | UP | UP | UP | UP | UP | + From f26f03caec60c4443d80cfdf7b5c90ffee474653 Mon Sep 17 00:00:00 2001 From: Roderick MacCrimmon Date: Fri, 20 Sep 2024 09:43:54 -0600 Subject: [PATCH 7/8] Make extra keys usable in keyboard mode (#1128) * Add E1 button as a test * Add remaining Extra keys to KeyboardMapping * Add support for E1-12 buttons in input history * Revert "Add support for E1-12 buttons in input history" This reverts commit bd21be6df170e1a1fa0bc22b6abfeb7793e5e5c5. * Update KeyboardMapping enum, re-order merged lines --- proto/config.proto | 13 +++++++++++++ src/configs/webconfig.cpp | 26 ++++++++++++++++++++++++- src/drivers/keyboard/KeyboardDriver.cpp | 12 ++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/proto/config.proto b/proto/config.proto index 05511c0a1..caaa13a9c 100644 --- a/proto/config.proto +++ b/proto/config.proto @@ -53,6 +53,19 @@ message KeyboardMapping optional uint32 keyButtonA2 = 18; optional uint32 keyButtonA3 = 19; optional uint32 keyButtonA4 = 20; + optional uint32 keyButtonE1 = 21; + optional uint32 keyButtonE2 = 22; + optional uint32 keyButtonE3 = 23; + optional uint32 keyButtonE4 = 24; + optional uint32 keyButtonE5 = 25; + optional uint32 keyButtonE6 = 26; + optional uint32 keyButtonE7 = 27; + optional uint32 keyButtonE8 = 28; + optional uint32 keyButtonE9 = 29; + optional uint32 keyButtonE10 = 30; + optional uint32 keyButtonE11 = 31; + optional uint32 keyButtonE12 = 32; + } message HotkeyEntry diff --git a/src/configs/webconfig.cpp b/src/configs/webconfig.cpp index c10578b6f..3a36895bc 100644 --- a/src/configs/webconfig.cpp +++ b/src/configs/webconfig.cpp @@ -1133,6 +1133,18 @@ std::string setKeyMappings() readDoc(keyboardMapping.keyButtonA2, doc, "A2"); readDoc(keyboardMapping.keyButtonA3, doc, "A3"); readDoc(keyboardMapping.keyButtonA4, doc, "A4"); + readDoc(keyboardMapping.keyButtonE1, doc, "E1"); + readDoc(keyboardMapping.keyButtonE2, doc, "E2"); + readDoc(keyboardMapping.keyButtonE3, doc, "E3"); + readDoc(keyboardMapping.keyButtonE4, doc, "E4"); + readDoc(keyboardMapping.keyButtonE5, doc, "E5"); + readDoc(keyboardMapping.keyButtonE6, doc, "E6"); + readDoc(keyboardMapping.keyButtonE7, doc, "E7"); + readDoc(keyboardMapping.keyButtonE8, doc, "E8"); + readDoc(keyboardMapping.keyButtonE9, doc, "E9"); + readDoc(keyboardMapping.keyButtonE10, doc, "E10"); + readDoc(keyboardMapping.keyButtonE11, doc, "E11"); + readDoc(keyboardMapping.keyButtonE12, doc, "E12"); Storage::getInstance().save(); @@ -1164,7 +1176,19 @@ std::string getKeyMappings() writeDoc(doc, "A2", keyboardMapping.keyButtonA2); writeDoc(doc, "A3", keyboardMapping.keyButtonA3); writeDoc(doc, "A4", keyboardMapping.keyButtonA4); - + writeDoc(doc, "E1", keyboardMapping.keyButtonE1); + writeDoc(doc, "E2", keyboardMapping.keyButtonE2); + writeDoc(doc, "E3", keyboardMapping.keyButtonE3); + writeDoc(doc, "E4", keyboardMapping.keyButtonE4); + writeDoc(doc, "E5", keyboardMapping.keyButtonE5); + writeDoc(doc, "E6", keyboardMapping.keyButtonE6); + writeDoc(doc, "E7", keyboardMapping.keyButtonE7); + writeDoc(doc, "E8", keyboardMapping.keyButtonE8); + writeDoc(doc, "E9", keyboardMapping.keyButtonE9); + writeDoc(doc, "E10", keyboardMapping.keyButtonE10); + writeDoc(doc, "E11", keyboardMapping.keyButtonE11); + writeDoc(doc, "E12", keyboardMapping.keyButtonE12); + return serialize_json(doc); } diff --git a/src/drivers/keyboard/KeyboardDriver.cpp b/src/drivers/keyboard/KeyboardDriver.cpp index ccc39b283..47539fa15 100644 --- a/src/drivers/keyboard/KeyboardDriver.cpp +++ b/src/drivers/keyboard/KeyboardDriver.cpp @@ -72,6 +72,18 @@ void KeyboardDriver::process(Gamepad * gamepad) { if(gamepad->pressedR3()) { pressKey(keyboardMapping.keyButtonR3); } if(gamepad->pressedA1()) { pressKey(keyboardMapping.keyButtonA1); } if(gamepad->pressedA2()) { pressKey(keyboardMapping.keyButtonA2); } + if(gamepad->pressedE1()) { pressKey(keyboardMapping.keyButtonE1); } + if(gamepad->pressedE2()) { pressKey(keyboardMapping.keyButtonE2); } + if(gamepad->pressedE3()) { pressKey(keyboardMapping.keyButtonE3); } + if(gamepad->pressedE4()) { pressKey(keyboardMapping.keyButtonE4); } + if(gamepad->pressedE5()) { pressKey(keyboardMapping.keyButtonE5); } + if(gamepad->pressedE6()) { pressKey(keyboardMapping.keyButtonE6); } + if(gamepad->pressedE7()) { pressKey(keyboardMapping.keyButtonE7); } + if(gamepad->pressedE8()) { pressKey(keyboardMapping.keyButtonE8); } + if(gamepad->pressedE9()) { pressKey(keyboardMapping.keyButtonE9); } + if(gamepad->pressedE10()) { pressKey(keyboardMapping.keyButtonE10); } + if(gamepad->pressedE11()) { pressKey(keyboardMapping.keyButtonE11); } + if(gamepad->pressedE12()) { pressKey(keyboardMapping.keyButtonE12); } // Wake up TinyUSB device if (tud_suspended()) From fd18b3cf5605e66dfc3453e71a2df502bad6f599 Mon Sep 17 00:00:00 2001 From: Luke A Date: Fri, 20 Sep 2024 13:29:42 -0400 Subject: [PATCH 8/8] Keyboard Driver - A3/A4 Fix (#1144) We added A3 and A4 assignment, but need to add it to the Keyboard Driver --- src/drivers/keyboard/KeyboardDriver.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/drivers/keyboard/KeyboardDriver.cpp b/src/drivers/keyboard/KeyboardDriver.cpp index 47539fa15..2d94ac0a6 100644 --- a/src/drivers/keyboard/KeyboardDriver.cpp +++ b/src/drivers/keyboard/KeyboardDriver.cpp @@ -72,6 +72,8 @@ void KeyboardDriver::process(Gamepad * gamepad) { if(gamepad->pressedR3()) { pressKey(keyboardMapping.keyButtonR3); } if(gamepad->pressedA1()) { pressKey(keyboardMapping.keyButtonA1); } if(gamepad->pressedA2()) { pressKey(keyboardMapping.keyButtonA2); } + if(gamepad->pressedA3()) { pressKey(keyboardMapping.keyButtonA3); } + if(gamepad->pressedA4()) { pressKey(keyboardMapping.keyButtonA4); } if(gamepad->pressedE1()) { pressKey(keyboardMapping.keyButtonE1); } if(gamepad->pressedE2()) { pressKey(keyboardMapping.keyButtonE2); } if(gamepad->pressedE3()) { pressKey(keyboardMapping.keyButtonE3); }