1
0
mirror of https://github.com/cathery/sys-con.git synced 2024-07-03 02:18:43 +00:00

Add support for multiple 360 wireless controllers

This commit is contained in:
cathery 2019-11-09 02:31:49 +03:00
parent 435b203525
commit ba7a0b754f
6 changed files with 96 additions and 79 deletions

View File

@ -20,7 +20,7 @@ private:
Xbox360ButtonData m_buttonData; Xbox360ButtonData m_buttonData;
bool m_presence; bool m_presence = false;
std::vector<OutputPacket> m_outputBuffer; std::vector<OutputPacket> m_outputBuffer;
@ -48,7 +48,12 @@ public:
Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude); Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude);
Status SetLED(Xbox360LEDValue value); Status SetLED(Xbox360LEDValue value);
Status OnControllerConnect();
Status OnControllerDisconnect();
static void LoadConfig(const ControllerConfig *config); static void LoadConfig(const ControllerConfig *config);
Status OutputBuffer(); Status OutputBuffer();
bool IsControllerActive() override { return m_presence; }
}; };

View File

@ -32,6 +32,7 @@ public:
inline IUSBDevice *GetDevice() { return m_device.get(); } inline IUSBDevice *GetDevice() { return m_device.get(); }
virtual ControllerType GetType() = 0; virtual ControllerType GetType() = 0;
virtual Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude) = 0; virtual Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude) = 0;
virtual bool IsControllerActive() { return true; }
Status OutputBuffer() { return 1; }; Status OutputBuffer() { return 1; };
}; };

View File

@ -4,7 +4,7 @@
static ControllerConfig _xbox360WControllerConfig{}; static ControllerConfig _xbox360WControllerConfig{};
static const uint8_t reconnectPacket[]{0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t reconnectPacket[]{0x08, 0x00, 0x0F, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const uint8_t poweroffPacket[]{0x00, 0x00, 0x08, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t poweroffPacket[]{0x00, 0x00, 0x08, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
static const uint8_t ledPacket[]{0x00, 0x00, 0x08, 0x2E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static const uint8_t ledPacket[]{0x00, 0x00, 0x08, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
Xbox360WirelessController::Xbox360WirelessController(std::unique_ptr<IUSBDevice> &&interface) Xbox360WirelessController::Xbox360WirelessController(std::unique_ptr<IUSBDevice> &&interface)
: IController(std::move(interface)) : IController(std::move(interface))
@ -25,12 +25,13 @@ Status Xbox360WirelessController::Initialize()
rc = OpenInterfaces(); rc = OpenInterfaces();
if (S_FAILED(rc)) if (S_FAILED(rc))
return rc; return rc;
/*
rc = m_outPipe->Write(reconnectPacket, sizeof(reconnectPacket)); rc = m_outPipe->Write(reconnectPacket, sizeof(reconnectPacket));
if (S_FAILED(rc)) if (S_FAILED(rc))
return rc; return rc;
SetLED(XBOX360LED_TOPLEFT); SetLED(XBOX360LED_TOPLEFT);
*/
return rc; return rc;
} }
void Xbox360WirelessController::Exit() void Xbox360WirelessController::Exit()
@ -125,12 +126,9 @@ Status Xbox360WirelessController::GetInput()
m_presence = newPresence; m_presence = newPresence;
if (m_presence) if (m_presence)
{ OnControllerConnect();
m_outputBuffer.push_back(OutputPacket{reconnectPacket, sizeof(reconnectPacket)});
m_outputBuffer.push_back(OutputPacket{ledPacket, sizeof(ledPacket)});
}
else else
m_outputBuffer.push_back(OutputPacket{poweroffPacket, sizeof(poweroffPacket)}); OnControllerDisconnect();
} }
} }
@ -241,8 +239,8 @@ Status Xbox360WirelessController::SetRumble(uint8_t strong_magnitude, uint8_t we
Status Xbox360WirelessController::SetLED(Xbox360LEDValue value) 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}; uint8_t customLEDPacket[]{0x00, 0x00, 0x08, static_cast<uint8_t>(value | 0x40), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
return m_outPipe->Write(ledPacket, sizeof(ledPacket)); return m_outPipe->Write(customLEDPacket, sizeof(customLEDPacket));
} }
void Xbox360WirelessController::LoadConfig(const ControllerConfig *config) void Xbox360WirelessController::LoadConfig(const ControllerConfig *config)
@ -250,12 +248,28 @@ void Xbox360WirelessController::LoadConfig(const ControllerConfig *config)
_xbox360WControllerConfig = *config; _xbox360WControllerConfig = *config;
} }
Status Xbox360WirelessController::OnControllerConnect()
{
m_outputBuffer.push_back(OutputPacket{reconnectPacket, sizeof(reconnectPacket)});
m_outputBuffer.push_back(OutputPacket{ledPacket, sizeof(ledPacket)});
return 0;
}
Status Xbox360WirelessController::OnControllerDisconnect()
{
m_outputBuffer.push_back(OutputPacket{poweroffPacket, sizeof(poweroffPacket)});
return 0;
}
Status Xbox360WirelessController::OutputBuffer() Status Xbox360WirelessController::OutputBuffer()
{ {
if (m_outputBuffer.empty()) if (m_outputBuffer.empty())
return 1; return 1;
Status rc = m_outPipe->Write(m_outputBuffer[0].packet, m_outputBuffer[0].length); Status rc;
m_outputBuffer.erase(m_outputBuffer.begin()); auto it = m_outputBuffer.begin();
rc = m_outPipe->Write(it->packet, it->length);
m_outputBuffer.erase(it);
return rc; return rc;
} }

