1
0
mirror of https://github.com/cathery/sys-con.git synced 2024-09-14 18:45:32 +00:00
sys-con/source/ControllerLib/Controllers/Dualshock3Controller.cpp

243 lines
7.2 KiB
C++
Raw Normal View History

2019-10-31 18:00:42 +00:00
#include "Controllers/Dualshock3Controller.h"
#include <cmath>
2019-11-06 22:20:58 +00:00
static ControllerConfig _dualshock3ControllerConfig{};
2019-10-31 18:00:42 +00:00
Dualshock3Controller::Dualshock3Controller(std::unique_ptr<IUSBDevice> &&interface)
: IController(std::move(interface))
{
}
Dualshock3Controller::~Dualshock3Controller()
{
Exit();
}
2019-11-13 11:16:13 +00:00
Result Dualshock3Controller::Initialize()
2019-10-31 18:00:42 +00:00
{
2019-11-13 11:16:13 +00:00
Result rc;
2019-10-31 18:00:42 +00:00
rc = OpenInterfaces();
2019-11-13 11:16:13 +00:00
if (R_FAILED(rc))
2019-10-31 18:00:42 +00:00
return rc;
SetLED(DS3LED_1);
2019-10-31 18:00:42 +00:00
return rc;
}
void Dualshock3Controller::Exit()
{
CloseInterfaces();
}
2019-11-13 11:16:13 +00:00
Result Dualshock3Controller::OpenInterfaces()
2019-10-31 18:00:42 +00:00
{
2019-11-13 11:16:13 +00:00
Result rc;
2019-10-31 18:00:42 +00:00
rc = m_device->Open();
2019-11-13 11:16:13 +00:00
if (R_FAILED(rc))
2019-10-31 18:00:42 +00:00
return rc;
//Open each interface, send it a setup packet and get the endpoints if it succeeds
2019-10-31 18:00:42 +00:00
std::vector<std::unique_ptr<IUSBInterface>> &interfaces = m_device->GetInterfaces();
for (auto &&interface : interfaces)
{
rc = interface->Open();
2019-11-13 11:16:13 +00:00
if (R_FAILED(rc))
2019-10-31 18:00:42 +00:00
return rc;
2019-11-25 12:58:23 +00:00
if (interface->GetDescriptor()->bInterfaceClass != 3)
continue;
if (interface->GetDescriptor()->bInterfaceProtocol != 0)
continue;
if (interface->GetDescriptor()->bNumEndpoints < 2)
continue;
//Send an initial control packet
constexpr uint8_t initBytes[] = {0x42, 0x0C, 0x00, 0x00};
rc = SendCommand(interface.get(), Ds3FeatureStartDevice, initBytes, sizeof(initBytes));
2019-11-13 11:16:13 +00:00
if (R_FAILED(rc))
return 60;
m_interface = interface.get();
2019-10-31 18:00:42 +00:00
if (!m_inPipe)
{
for (int i = 0; i != 15; ++i)
{
IUSBEndpoint *inEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_IN, i);
if (inEndpoint)
{
rc = inEndpoint->Open();
2019-11-13 11:16:13 +00:00
if (R_FAILED(rc))
return 61;
m_inPipe = inEndpoint;
break;
}
2019-10-31 18:00:42 +00:00
}
}
2019-10-31 18:00:42 +00:00
if (!m_outPipe)
{
for (int i = 0; i != 15; ++i)
2019-10-31 18:00:42 +00:00
{
IUSBEndpoint *outEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_OUT, i);
if (outEndpoint)
{
rc = outEndpoint->Open();
2019-11-13 11:16:13 +00:00
if (R_FAILED(rc))
return 62;
m_outPipe = outEndpoint;
break;
}
2019-10-31 18:00:42 +00:00
}
}
}
if (!m_inPipe || !m_outPipe)
return 69;
2019-10-31 18:00:42 +00:00
return rc;
}
void Dualshock3Controller::CloseInterfaces()
{
2019-11-07 17:46:47 +00:00
//m_device->Reset();
2019-10-31 18:00:42 +00:00
m_device->Close();
}
2019-11-13 11:16:13 +00:00
Result Dualshock3Controller::GetInput()
2019-10-31 18:00:42 +00:00
{
2019-11-04 19:11:55 +00:00
uint8_t input_bytes[49];
2019-10-31 18:00:42 +00:00
2019-11-13 11:16:13 +00:00
Result rc = m_inPipe->Read(input_bytes, sizeof(input_bytes));
if (R_FAILED(rc))
2019-10-31 18:00:42 +00:00
return rc;
2019-11-04 19:11:55 +00:00
if (input_bytes[0] == Ds3InputPacket_Button)
{
m_buttonData = *reinterpret_cast<Dualshock3ButtonData *>(input_bytes);
}
2019-10-31 18:00:42 +00:00
return rc;
}
2019-11-04 19:11:55 +00:00
float Dualshock3Controller::NormalizeTrigger(uint8_t value)
2019-10-31 18:00:42 +00:00
{
2019-11-07 17:46:47 +00:00
uint8_t deadzone = (UINT8_MAX * _dualshock3ControllerConfig.triggerDeadzonePercent) / 100;
2019-10-31 18:00:42 +00:00
//If the given value is below the trigger zone, save the calc and return 0, otherwise adjust the value to the deadzone
2019-11-07 17:46:47 +00:00
return value < deadzone
2019-10-31 18:00:42 +00:00
? 0
2019-11-07 17:46:47 +00:00
: static_cast<float>(value - deadzone) / (UINT8_MAX - deadzone);
2019-10-31 18:00:42 +00:00
}
2019-11-04 19:11:55 +00:00
void Dualshock3Controller::NormalizeAxis(uint8_t x,
uint8_t y,
2019-11-07 17:46:47 +00:00
uint8_t deadzonePercent,
2019-10-31 18:00:42 +00:00
float *x_out,
float *y_out)
{
2019-11-04 19:11:55 +00:00
float x_val = x - 127.0f;
float y_val = 127.0f - y;
2019-10-31 18:00:42 +00:00
// 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);
2019-11-07 17:46:47 +00:00
float real_deadzone = (127 * deadzonePercent) / 100;
2019-10-31 18:00:42 +00:00
// Check if the controller is outside a circular dead zone.
2019-11-07 17:46:47 +00:00
if (real_magnitude > real_deadzone)
2019-10-31 18:00:42 +00:00
{
// Clip the magnitude at its expected maximum value.
2019-11-04 19:11:55 +00:00
float magnitude = std::min(127.0f, real_magnitude);
2019-10-31 18:00:42 +00:00
// Adjust magnitude relative to the end of the dead zone.
2019-11-07 17:46:47 +00:00
magnitude -= real_deadzone;
2019-10-31 18:00:42 +00:00
// Normalize the magnitude with respect to its expected range giving a
// magnitude value of 0.0 to 1.0
//ratio = (currentValue / maxValue) / realValue
2019-11-07 17:46:47 +00:00
float ratio = (magnitude / (127 - real_deadzone)) / real_magnitude;
2019-10-31 18:00:42 +00:00
*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 Dualshock3Controller::GetNormalizedButtonData()
{
NormalizedButtonData normalData;
2019-11-07 17:46:47 +00:00
normalData.triggers[0] = NormalizeTrigger(m_buttonData.trigger_left_pressure);
normalData.triggers[1] = NormalizeTrigger(m_buttonData.trigger_right_pressure);
NormalizeAxis(m_buttonData.stick_left_x, m_buttonData.stick_left_y, _dualshock3ControllerConfig.leftStickDeadzonePercent,
&normalData.sticks[0].axis_x, &normalData.sticks[0].axis_y);
NormalizeAxis(m_buttonData.stick_right_x, m_buttonData.stick_right_y, _dualshock3ControllerConfig.rightStickDeadzonePercent,
&normalData.sticks[1].axis_x, &normalData.sticks[1].axis_y);
bool buttons[NUM_CONTROLLERBUTTONS] = {
m_buttonData.triangle,
m_buttonData.circle,
m_buttonData.cross,
m_buttonData.square,
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 = _dualshock3ControllerConfig.buttons[i];
normalData.buttons[(button != NOT_SET ? button : i)] = buttons[i];
}
2019-10-31 18:00:42 +00:00
return normalData;
}
2019-11-13 11:16:13 +00:00
Result Dualshock3Controller::SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude)
2019-10-31 18:00:42 +00:00
{
2019-11-04 19:11:55 +00:00
//Not implemented yet
2019-10-31 18:00:42 +00:00
return 9;
2019-11-06 22:20:58 +00:00
}
Result Dualshock3Controller::SendCommand(IUSBInterface *interface, Dualshock3FeatureValue feature, const void *buffer, uint16_t size)
{
return interface->ControlTransfer(0x21, 0x09, static_cast<uint16_t>(feature), 0, size, buffer);
}
2019-11-13 11:16:13 +00:00
Result Dualshock3Controller::SetLED(Dualshock3LEDValue value)
{
const uint8_t ledPacket[]{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
static_cast<uint8_t>(value << 1),
LED_PERMANENT,
LED_PERMANENT,
LED_PERMANENT,
LED_PERMANENT};
return SendCommand(m_interface, Ds3FeatureUnknown1, ledPacket, sizeof(ledPacket));
}
2019-11-06 22:20:58 +00:00
void Dualshock3Controller::LoadConfig(const ControllerConfig *config)
{
_dualshock3ControllerConfig = *config;
2019-11-09 20:26:47 +00:00
}
ControllerConfig *Dualshock3Controller::GetConfig()
{
return &_dualshock3ControllerConfig;
2019-10-31 18:00:42 +00:00
}