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'),