mirror of
https://github.com/cathery/sys-con.git
synced 2024-10-04 13:29:43 +00:00
Begin implementing Dualshock 4 controller
This commit is contained in:
parent
45321fa29d
commit
8d61e5b10b
@ -36,7 +36,8 @@ enum ProductIDs
|
||||
PRODUCT_XBOXADAPTIVE = 0xb0a,
|
||||
|
||||
PRODUCT_DUALSHOCK3 = 0x268,
|
||||
PRODUCT_DUALSHOCK4 = 0x5c4,
|
||||
PRODUCT_DUALSHOCK4_1X = 0x5c4,
|
||||
PRODUCT_DUALSHOCK4_2X = 0x9cc,
|
||||
};
|
||||
|
||||
enum ControllerSupport
|
||||
|
@ -7,40 +7,68 @@
|
||||
|
||||
struct Dualshock4ButtonData
|
||||
{
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint8_t padding0[2];
|
||||
|
||||
bool dpad_up : 1;
|
||||
bool dpad_down : 1;
|
||||
bool dpad_left : 1;
|
||||
bool dpad_right : 1;
|
||||
uint8_t stick_left_x;
|
||||
uint8_t stick_left_y;
|
||||
uint8_t stick_right_x;
|
||||
uint8_t stick_right_y;
|
||||
uint8_t dpad : 4;
|
||||
bool square : 1;
|
||||
bool cross : 1;
|
||||
bool circle : 1;
|
||||
bool triangle : 1;
|
||||
bool l1 : 1;
|
||||
bool r1 : 1;
|
||||
bool l2 : 1;
|
||||
bool r2 : 1;
|
||||
bool share : 1;
|
||||
bool options : 1;
|
||||
bool l3 : 1;
|
||||
bool r3 : 1;
|
||||
bool psbutton : 1;
|
||||
bool touchpad_press : 1;
|
||||
uint8_t sequence_number : 6;
|
||||
uint8_t l2_pressure;
|
||||
uint8_t r2_pressure;
|
||||
uint16_t timestamp;
|
||||
uint8_t sensor_temperature;
|
||||
uint16_t gyro_pitch;
|
||||
uint16_t gyro_yaw;
|
||||
uint16_t gyro_roll;
|
||||
uint16_t accelerometer_x;
|
||||
uint16_t accelerometer_y;
|
||||
uint16_t accelerometer_z;
|
||||
uint8_t padding1[5];
|
||||
uint8_t battery_info : 5;
|
||||
uint8_t padding2 : 2;
|
||||
bool extension_detection : 1;
|
||||
|
||||
bool start : 1;
|
||||
bool back : 1;
|
||||
bool stick_left_click : 1;
|
||||
bool stick_right_click : 1;
|
||||
uint8_t padding3[2];
|
||||
|
||||
bool bumper_left : 1;
|
||||
bool bumper_right : 1;
|
||||
bool guide : 1;
|
||||
bool dummy1 : 1; // Always 0.
|
||||
uint8_t touches_count;
|
||||
uint8_t touch_data_timestamp;
|
||||
uint8_t touch0_id : 7;
|
||||
bool touch0_is_invalid : 1;
|
||||
uint8_t touch0_data[3];
|
||||
uint8_t touch1_id : 7;
|
||||
bool touch1_is_invalid : 1;
|
||||
uint8_t touch1_data[3];
|
||||
|
||||
bool a : 1;
|
||||
bool b : 1;
|
||||
bool x : 1;
|
||||
bool y : 1;
|
||||
uint8_t padding4[2];
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
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;
|
||||
enum Dualshock4Dpad
|
||||
{
|
||||
DS4_UP = 0x000,
|
||||
DS4_UPRIGHT = 0x001,
|
||||
DS4_RIGHT = 0x010,
|
||||
DS4_DOWNRIGHT = 0x011,
|
||||
DS4_DOWN = 0x100,
|
||||
DS4_DOWNLEFT = 0x101,
|
||||
DS4_LEFT = 0x110,
|
||||
DS4_UPLEFT = 0x111,
|
||||
};
|
||||
|
||||
class Dualshock4Controller : public IController
|
||||
|
@ -17,6 +17,9 @@ protected:
|
||||
std::unique_ptr<IUSBDevice> m_device;
|
||||
|
||||
public:
|
||||
uint8_t m_inputData[100];
|
||||
bool m_UpdateCalled;
|
||||
|
||||
IController(std::unique_ptr<IUSBDevice> &&interface) : m_device(std::move(interface)) {}
|
||||
virtual ~IController() = default;
|
||||
|
||||
|
@ -3,6 +3,10 @@
|
||||
|
||||
static ControllerConfig _dualshock4ControllerConfig{};
|
||||
|
||||
const uint8_t kRumbleMagnitudeMax = 0xff;
|
||||
const float kAxisMax = 255.0f;
|
||||
const float kDpadMax = 7.0f;
|
||||
|
||||
Dualshock4Controller::Dualshock4Controller(std::unique_ptr<IUSBDevice> &&interface)
|
||||
: IController(std::move(interface))
|
||||
{
|
||||
@ -12,6 +16,26 @@ Dualshock4Controller::~Dualshock4Controller()
|
||||
{
|
||||
Exit();
|
||||
}
|
||||
/*
|
||||
uint32_t ComputeDualshock4Checksum(const uint8_t *report_data, uint16_t length)
|
||||
{
|
||||
constexpr uint8_t bt_header = 0xa2;
|
||||
uint32_t crc = crc32(0xffffffff, &bt_header, 1);
|
||||
return unaligned_crc32(crc, report_data, length);
|
||||
}
|
||||
*/
|
||||
|
||||
Status Dualshock4Controller::SendInitBytes()
|
||||
{
|
||||
uint8_t init_bytes[32] = {
|
||||
//for bluetooth connection
|
||||
//0x11, 0xC4, 0x00, 0x07, 0x00, 0x00,
|
||||
0x05, 0x07, 0x00, 0x00,
|
||||
0xFF, 0xFF,
|
||||
0x00, 0x00, 0x40,
|
||||
0x00, 0x00};
|
||||
return m_outPipe->Write(init_bytes, sizeof(init_bytes));
|
||||
}
|
||||
|
||||
Status Dualshock4Controller::Initialize()
|
||||
{
|
||||
@ -45,27 +69,44 @@ Status Dualshock4Controller::OpenInterfaces()
|
||||
rc = interface->Open();
|
||||
if (S_FAILED(rc))
|
||||
return rc;
|
||||
//TODO: check for numEndpoints before trying to open them!
|
||||
if (interface->GetDescriptor()->bNumEndpoints >= 2)
|
||||
|
||||
if (interface->GetDescriptor()->bInterfaceProtocol != 0)
|
||||
continue;
|
||||
|
||||
if (interface->GetDescriptor()->bNumEndpoints < 2)
|
||||
continue;
|
||||
|
||||
if (!m_inPipe)
|
||||
{
|
||||
IUSBEndpoint *inEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_IN, 1);
|
||||
if (inEndpoint->GetDescriptor()->bLength != 0)
|
||||
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 5555;
|
||||
return 61;
|
||||
|
||||
m_inPipe = inEndpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IUSBEndpoint *outEndpoint = interface->GetEndpoint(IUSBEndpoint::USB_ENDPOINT_OUT, 1);
|
||||
if (outEndpoint->GetDescriptor()->bLength != 0)
|
||||
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 6666;
|
||||
return 62;
|
||||
|
||||
m_outPipe = outEndpoint;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,46 +124,24 @@ void Dualshock4Controller::CloseInterfaces()
|
||||
|
||||
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;
|
||||
|
||||
for (int i = 0; i != 64; ++i)
|
||||
{
|
||||
m_inputData[i] = input_bytes[i];
|
||||
}
|
||||
m_UpdateCalled = true;
|
||||
|
||||
uint8_t type = input_bytes[0];
|
||||
|
||||
if (type == XBONEINPUT_BUTTON) //Button data
|
||||
if (type == 0x11) //Button data
|
||||
{
|
||||
m_buttonData = *reinterpret_cast<Dualshock4ButtonData *>(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()
|
||||
{
|
||||
uint8_t init_bytes[]{
|
||||
0x05,
|
||||
0x20, 0x00, 0x01, 0x00};
|
||||
|
||||
Status rc = m_outPipe->Write(init_bytes, sizeof(init_bytes));
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -175,6 +194,41 @@ NormalizedButtonData Dualshock4Controller::GetNormalizedButtonData()
|
||||
{
|
||||
NormalizedButtonData normalData;
|
||||
|
||||
normalData.triggers[0] = NormalizeTrigger(m_buttonData.l2_pressure);
|
||||
normalData.triggers[1] = NormalizeTrigger(m_buttonData.r2_pressure);
|
||||
|
||||
NormalizeAxis(m_buttonData.stick_left_x, m_buttonData.stick_left_y, _dualshock4ControllerConfig.leftStickDeadzonePercent,
|
||||
&normalData.sticks[0].axis_x, &normalData.sticks[0].axis_y);
|
||||
NormalizeAxis(m_buttonData.stick_right_x, m_buttonData.stick_right_y, _dualshock4ControllerConfig.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.l3,
|
||||
m_buttonData.r3,
|
||||
m_buttonData.l1,
|
||||
m_buttonData.r1,
|
||||
m_buttonData.l2,
|
||||
m_buttonData.r2,
|
||||
m_buttonData.share,
|
||||
m_buttonData.options,
|
||||
m_buttonData.dpad & DS4_UP,
|
||||
m_buttonData.dpad & DS4_RIGHT,
|
||||
m_buttonData.dpad & DS4_DOWN,
|
||||
m_buttonData.dpad & DS4_LEFT,
|
||||
m_buttonData.touchpad_press,
|
||||
m_buttonData.psbutton,
|
||||
};
|
||||
|
||||
for (int i = 0; i != NUM_CONTROLLERBUTTONS; ++i)
|
||||
{
|
||||
ControllerButton button = _dualshock4ControllerConfig.buttons[i];
|
||||
normalData.buttons[(button != NOT_SET ? button : i)] = buttons[i];
|
||||
}
|
||||
|
||||
return normalData;
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
#include "SwitchAbstractedPadHandler.h"
|
||||
#include "configFile.h"
|
||||
|
||||
#define APP_VERSION "0.4.2"
|
||||
#define APP_VERSION "0.4.3"
|
||||
|
||||
struct VendorEvent
|
||||
{
|
||||
@ -30,6 +30,19 @@ Result QueryInterfaces(UsbHsInterface *interfaces, size_t interfaces_size, s32 *
|
||||
return 1;
|
||||
}
|
||||
|
||||
Result QueryVendorProduct(UsbHsInterface *interfaces, size_t interfaces_size, s32 *total_entries, uint16_t vendor_id, uint16_t product_id)
|
||||
{
|
||||
UsbHsInterfaceFilter filter;
|
||||
filter.Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct;
|
||||
filter.idVendor = vendor_id;
|
||||
filter.idProduct = product_id;
|
||||
Result rc = usbHsQueryAvailableInterfaces(&filter, interfaces, interfaces_size, total_entries);
|
||||
if (R_SUCCEEDED(rc) && *total_entries != 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::unique_ptr<IUSBDevice> devicePtr;
|
||||
std::unique_ptr<IController> controllerPtr;
|
||||
bool useAbstractedPad = hosversionBetween(5, 7);
|
||||
@ -69,6 +82,7 @@ Result mainLoop()
|
||||
|
||||
Event catchAllEvent;
|
||||
Event ds3Event;
|
||||
Event ds4Event;
|
||||
|
||||
UTimer filecheckTimer;
|
||||
Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer);
|
||||
@ -98,6 +112,25 @@ Result mainLoop()
|
||||
WriteToLog("Failed to open catch-all event");
|
||||
else
|
||||
WriteToLog("Successfully created catch-all event");
|
||||
|
||||
filter.Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct;
|
||||
filter.idVendor = VENDOR_SONY;
|
||||
filter.idProduct = PRODUCT_DUALSHOCK4_2X;
|
||||
rc = usbHsCreateInterfaceAvailableEvent(&ds4Event, true, 2, &filter);
|
||||
if (R_FAILED(rc))
|
||||
WriteToLog("Failed to open event for Dualshock 4 2x");
|
||||
else
|
||||
WriteToLog("Successfully created event for Dualshock 4 2x");
|
||||
/*
|
||||
filter.Flags = UsbHsInterfaceFilterFlags_idVendor | UsbHsInterfaceFilterFlags_idProduct;
|
||||
filter.idVendor = VENDOR_SONY;
|
||||
filter.idProduct = PRODUCT_DUALSHOCK4_1X;
|
||||
rc = usbHsCreateInterfaceAvailableEvent(&ds4Event, true, 2, &filter);
|
||||
if (R_FAILED(rc))
|
||||
WriteToLog("Failed to open event for Dualshock 4 1x");
|
||||
else
|
||||
WriteToLog("Successfully created event for Dualshock 4 1x");
|
||||
*/
|
||||
}
|
||||
|
||||
controllerInterfaces.reserve(10);
|
||||
@ -109,8 +142,26 @@ Result mainLoop()
|
||||
hidScanInput();
|
||||
u64 kDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
||||
|
||||
for (int i = 0; i != 8; ++i)
|
||||
{
|
||||
u64 kHeld = hidKeysDown(static_cast<HidControllerID>(i));
|
||||
if (kHeld != 0)
|
||||
WriteToLog("Player ", i + 1, ": ", kHeld);
|
||||
}
|
||||
|
||||
if (kDown & KEY_B)
|
||||
break;
|
||||
|
||||
for (auto &&handler : controllerInterfaces)
|
||||
{
|
||||
if (handler->GetController()->m_UpdateCalled)
|
||||
{
|
||||
for (int i = 0; i != 64; ++i)
|
||||
printf("0x%02X ", handler->GetController()->m_inputData[i]);
|
||||
printf("\n");
|
||||
handler->GetController()->m_UpdateCalled = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
rc = eventWait(&catchAllEvent, 0);
|
||||
if (R_SUCCEEDED(rc))
|
||||
@ -167,13 +218,27 @@ Result mainLoop()
|
||||
UsbHsInterface interfaces[4];
|
||||
s32 total_entries;
|
||||
|
||||
if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_HID, 0, 0)))
|
||||
if (R_SUCCEEDED(QueryVendorProduct(interfaces, sizeof(interfaces), &total_entries, VENDOR_SONY, PRODUCT_DUALSHOCK3)))
|
||||
{
|
||||
WriteToLog("Registering DS3 controller");
|
||||
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces, total_entries);
|
||||
controllerPtr = std::make_unique<Dualshock3Controller>(std::move(devicePtr));
|
||||
}
|
||||
}
|
||||
rc = eventWait(&ds4Event, 0);
|
||||
if (R_SUCCEEDED(rc))
|
||||
{
|
||||
WriteToLog("Dualshock 4 event went off");
|
||||
UsbHsInterface interfaces[4];
|
||||
s32 total_entries;
|
||||
|
||||
if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_HID, 0, 0)))
|
||||
{
|
||||
WriteToLog("Registering DS4 controller");
|
||||
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces, total_entries);
|
||||
controllerPtr = std::make_unique<Dualshock4Controller>(std::move(devicePtr));
|
||||
}
|
||||
}
|
||||
CallInitHandler();
|
||||
|
||||
//On interface change event, check if any devices were removed, and erase them from memory appropriately
|
||||
@ -238,6 +303,7 @@ Result mainLoop()
|
||||
WriteToLog("Destroying events");
|
||||
usbHsDestroyInterfaceAvailableEvent(&ds3Event, 0);
|
||||
usbHsDestroyInterfaceAvailableEvent(&catchAllEvent, 1);
|
||||
usbHsDestroyInterfaceAvailableEvent(&ds4Event, 2);
|
||||
|
||||
//controllerInterfaces.clear();
|
||||
return rc;
|
||||
|
Loading…
Reference in New Issue
Block a user