View File

@ -18,39 +18,11 @@ Result SwitchHDLHandler::Initialize()
if (R_FAILED(rc)) if (R_FAILED(rc))
return rc; return rc;
/*
hidScanInput();
HidControllerID lastOfflineID = CONTROLLER_PLAYER_1;
for (int i = 0; i != 8; ++i)
{
if (!hidIsControllerConnected(static_cast<HidControllerID>(i)))
{
lastOfflineID = static_cast<HidControllerID>(i);
break;
}
}
//WriteToLog("Found last offline ID: ", lastOfflineID);
*/
rc = InitHdlState(); rc = InitHdlState();
if (R_FAILED(rc)) if (R_FAILED(rc))
return rc; return rc;
/* if (DoesControllerSupport(GetController()->GetType(), SUPPORTS_PAIRING))
svcSleepThread(1e+7L);
hidScanInput();
//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))
InitOutputThread();
else
WriteToLog("Failed to iniitalize vibration with error ", rc2);
*/
if (DoesControllerSupport(m_controllerHandler.GetController()->GetType(), SUPPORTS_PAIRING))
{ {
rc = InitOutputThread(); rc = InitOutputThread();
if (R_FAILED(rc)) if (R_FAILED(rc))
@ -93,7 +65,10 @@ Result SwitchHDLHandler::InitHdlState()
m_hdlState.joysticks[JOYSTICK_RIGHT].dx = 0x5678; m_hdlState.joysticks[JOYSTICK_RIGHT].dx = 0x5678;
m_hdlState.joysticks[JOYSTICK_RIGHT].dy = -0x5678; m_hdlState.joysticks[JOYSTICK_RIGHT].dy = -0x5678;
return hiddbgAttachHdlsVirtualDevice(&m_hdlHandle, &m_deviceInfo); if (GetController()->IsControllerActive())
return hiddbgAttachHdlsVirtualDevice(&m_hdlHandle, &m_deviceInfo);
return 0;
} }
Result SwitchHDLHandler::ExitHdlState() Result SwitchHDLHandler::ExitHdlState()
{ {
@ -155,18 +130,28 @@ void SwitchHDLHandler::UpdateInput()
if (R_FAILED(rc)) if (R_FAILED(rc))
return; return;
FillHdlState(GetController()->GetNormalizedButtonData()); if (!GetController()->IsControllerActive())
rc = UpdateHdlState(); {
if (R_FAILED(rc)) hiddbgDetachHdlsVirtualDevice(m_hdlHandle);
return; }
else
{
FillHdlState(GetController()->GetNormalizedButtonData());
rc = UpdateHdlState();
if (R_FAILED(rc))
return;
}
} }
void SwitchHDLHandler::UpdateOutput() void SwitchHDLHandler::UpdateOutput()
{ {
if (R_SUCCEEDED(m_controllerHandler.GetController()->OutputBuffer())) if (R_SUCCEEDED(GetController()->OutputBuffer()))
{
svcSleepThread(1e+7L);
return; return;
}
if (DoesControllerSupport(m_controllerHandler.GetController()->GetType(), SUPPORTS_RUMBLE)) if (DoesControllerSupport(GetController()->GetType(), SUPPORTS_RUMBLE))
{ {
Result rc; Result rc;
HidVibrationValue value; HidVibrationValue value;

View File

@ -1,6 +1,7 @@
#include "switch.h" #include "switch.h"
#include "log.h" #include "log.h"
#include "mainLoop.h" #include "mainLoop.h"
#include "log.h"
//ISSUES: //ISSUES:
// when exiting the applet, only one of the controllers is reset // when exiting the applet, only one of the controllers is reset
@ -9,8 +10,6 @@
//TODO: //TODO:
// Shrink unneessary heap memory/stack size used for the sysmodule // Shrink unneessary heap memory/stack size used for the sysmodule
// Allow to connect controllers paired through a bluetooth adapter
// Allow to connect controllers through usbDs (directly to switch)
// Make a config application companion to test controller input and edit various preferences (buttons, deadzones) // Make a config application companion to test controller input and edit various preferences (buttons, deadzones)
extern "C" extern "C"
@ -38,7 +37,7 @@ extern "C"
#endif #endif
void __attribute__((weak)) userAppInit(void) void userAppInit(void)
{ {
//Seems like every thread on the switch needs to sleep for a little //Seems like every thread on the switch needs to sleep for a little
// or it will block the entire console // or it will block the entire console
@ -65,7 +64,7 @@ extern "C"
#endif #endif
} }
void __attribute__((weak)) userAppExit(void) void userAppExit(void)
{ {
#ifndef __APPLET__ #ifndef __APPLET__
hidExit(); hidExit();

View File

@ -28,15 +28,45 @@ Result QueryInterfaces(UsbHsInterface *interfaces, size_t interfaces_size, s32 *
return 1; return 1;
} }
std::unique_ptr<IUSBDevice> devicePtr;
std::unique_ptr<IController> controllerPtr;
bool useAbstractedPad = hosversionBetween(5, 7);
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>> controllerInterfaces;
Result CallInitHandler()
{
if (controllerPtr)
{
Result rc;
std::unique_ptr<SwitchVirtualGamepadHandler> switchHandler;
if (useAbstractedPad)
switchHandler = std::make_unique<SwitchAbstractedPadHandler>(std::move(controllerPtr));
else
switchHandler = std::make_unique<SwitchHDLHandler>(std::move(controllerPtr));
rc = switchHandler->Initialize();
if (R_SUCCEEDED(rc))
{
controllerInterfaces.push_back(std::move(switchHandler));
WriteToLog("Interface created successfully");
return 0;
}
else
{
WriteToLog("Error creating interface with error ", rc);
return rc;
}
}
return 1;
}
Result mainLoop() Result mainLoop()
{ {
WriteToLog("\n\nNew sysmodule session started"); WriteToLog("\n\nNew sysmodule session started");
Result rc = 0; Result rc = 0;
bool useAbstractedPad = hosversionBetween(5, 7);
Event catchAllEvent; Event catchAllEvent;
Event ds3Event; Event ds3Event;
std::vector<std::unique_ptr<SwitchVirtualGamepadHandler>> controllerInterfaces;
UTimer filecheckTimer; UTimer filecheckTimer;
Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer); Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer);
@ -69,8 +99,6 @@ Result mainLoop()
} }
controllerInterfaces.reserve(8); controllerInterfaces.reserve(8);
std::unique_ptr<IUSBDevice> devicePtr;
std::unique_ptr<IController> controllerPtr;
while (appletMainLoop()) while (appletMainLoop())
{ {
@ -97,9 +125,13 @@ Result mainLoop()
} }
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 93, 129))) else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, USB_CLASS_VENDOR_SPEC, 93, 129)))
{ {
WriteToLog("Registering Xbox 360 Wireless controller"); WriteToLog("Registering Xbox 360 Wireless adapter");
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces, total_entries); for (int i = 0; i != total_entries; ++i)
controllerPtr = std::make_unique<Xbox360WirelessController>(std::move(devicePtr)); {
devicePtr = std::make_unique<SwitchUSBDevice>(interfaces + i, 1);
controllerPtr = std::make_unique<Xbox360WirelessController>(std::move(devicePtr));
CallInitHandler();
}
} }
else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, 0x58, 0x42, 0x00))) else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, 0x58, 0x42, 0x00)))
{ {
@ -128,26 +160,7 @@ Result mainLoop()
controllerPtr = std::make_unique<Dualshock3Controller>(std::move(devicePtr)); controllerPtr = std::make_unique<Dualshock3Controller>(std::move(devicePtr));
} }
} }
CallInitHandler();
if (controllerPtr)
{
std::unique_ptr<SwitchVirtualGamepadHandler> switchHandler;
if (useAbstractedPad)
switchHandler = std::make_unique<SwitchAbstractedPadHandler>(std::move(controllerPtr));
else
switchHandler = std::make_unique<SwitchHDLHandler>(std::move(controllerPtr));
rc = switchHandler->Initialize();
if (R_SUCCEEDED(rc))
{
controllerInterfaces.push_back(std::move(switchHandler));
WriteToLog("Interface created successfully");
}
else
{
WriteToLog("Error creating interface with error ", rc);
}
}
//On interface change event, check if any devices were removed, and erase them from memory appropriately //On interface change event, check if any devices were removed, and erase them from memory appropriately
rc = eventWait(usbHsGetInterfaceStateChangeEvent(), 0); rc = eventWait(usbHsGetInterfaceStateChangeEvent(), 0);