From 7ae2204070797ab3bcfcf6b8b0723937d5afb4e0 Mon Sep 17 00:00:00 2001 From: cathery Date: Fri, 8 Nov 2019 15:56:20 +0300 Subject: [PATCH] Begin Xbox 360 Wireless implementation --- ControllerUSB/include/ControllerHelpers.h | 12 - ControllerUSB/include/ControllerTypes.h | 1 + ControllerUSB/include/Controllers.h | 1 + .../Controllers/Xbox360WirelessController.h | 46 ++++ ControllerUSB/source/ControllerHelpers.cpp | 95 ------- .../Controllers/Xbox360WirelessController.cpp | 255 ++++++++++++++++++ source/configFile.cpp | 3 + source/mainLoop.cpp | 6 + 8 files changed, 312 insertions(+), 107 deletions(-) create mode 100644 ControllerUSB/include/Controllers/Xbox360WirelessController.h create mode 100644 ControllerUSB/source/Controllers/Xbox360WirelessController.cpp diff --git a/ControllerUSB/include/ControllerHelpers.h b/ControllerUSB/include/ControllerHelpers.h index 510adb9..855433c 100644 --- a/ControllerUSB/include/ControllerHelpers.h +++ b/ControllerUSB/include/ControllerHelpers.h @@ -1,17 +1,5 @@ #pragma once #include "Controllers.h" -//Returns a vector with all vendor IDs -std::vector GetVendors(); - -//Returns all product IDs for specified vendor -std::vector GetVendorProducts(uint16_t vendor_id); - -//Returns a constructed controller derived from IController based on the type -std::unique_ptr ConstructControllerFromType(ControllerType type, std::unique_ptr &&device); - -//Gets the controller type based on vendor + product combo -ControllerType GetControllerTypeFromIds(uint16_t vendor_id, uint16_t product_id); - //Returns true if said controller supports said feature bool DoesControllerSupport(ControllerType type, ControllerSupport supportType); \ No newline at end of file diff --git a/ControllerUSB/include/ControllerTypes.h b/ControllerUSB/include/ControllerTypes.h index a0f9d4f..da3bc54 100644 --- a/ControllerUSB/include/ControllerTypes.h +++ b/ControllerUSB/include/ControllerTypes.h @@ -4,6 +4,7 @@ enum ControllerType { CONTROLLER_UNDEFINED, CONTROLLER_XBOX360, + CONTROLLER_XBOX360W, CONTROLLER_XBOXONE, CONTROLLER_DUALSHOCK3, CONTROLLER_DUALSHOCK4, diff --git a/ControllerUSB/include/Controllers.h b/ControllerUSB/include/Controllers.h index 3e02438..1f39a94 100644 --- a/ControllerUSB/include/Controllers.h +++ b/ControllerUSB/include/Controllers.h @@ -1,6 +1,7 @@ #pragma once #include "Controllers/Xbox360Controller.h" +#include "Controllers/Xbox360WirelessController.h" #include "Controllers/XboxOneController.h" #include "Controllers/Dualshock3Controller.h" #include "Controllers/Dualshock4Controller.h" diff --git a/ControllerUSB/include/Controllers/Xbox360WirelessController.h b/ControllerUSB/include/Controllers/Xbox360WirelessController.h new file mode 100644 index 0000000..d6494c0 --- /dev/null +++ b/ControllerUSB/include/Controllers/Xbox360WirelessController.h @@ -0,0 +1,46 @@ +#pragma once + +#include "IController.h" +#include "Xbox360Controller.h" + +//References used: +//https://cs.chromium.org/chromium/src/device/gamepad/xbox_controller_mac.mm + +class Xbox360WirelessController : public IController +{ +private: + IUSBEndpoint *m_inPipe = nullptr; + IUSBEndpoint *m_outPipe = nullptr; + + Xbox360ButtonData m_buttonData; + + bool m_presence; + +public: + Xbox360WirelessController(std::unique_ptr &&interface); + virtual ~Xbox360WirelessController(); + + virtual Status Initialize(); + virtual void Exit(); + + Status OpenInterfaces(); + void CloseInterfaces(); + + virtual Status GetInput(); + + virtual NormalizedButtonData GetNormalizedButtonData(); + + virtual ControllerType GetType() { return CONTROLLER_XBOX360W; } + + inline const Xbox360ButtonData &GetButtonData() { return m_buttonData; }; + + float NormalizeTrigger(uint8_t value); + void NormalizeAxis(int16_t x, int16_t y, uint8_t deadzonePercent, float *x_out, float *y_out); + + Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude); + Status SetLED(Xbox360LEDValue value); + Status PowerOffController(); + Status ReconnectController(); + + static void LoadConfig(const ControllerConfig *config); +}; \ No newline at end of file diff --git a/ControllerUSB/source/ControllerHelpers.cpp b/ControllerUSB/source/ControllerHelpers.cpp index b833626..220e225 100644 --- a/ControllerUSB/source/ControllerHelpers.cpp +++ b/ControllerUSB/source/ControllerHelpers.cpp @@ -1,100 +1,5 @@ #include "ControllerHelpers.h" -std::vector GetVendors() -{ - return {VENDOR_MICROSOFT, VENDOR_SONY}; -} - -std::vector GetVendorProducts(uint16_t vendor_id) -{ - switch (vendor_id) - { - case VENDOR_MICROSOFT: - return { - PRODUCT_XBOX360, - PRODUCT_XBOXONE2013, - PRODUCT_XBOXONE2015, - PRODUCT_XBOXONEELITE, - PRODUCT_XBOXONES, - PRODUCT_XBOXADAPTIVE, - /* - PRODUCT_XBOX360_WIRELESS, - PRODUCT_XBOX360_WIRELESS_MODULE, - PRODUCT_XBOX360_WIRELESS_ADAPTER, - PRODUCT_XBOX360_WIRELESS_N_ADAPTER, - PRODUCT_XBOX360_WIRELESS_NETWORK_ADAPTER, - PRODUCT_XBOX360_WIRELESS_RECEIVER, - PRODUCT_XBOX360_WIRELESS_RECEIVER_2 - */ - }; - case VENDOR_SONY: - return {PRODUCT_DUALSHOCK3, - PRODUCT_DUALSHOCK4}; - } - return {}; -} - -std::unique_ptr ConstructControllerFromType(ControllerType type, std::unique_ptr &&device) -{ - - //surely there must be a better way to pass a class type from a function - switch (type) - { - case CONTROLLER_XBOX360: - 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; - } - return std::unique_ptr{}; -} - -ControllerType GetControllerTypeFromIds(uint16_t vendor_id, uint16_t product_id) -{ - switch (vendor_id) - { - case VENDOR_MICROSOFT: - switch (product_id) - { - case PRODUCT_XBOX360: - /* - case PRODUCT_XBOX360_WIRELESS: - case PRODUCT_XBOX360_WIRELESS_MODULE: - case PRODUCT_XBOX360_WIRELESS_ADAPTER: - case PRODUCT_XBOX360_WIRELESS_N_ADAPTER: - case PRODUCT_XBOX360_WIRELESS_NETWORK_ADAPTER: - case PRODUCT_XBOX360_WIRELESS_RECEIVER: - case PRODUCT_XBOX360_WIRELESS_RECEIVER_2: - */ - return CONTROLLER_XBOX360; - case PRODUCT_XBOXONE2013: - case PRODUCT_XBOXONE2015: - case PRODUCT_XBOXONEELITE: - case PRODUCT_XBOXONES: - case PRODUCT_XBOXADAPTIVE: - 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; - } - return CONTROLLER_UNDEFINED; -} - bool DoesControllerSupport(ControllerType type, ControllerSupport supportType) { switch (type) diff --git a/ControllerUSB/source/Controllers/Xbox360WirelessController.cpp b/ControllerUSB/source/Controllers/Xbox360WirelessController.cpp new file mode 100644 index 0000000..275d545 --- /dev/null +++ b/ControllerUSB/source/Controllers/Xbox360WirelessController.cpp @@ -0,0 +1,255 @@ +#include "Controllers/Xbox360WirelessController.h" +#include + +static ControllerConfig _xbox360WControllerConfig{}; + +Xbox360WirelessController::Xbox360WirelessController(std::unique_ptr &&interface) + : IController(std::move(interface)) +{ +} + +Xbox360WirelessController::~Xbox360WirelessController() +{ + Exit(); +} + +Status Xbox360WirelessController::Initialize() +{ + Status rc; + + rc = OpenInterfaces(); + if (S_FAILED(rc)) + return rc; + + rc = ReconnectController(); + if (S_FAILED(rc)) + return rc; + + SetLED(XBOX360LED_TOPLEFT); + return rc; +} +void Xbox360WirelessController::Exit() +{ + CloseInterfaces(); +} + +Status Xbox360WirelessController::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; + + if (interface->GetDescriptor()->bInterfaceProtocol != 129) + continue; + + if (interface->GetDescriptor()->bNumEndpoints < 2) + continue; + + if (!m_inPipe) + { + for (int i = 0; i != 15; ++i) + { + IUSBEndpoint *inEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_IN, i); + if (inEndpoint) + { + rc = inEndpoint->Open(); + if (S_FAILED(rc)) + return 55555; + + m_inPipe = inEndpoint; + break; + } + } + } + + if (!m_outPipe) + { + for (int i = 0; i != 15; ++i) + { + IUSBEndpoint *outEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_OUT, i); + if (outEndpoint) + { + rc = outEndpoint->Open(); + if (S_FAILED(rc)) + return 66666; + + m_outPipe = outEndpoint; + break; + } + } + } + } + + if (!m_inPipe || !m_outPipe) + return 3469; + + return rc; +} +void Xbox360WirelessController::CloseInterfaces() +{ + if (m_presence) + PowerOffController(); + + //m_device->Reset(); + m_device->Close(); +} + +Status Xbox360WirelessController::GetInput() +{ + uint8_t input_bytes[64]; + + Status rc = m_inPipe->Read(input_bytes, sizeof(input_bytes)); + + uint8_t type = input_bytes[0]; + + if (input_bytes[0] & 0x08) + { + bool newPresence = (input_bytes[1] & 0x80) != 0; + + if (m_presence != newPresence) + { + m_presence = newPresence; + + if (m_presence) + ReconnectController(); + else + PowerOffController(); + } + } + + if (input_bytes[1] != 0x1) + return 1; + + if (type == XBOX360INPUT_BUTTON) + { + m_buttonData = *reinterpret_cast(input_bytes); + } + + return rc; +} + +float Xbox360WirelessController::NormalizeTrigger(uint8_t value) +{ + uint16_t deadzone = (UINT8_MAX * _xbox360WControllerConfig.triggerDeadzonePercent) / 100; + //If the given value is below the trigger zone, save the calc and return 0, otherwise adjust the value to the deadzone + return value < deadzone + ? 0 + : static_cast(value - deadzone) / (UINT8_MAX - deadzone); +} + +void Xbox360WirelessController::NormalizeAxis(int16_t x, + int16_t y, + uint8_t deadzonePercent, + 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); + float real_deadzone = (32767 * deadzonePercent) / 100; + // Check if the controller is outside a circular dead zone. + if (real_magnitude > real_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 -= real_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 - real_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 Xbox360WirelessController::GetNormalizedButtonData() +{ + NormalizedButtonData normalData; + + normalData.triggers[0] = NormalizeTrigger(m_buttonData.trigger_left); + normalData.triggers[1] = NormalizeTrigger(m_buttonData.trigger_right); + + NormalizeAxis(m_buttonData.stick_left_x, m_buttonData.stick_left_y, _xbox360WControllerConfig.leftStickDeadzonePercent, + &normalData.sticks[0].axis_x, &normalData.sticks[0].axis_y); + NormalizeAxis(m_buttonData.stick_right_x, m_buttonData.stick_right_y, _xbox360WControllerConfig.rightStickDeadzonePercent, + &normalData.sticks[1].axis_x, &normalData.sticks[1].axis_y); + + bool buttons[NUM_CONTROLLERBUTTONS]{ + m_buttonData.y, + m_buttonData.b, + m_buttonData.a, + m_buttonData.x, + m_buttonData.stick_left_click, + m_buttonData.stick_right_click, + m_buttonData.bumper_left, + m_buttonData.bumper_right, + normalData.triggers[0] > 0, + normalData.triggers[1] > 0, + m_buttonData.back, + m_buttonData.start, + m_buttonData.dpad_up, + m_buttonData.dpad_right, + m_buttonData.dpad_down, + m_buttonData.dpad_left, + false, + m_buttonData.guide, + }; + + for (int i = 0; i != NUM_CONTROLLERBUTTONS; ++i) + { + ControllerButton button = _xbox360WControllerConfig.buttons[i]; + normalData.buttons[(button != NOT_SET ? button : i)] = buttons[i]; + } + + return normalData; +} + +Status Xbox360WirelessController::SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude) +{ + uint8_t rumbleData[]{0x00, 0x01, 0x0F, 0xC0, 0x00, strong_magnitude, weak_magnitude, 0x00, 0x00, 0x00, 0x00, 0x00}; + return m_outPipe->Write(rumbleData, sizeof(rumbleData)); +} + +Status Xbox360WirelessController::SetLED(Xbox360LEDValue value) +{ + uint8_t ledPacket[]{0x00, 0x00, 0x08, static_cast(value + 40), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return m_outPipe->Write(ledPacket, sizeof(ledPacket)); +} + +Status Xbox360WirelessController::PowerOffController() +{ + uint8_t poweroffPacket[]{0x00, 0x00, 0x08, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return m_outPipe->Write(poweroffPacket, sizeof(poweroffPacket)); +} + +Status Xbox360WirelessController::ReconnectController() +{ + uint8_t reconnectPacket[]{0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return m_outPipe->Write(reconnectPacket, sizeof(reconnectPacket)); +} + +void Xbox360WirelessController::LoadConfig(const ControllerConfig *config) +{ + _xbox360WControllerConfig = *config; +} \ No newline at end of file diff --git a/source/configFile.cpp b/source/configFile.cpp index 6b854a2..e3abece 100644 --- a/source/configFile.cpp +++ b/source/configFile.cpp @@ -108,7 +108,10 @@ void LoadAllConfigs() WriteToLog("Failed to read from xbox one config!"); if (R_SUCCEEDED(_ReadFromConfig(CONFIG_PATH XBOX360CONFIG))) + { Xbox360Controller::LoadConfig(&temp_config); + Xbox360WirelessController::LoadConfig(&temp_config); + } else WriteToLog("Failed to read from xbox 360 config!"); diff --git a/source/mainLoop.cpp b/source/mainLoop.cpp index 13bccdf..6cdb71c 100644 --- a/source/mainLoop.cpp +++ b/source/mainLoop.cpp @@ -95,6 +95,12 @@ Result mainLoop() devicePtr = std::make_unique(interfaces, total_entries); controllerPtr = std::make_unique(std::move(devicePtr)); } + else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 93, 129))) + { + WriteToLog("Registering Xbox 360 Wireless controller"); + devicePtr = std::make_unique(interfaces, total_entries); + controllerPtr = std::make_unique(std::move(devicePtr)); + } else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 71, 208))) { WriteToLog("Registering Xbox One controller");