mirror of
https://github.com/cathery/sys-con.git
synced 2024-11-05 08:26:32 +00:00
Begin Xbox 360 Wireless implementation
This commit is contained in:
parent
d9d4ccf1d4
commit
7ae2204070
@ -1,17 +1,5 @@
|
||||
#pragma once
|
||||
#include "Controllers.h"
|
||||
|
||||
//Returns a vector with all vendor IDs
|
||||
std::vector<uint16_t> GetVendors();
|
||||
|
||||
//Returns all product IDs for specified vendor
|
||||
std::vector<uint16_t> GetVendorProducts(uint16_t vendor_id);
|
||||
|
||||
//Returns a constructed controller derived from IController based on the type
|
||||
std::unique_ptr<IController> ConstructControllerFromType(ControllerType type, std::unique_ptr<IUSBDevice> &&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);
|
@ -4,6 +4,7 @@ enum ControllerType
|
||||
{
|
||||
CONTROLLER_UNDEFINED,
|
||||
CONTROLLER_XBOX360,
|
||||
CONTROLLER_XBOX360W,
|
||||
CONTROLLER_XBOXONE,
|
||||
CONTROLLER_DUALSHOCK3,
|
||||
CONTROLLER_DUALSHOCK4,
|
||||
|
@ -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"
|
||||
|
@ -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<IUSBDevice> &&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);
|
||||
};
|
@ -1,100 +1,5 @@
|
||||
#include "ControllerHelpers.h"
|
||||
|
||||
std::vector<uint16_t> GetVendors()
|
||||
{
|
||||
return {VENDOR_MICROSOFT, VENDOR_SONY};
|
||||
}
|
||||
|
||||
std::vector<uint16_t> 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<IController> ConstructControllerFromType(ControllerType type, std::unique_ptr<IUSBDevice> &&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<Xbox360Controller>(std::move(device));
|
||||
case CONTROLLER_XBOXONE:
|
||||
return std::make_unique<XboxOneController>(std::move(device));
|
||||
case CONTROLLER_DUALSHOCK3:
|
||||
return std::make_unique<Dualshock3Controller>(std::move(device));
|
||||
case CONTROLLER_DUALSHOCK4:
|
||||
return std::make_unique<Dualshock4Controller>(std::move(device));
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return std::unique_ptr<IController>{};
|
||||
}
|
||||
|
||||
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)
|
||||
|
255
ControllerUSB/source/Controllers/Xbox360WirelessController.cpp
Normal file
255
ControllerUSB/source/Controllers/Xbox360WirelessController.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
#include "Controllers/Xbox360WirelessController.h"
|
||||
#include <cmath>
|
||||
|
||||
static ControllerConfig _xbox360WControllerConfig{};
|
||||
|
||||
Xbox360WirelessController::Xbox360WirelessController(std::unique_ptr<IUSBDevice> &&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<std::unique_ptr<IUSBInterface>> &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<Xbox360ButtonData *>(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<float>(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<uint8_t>(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;
|
||||
}
|
@ -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!");
|
||||
|
||||
|
@ -95,6 +95,12 @@ Result mainLoop()
|
||||
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces, total_entries);
|
||||
controllerPtr = std::make_unique<Xbox360Controller>(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<SwitchUSBDevice>(interfaces, total_entries);
|
||||
controllerPtr = std::make_unique<Xbox360WirelessController>(std::move(devicePtr));
|
||||
}
|
||||
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 71, 208)))
|
||||
{
|
||||
WriteToLog("Registering Xbox One controller");
|
||||
|
Loading…
Reference in New Issue
Block a user