From 500fcddaa87b0684dc418f5bf72c31d0a20eadc4 Mon Sep 17 00:00:00 2001 From: cathery Date: Sun, 3 Nov 2019 22:38:24 +0300 Subject: [PATCH] minor attempts at vibration +dualshock dummy class --- ControllerUSB/include/ControllerTypes.h | 6 + ControllerUSB/include/Controllers.h | 20 +- .../Controllers/Dualshock4Controller.h | 82 ++++++ .../Controllers/Dualshock4Controller.cpp | 240 ++++++++++++++++++ .../source/SwitchAbstractedPadHandler.cpp | 31 ++- SwitchUSB/source/SwitchHDLHandler.cpp | 28 +- source/mainLoop.cpp | 23 +- 7 files changed, 412 insertions(+), 18 deletions(-) create mode 100644 ControllerUSB/include/Controllers/Dualshock4Controller.h create mode 100644 ControllerUSB/source/Controllers/Dualshock4Controller.cpp diff --git a/ControllerUSB/include/ControllerTypes.h b/ControllerUSB/include/ControllerTypes.h index 212e85f..c3b4342 100644 --- a/ControllerUSB/include/ControllerTypes.h +++ b/ControllerUSB/include/ControllerTypes.h @@ -5,11 +5,14 @@ enum ControllerType CONTROLLER_UNDEFINED, CONTROLLER_XBOX360, CONTROLLER_XBOXONE, + CONTROLLER_DUALSHOCK3, + CONTROLLER_DUALSHOCK4, }; enum VendorIDs { VENDOR_MICROSOFT = 0x45e, + VENDOR_SONY = 0x54c, }; enum ProductIDs @@ -20,4 +23,7 @@ enum ProductIDs PRODUCT_XBOXONEELITE = 0x2e3, PRODUCT_XBOXONES = 0x2ea, PRODUCT_XBOXADAPTIVE = 0xb0a, + + PRODUCT_DUALSHOCK3 = 0x268, + PRODUCT_DUALSHOCK4 = 0x5c4, }; \ No newline at end of file diff --git a/ControllerUSB/include/Controllers.h b/ControllerUSB/include/Controllers.h index 46121b7..cb50e8e 100644 --- a/ControllerUSB/include/Controllers.h +++ b/ControllerUSB/include/Controllers.h @@ -3,10 +3,12 @@ //Catch-all header to include all the controllers #include "Controllers/Xbox360Controller.h" #include "Controllers/XboxOneController.h" +#include "Controllers/Dualshock3Controller.h" +#include "Controllers/Dualshock4Controller.h" std::vector GetVendors() { - return {VENDOR_MICROSOFT}; + return {VENDOR_MICROSOFT, VENDOR_SONY}; } std::vector GetVendorProducts(uint16_t vendor_id) @@ -20,6 +22,9 @@ std::vector GetVendorProducts(uint16_t vendor_id) PRODUCT_XBOXONEELITE, PRODUCT_XBOXONES, PRODUCT_XBOXADAPTIVE}; + case VENDOR_SONY: + return {PRODUCT_DUALSHOCK3, + PRODUCT_DUALSHOCK4}; } return {}; } @@ -34,6 +39,10 @@ std::unique_ptr ConstructControllerFromType(ControllerType type, st return std::make_unique(std::move(device)); case CONTROLLER_XBOXONE: return std::make_unique(std::move(device)); + case CONTROLLER_DUALSHOCK3: + return std::make_unique(std::move(device)); + case CONTROLLER_DUALSHOCK4: + return std::make_unique(std::move(device)); default: break; } @@ -57,6 +66,15 @@ ControllerType GetControllerTypeFromIds(uint16_t vendor_id, uint16_t product_id) return CONTROLLER_XBOXONE; } break; + case VENDOR_SONY: + switch (product_id) + { + case PRODUCT_DUALSHOCK3: + return CONTROLLER_DUALSHOCK3; + case PRODUCT_DUALSHOCK4: + return CONTROLLER_DUALSHOCK4; + } + break; default: break; } diff --git a/ControllerUSB/include/Controllers/Dualshock4Controller.h b/ControllerUSB/include/Controllers/Dualshock4Controller.h new file mode 100644 index 0000000..9d43b84 --- /dev/null +++ b/ControllerUSB/include/Controllers/Dualshock4Controller.h @@ -0,0 +1,82 @@ +#pragma once + +#include "IController.h" + +//References used: +//https://cs.chromium.org/chromium/src/device/gamepad/dualshock4_controller.cc + +struct Dualshock4ButtonData +{ + uint8_t type; + uint8_t length; + + bool dpad_up : 1; + bool dpad_down : 1; + bool dpad_left : 1; + bool dpad_right : 1; + + bool start : 1; + bool back : 1; + bool stick_left_click : 1; + bool stick_right_click : 1; + + bool bumper_left : 1; + bool bumper_right : 1; + bool guide : 1; + bool dummy1 : 1; // Always 0. + + bool a : 1; + bool b : 1; + bool x : 1; + bool y : 1; + + uint8_t trigger_left; + uint8_t trigger_right; + + int16_t stick_left_x; + int16_t stick_left_y; + int16_t stick_right_x; + int16_t stick_right_y; + + // Always 0. + uint32_t dummy2; + uint16_t dummy3; +}; + +class Dualshock4Controller : public IController +{ +private: + IUSBEndpoint *m_inPipe = nullptr; + IUSBEndpoint *m_outPipe = nullptr; + + Dualshock4ButtonData m_buttonData; + + int16_t kLeftThumbDeadzone = 0; //7849; + int16_t kRightThumbDeadzone = 0; //8689; + uint16_t kTriggerMax = 0; //1023; + uint16_t kTriggerDeadzone = 0; //120; + +public: + Dualshock4Controller(std::unique_ptr &&interface); + virtual ~Dualshock4Controller(); + + virtual Status Initialize(); + virtual void Exit(); + + Status OpenInterfaces(); + void CloseInterfaces(); + + virtual Status GetInput(); + + virtual NormalizedButtonData GetNormalizedButtonData(); + + virtual ControllerType GetType() { return CONTROLLER_XBOX360; } + + inline const Dualshock4ButtonData &GetButtonData() { return m_buttonData; }; + + float NormalizeTrigger(uint16_t value); + void NormalizeAxis(int16_t x, int16_t y, int16_t deadzone, float *x_out, float *y_out); + + Status SendInitBytes(); + Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude); +}; \ No newline at end of file diff --git a/ControllerUSB/source/Controllers/Dualshock4Controller.cpp b/ControllerUSB/source/Controllers/Dualshock4Controller.cpp new file mode 100644 index 0000000..ffde658 --- /dev/null +++ b/ControllerUSB/source/Controllers/Dualshock4Controller.cpp @@ -0,0 +1,240 @@ +#include "Controllers/Dualshock4Controller.h" +#include + +Dualshock4Controller::Dualshock4Controller(std::unique_ptr &&interface) + : IController(std::move(interface)) +{ +} + +Dualshock4Controller::~Dualshock4Controller() +{ + Exit(); +} + +Status Dualshock4Controller::Initialize() +{ + Status rc; + + rc = OpenInterfaces(); + if (S_FAILED(rc)) + return rc; + + rc = SendInitBytes(); + if (S_FAILED(rc)) + return rc; + return rc; +} +void Dualshock4Controller::Exit() +{ + CloseInterfaces(); +} + +Status Dualshock4Controller::OpenInterfaces() +{ + Status rc; + rc = m_device->Open(); + if (S_FAILED(rc)) + return rc; + + //This will open each interface and try to acquire Xbox One controller's in and out endpoints, if it hasn't already + std::vector> &interfaces = m_device->GetInterfaces(); + for (auto &&interface : interfaces) + { + rc = interface->Open(); + if (S_FAILED(rc)) + return rc; + //TODO: check for numEndpoints before trying to open them! + if (interface->GetDescriptor()->bNumEndpoints >= 2) + { + IUSBEndpoint *inEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_IN, 1); + if (inEndpoint->GetDescriptor()->bLength != 0) + { + rc = inEndpoint->Open(); + if (S_FAILED(rc)) + return 5555; + + m_inPipe = inEndpoint; + } + + IUSBEndpoint *outEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_OUT, 1); + if (outEndpoint->GetDescriptor()->bLength != 0) + { + rc = outEndpoint->Open(); + if (S_FAILED(rc)) + return 6666; + + m_outPipe = outEndpoint; + } + } + } + + if (!m_inPipe || !m_outPipe) + return 69; + + return rc; +} +void Dualshock4Controller::CloseInterfaces() +{ + m_device->Reset(); + m_device->Close(); +} + +Status Dualshock4Controller::GetInput() +{ + return 9; + /* + uint8_t input_bytes[64]; + + Status rc = m_inPipe->Read(input_bytes, sizeof(input_bytes)); + if (S_FAILED(rc)) + return rc; + + uint8_t type = input_bytes[0]; + + if (type == XBONEINPUT_BUTTON) //Button data + { + m_buttonData = *reinterpret_cast(input_bytes); + } + else if (type == XBONEINPUT_GUIDEBUTTON) //Guide button status + { + m_buttonData.sync = input_bytes[4]; + + //Xbox one S needs to be sent an ack report for guide buttons + //TODO: needs testing + if (input_bytes[1] == 0x30) + { + rc = WriteAckGuideReport(input_bytes[2]); + if (S_FAILED(rc)) + return rc; + } + //TODO: add ack check and send ack report! + } + + return rc; + */ +} + +Status Dualshock4Controller::SendInitBytes() +{ + /* + UCHAR hidCommandEnable[DS4_HID_COMMAND_ENABLE_SIZE] = + { + 0x42, 0x0C, 0x00, 0x00 + }; + + Context, + BmRequestHostToDevice, + BmRequestClass, + SetReport, + DS4FeatureStartDevice, + 0, + hidCommandEnable, + DS4_HID_COMMAND_ENABLE_SIZE + + */ + uint8_t init_bytes[]{ + 0x05, + 0x20, 0x00, 0x01, 0x00}; + + Status rc = m_outPipe->Write(init_bytes, sizeof(init_bytes)); + return rc; +} + +float Dualshock4Controller::NormalizeTrigger(uint16_t value) +{ + //If the given value is below the trigger zone, save the calc and return 0, otherwise adjust the value to the deadzone + return value < kTriggerDeadzone + ? 0 + : static_cast(value - kTriggerDeadzone) / + (kTriggerMax - kTriggerDeadzone); +} + +void Dualshock4Controller::NormalizeAxis(int16_t x, + int16_t y, + int16_t deadzone, + float *x_out, + float *y_out) +{ + float x_val = x; + float y_val = y; + // Determine how far the stick is pushed. + //This will never exceed 32767 because if the stick is + //horizontally maxed in one direction, vertically it must be neutral(0) and vice versa + float real_magnitude = std::sqrt(x_val * x_val + y_val * y_val); + // Check if the controller is outside a circular dead zone. + if (real_magnitude > deadzone) + { + // Clip the magnitude at its expected maximum value. + float magnitude = std::min(32767.0f, real_magnitude); + // Adjust magnitude relative to the end of the dead zone. + magnitude -= deadzone; + // Normalize the magnitude with respect to its expected range giving a + // magnitude value of 0.0 to 1.0 + //ratio = (currentValue / maxValue) / realValue + float ratio = (magnitude / (32767 - deadzone)) / real_magnitude; + // Y is negated because xbox controllers have an opposite sign from + // the 'standard controller' recommendations. + *x_out = x_val * ratio; + *y_out = y_val * ratio; + } + else + { + // If the controller is in the deadzone zero out the magnitude. + *x_out = *y_out = 0.0f; + } +} + +//Pass by value should hopefully be optimized away by RVO +NormalizedButtonData Dualshock4Controller::GetNormalizedButtonData() +{ + NormalizedButtonData normalData; + + normalData.bottom_action = m_buttonData.a; + normalData.right_action = m_buttonData.b; + normalData.left_action = m_buttonData.x; + normalData.top_action = m_buttonData.y; + + normalData.dpad_up = m_buttonData.dpad_up; + normalData.dpad_down = m_buttonData.dpad_down; + normalData.dpad_left = m_buttonData.dpad_left; + normalData.dpad_right = m_buttonData.dpad_right; + + normalData.back = m_buttonData.back; + normalData.start = m_buttonData.start; + + normalData.left_bumper = m_buttonData.bumper_left; + normalData.right_bumper = m_buttonData.bumper_right; + + normalData.left_stick_click = m_buttonData.stick_left_click; + normalData.right_stick_click = m_buttonData.stick_right_click; + + normalData.capture = false; + normalData.home = false; + + //normalData.guide = m_buttonData.sync; + + normalData.left_trigger = NormalizeTrigger(m_buttonData.trigger_left); + normalData.right_trigger = NormalizeTrigger(m_buttonData.trigger_right); + + NormalizeAxis(m_buttonData.stick_left_x, m_buttonData.stick_left_y, kLeftThumbDeadzone, + &normalData.left_stick_x, &normalData.left_stick_y); + NormalizeAxis(m_buttonData.stick_right_x, m_buttonData.stick_right_y, kRightThumbDeadzone, + &normalData.right_stick_x, &normalData.right_stick_y); + + return normalData; +} + +Status Dualshock4Controller::SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude) +{ + return 9; + /* + uint8_t rumble_data[]{ + 0x09, 0x00, + m_rumbleDataCounter++, + 0x09, 0x00, 0x0f, 0x00, 0x00, + strong_magnitude, + weak_magnitude, + 0xff, 0x00, 0x00}; + return m_outPipe->Write(rumble_data, sizeof(rumble_data)); + */ +} \ No newline at end of file diff --git a/SwitchUSB/source/SwitchAbstractedPadHandler.cpp b/SwitchUSB/source/SwitchAbstractedPadHandler.cpp index 385e6c0..e31e997 100644 --- a/SwitchUSB/source/SwitchAbstractedPadHandler.cpp +++ b/SwitchUSB/source/SwitchAbstractedPadHandler.cpp @@ -20,7 +20,7 @@ Result SwitchAbstractedPadHandler::Initialize() return rc; hidScanInput(); - HidControllerID lastOfflineID; + HidControllerID lastOfflineID = CONTROLLER_PLAYER_1; for (int i = 0; i != 8; ++i) { if (!hidIsControllerConnected(static_cast(i))) @@ -29,7 +29,7 @@ Result SwitchAbstractedPadHandler::Initialize() break; } } - WriteToLog("Found last offline ID: ", lastOfflineID); + //WriteToLog("Found last offline ID: ", lastOfflineID); rc = InitAbstractedPadState(); if (R_FAILED(rc)) @@ -38,17 +38,38 @@ Result SwitchAbstractedPadHandler::Initialize() svcSleepThread(1e+7L); hidScanInput(); - WriteToLog("Is last offline id connected? ", hidIsControllerConnected(lastOfflineID)); - WriteToLog("Last offline id type: ", hidGetControllerType(lastOfflineID)); + //WriteToLog("Is last offline id connected? ", hidIsControllerConnected(lastOfflineID)); + //WriteToLog("Last offline id type: ", hidGetControllerType(lastOfflineID)); Result rc2 = hidInitializeVibrationDevices(&m_vibrationDeviceHandle, 1, lastOfflineID, hidGetControllerType(lastOfflineID)); if (R_SUCCEEDED(rc2)) { + /* + u32 tmp_type = 0x20; + m_vibrationDeviceHandle = tmp_type | (lastOfflineID & 0xff) << 8; + WriteToLog("Initializing vibration device with handle ", m_vibrationDeviceHandle); + Service IActiveVibrationDeviceList; + + if (R_SUCCEEDED(serviceDispatch(hidGetServiceSession(), 203, .out_num_objects = 1, .out_objects = &IActiveVibrationDeviceList))) + { + WriteToLog("Got vibration device list object_id ", IActiveVibrationDeviceList.object_id); + + Result rc69 = serviceDispatchIn(&IActiveVibrationDeviceList, 0, m_vibrationDeviceHandle); + serviceClose(&IActiveVibrationDeviceList); + if (R_SUCCEEDED(rc69)) + { + WriteToLog("Activated vibration handle"); + InitOutputThread(); + } + else + WriteToLog("Failed to activate handle, result: ", rc69); + } + */ InitOutputThread(); } else - WriteToLog("Failed to iniitalize vibration with error ", rc2); + WriteToLog("Failed to iniitalize vibration device with error ", rc2); InitInputThread(); return rc; diff --git a/SwitchUSB/source/SwitchHDLHandler.cpp b/SwitchUSB/source/SwitchHDLHandler.cpp index 9d8bd62..a78bc56 100644 --- a/SwitchUSB/source/SwitchHDLHandler.cpp +++ b/SwitchUSB/source/SwitchHDLHandler.cpp @@ -19,7 +19,7 @@ Result SwitchHDLHandler::Initialize() return rc; hidScanInput(); - HidControllerID lastOfflineID; + HidControllerID lastOfflineID = CONTROLLER_PLAYER_1; for (int i = 0; i != 8; ++i) { if (!hidIsControllerConnected(static_cast(i))) @@ -28,7 +28,7 @@ Result SwitchHDLHandler::Initialize() break; } } - WriteToLog("Found last offline ID: ", lastOfflineID); + //WriteToLog("Found last offline ID: ", lastOfflineID); rc = InitHdlState(); if (R_FAILED(rc)) @@ -37,13 +37,33 @@ Result SwitchHDLHandler::Initialize() svcSleepThread(1e+7L); hidScanInput(); - WriteToLog("Is last offline id connected? ", hidIsControllerConnected(lastOfflineID)); - WriteToLog("Last offline id type: ", hidGetControllerType(lastOfflineID)); + //WriteToLog("Is last offline id connected? ", hidIsControllerConnected(lastOfflineID)); + //WriteToLog("Last offline id type: ", hidGetControllerType(lastOfflineID)); Result rc2 = hidInitializeVibrationDevices(&m_vibrationDeviceHandle, 1, lastOfflineID, hidGetControllerType(lastOfflineID)); if (R_SUCCEEDED(rc2)) { + /* + m_vibrationDeviceHandle = 3 | (lastOfflineID & 0xff) << 8; + WriteToLog("Initializing vibration device with handle ", m_vibrationDeviceHandle); + Service IActiveVibrationDeviceList; + WriteToLog("Got vibration device list object_id ", IActiveVibrationDeviceList.object_id); + if (R_SUCCEEDED(serviceDispatch(hidGetServiceSession(), 203, .out_num_objects = 1, .out_objects = &IActiveVibrationDeviceList))) + { + WriteToLog("Got vibration device list object_id ", IActiveVibrationDeviceList.object_id); + + Result rc69 = serviceDispatchIn(&IActiveVibrationDeviceList, 0, m_vibrationDeviceHandle); + serviceClose(&IActiveVibrationDeviceList); + if (R_SUCCEEDED(rc69)) + { + WriteToLog("Activated vibration handle"); + InitOutputThread(); + } + else + WriteToLog("Failed to activate handle, result: ", rc69); + } + */ InitOutputThread(); } else diff --git a/source/mainLoop.cpp b/source/mainLoop.cpp index 49b92f0..fd3115f 100644 --- a/source/mainLoop.cpp +++ b/source/mainLoop.cpp @@ -20,27 +20,28 @@ Result mainLoop() s32 total_entries; std::vector vendors = GetVendors(); bool useAbstractedPad = hosversionBetween(5, 7); - hidPermitVibration(false); - hidPermitVibration(true); + //hidPermitVibration(false); + //hidPermitVibration(true); VendorEvent events[vendors.size()]; std::vector> controllerInterfaces; WriteToLog("\n\nNew sysmodule session started"); - UsbHsInterfaceFilter filter; - filter.Flags = UsbHsInterfaceFilterFlags_idVendor; { int i = 0; for (auto &&vendor : vendors) { + UsbHsInterfaceFilter filter; + filter.Flags = UsbHsInterfaceFilterFlags_idVendor; filter.idVendor = vendor; - auto &&event = events[i++] = {vendor, Event()}; + auto &&event = events[i] = {vendor, Event()}; - rc = usbHsCreateInterfaceAvailableEvent(&event.event, true, 0, &filter); + rc = usbHsCreateInterfaceAvailableEvent(&event.event, true, i, &filter); if (R_FAILED(rc)) WriteToLog("Failed to open event ", event.vendor); else WriteToLog("Successfully created event ", event.vendor); + ++i; } } @@ -81,10 +82,16 @@ Result mainLoop() HidVibrationValue value; value.amp_high = 0.5f; value.amp_low = 0.5f; - value.freq_high = 320.0f; - value.freq_low = 160.0f; + value.freq_high = 0.0f; + value.freq_low = 0.0f; rc = hidSendVibrationValue(vibrationHandle, &value); WriteToLog("SendVirationValue result: ", rc); + rc = hidGetActualVibrationValue(vibrationHandle, &value); + WriteToLog("hidGetActualVibrationValue result: ", rc); + if (R_SUCCEEDED(rc)) + { + WriteToLog("Amp high: ", value.amp_high, " Amp low: ", value.amp_low, " Freq high: ", value.freq_high, " Freq low: ", value.freq_low); + } } else WriteToLog("failed to check for vibration device");