From ba7a0b754fb3622b37bf2a9b5340b098dccde308 Mon Sep 17 00:00:00 2001 From: cathery Date: Sat, 9 Nov 2019 02:31:49 +0300 Subject: [PATCH] Add support for multiple 360 wireless controllers --- .../Controllers/Xbox360WirelessController.h | 7 +- ControllerUSB/include/IController.h | 1 + .../Controllers/Xbox360WirelessController.cpp | 36 +++++++--- SwitchUSB/source/SwitchHDLHandler.cpp | 57 ++++++---------- source/main.cpp | 7 +- source/mainLoop.cpp | 67 +++++++++++-------- 6 files changed, 96 insertions(+), 79 deletions(-) diff --git a/ControllerUSB/include/Controllers/Xbox360WirelessController.h b/ControllerUSB/include/Controllers/Xbox360WirelessController.h index c02297d..f080162 100644 --- a/ControllerUSB/include/Controllers/Xbox360WirelessController.h +++ b/ControllerUSB/include/Controllers/Xbox360WirelessController.h @@ -20,7 +20,7 @@ private: Xbox360ButtonData m_buttonData; - bool m_presence; + bool m_presence = false; std::vector m_outputBuffer; @@ -48,7 +48,12 @@ public: Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude); Status SetLED(Xbox360LEDValue value); + Status OnControllerConnect(); + Status OnControllerDisconnect(); + static void LoadConfig(const ControllerConfig *config); Status OutputBuffer(); + + bool IsControllerActive() override { return m_presence; } }; \ No newline at end of file diff --git a/ControllerUSB/include/IController.h b/ControllerUSB/include/IController.h index ee35a9a..80385c5 100644 --- a/ControllerUSB/include/IController.h +++ b/ControllerUSB/include/IController.h @@ -32,6 +32,7 @@ public: inline IUSBDevice *GetDevice() { return m_device.get(); } virtual ControllerType GetType() = 0; virtual Status SetRumble(uint8_t strong_magnitude, uint8_t weak_magnitude) = 0; + virtual bool IsControllerActive() { return true; } Status OutputBuffer() { return 1; }; }; \ No newline at end of file diff --git a/ControllerUSB/source/Controllers/Xbox360WirelessController.cpp b/ControllerUSB/source/Controllers/Xbox360WirelessController.cpp index 376c11c..f13f039 100644 --- a/ControllerUSB/source/Controllers/Xbox360WirelessController.cpp +++ b/ControllerUSB/source/Controllers/Xbox360WirelessController.cpp @@ -4,7 +4,7 @@ static ControllerConfig _xbox360WControllerConfig{}; 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 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 &&interface) : IController(std::move(interface)) @@ -25,12 +25,13 @@ Status Xbox360WirelessController::Initialize() rc = OpenInterfaces(); if (S_FAILED(rc)) return rc; - + /* rc = m_outPipe->Write(reconnectPacket, sizeof(reconnectPacket)); if (S_FAILED(rc)) return rc; SetLED(XBOX360LED_TOPLEFT); + */ return rc; } void Xbox360WirelessController::Exit() @@ -125,12 +126,9 @@ Status Xbox360WirelessController::GetInput() m_presence = newPresence; if (m_presence) - { - m_outputBuffer.push_back(OutputPacket{reconnectPacket, sizeof(reconnectPacket)}); - m_outputBuffer.push_back(OutputPacket{ledPacket, sizeof(ledPacket)}); - } + OnControllerConnect(); 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) { - 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)); + uint8_t customLEDPacket[]{0x00, 0x00, 0x08, static_cast(value | 0x40), 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + return m_outPipe->Write(customLEDPacket, sizeof(customLEDPacket)); } void Xbox360WirelessController::LoadConfig(const ControllerConfig *config) @@ -250,12 +248,28 @@ void Xbox360WirelessController::LoadConfig(const ControllerConfig *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() { if (m_outputBuffer.empty()) return 1; - Status rc = m_outPipe->Write(m_outputBuffer[0].packet, m_outputBuffer[0].length); - m_outputBuffer.erase(m_outputBuffer.begin()); + Status rc; + auto it = m_outputBuffer.begin(); + rc = m_outPipe->Write(it->packet, it->length); + m_outputBuffer.erase(it); + return rc; } diff --git a/SwitchUSB/source/SwitchHDLHandler.cpp b/SwitchUSB/source/SwitchHDLHandler.cpp index 819985e..a88c9d4 100644 --- a/SwitchUSB/source/SwitchHDLHandler.cpp +++ b/SwitchUSB/source/SwitchHDLHandler.cpp @@ -18,39 +18,11 @@ Result SwitchHDLHandler::Initialize() if (R_FAILED(rc)) return rc; - /* - hidScanInput(); - HidControllerID lastOfflineID = CONTROLLER_PLAYER_1; - for (int i = 0; i != 8; ++i) - { - if (!hidIsControllerConnected(static_cast(i))) - { - lastOfflineID = static_cast(i); - break; - } - } - //WriteToLog("Found last offline ID: ", lastOfflineID); - */ - rc = InitHdlState(); if (R_FAILED(rc)) return rc; - /* - 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)) + if (DoesControllerSupport(GetController()->GetType(), SUPPORTS_PAIRING)) { rc = InitOutputThread(); if (R_FAILED(rc)) @@ -93,7 +65,10 @@ Result SwitchHDLHandler::InitHdlState() m_hdlState.joysticks[JOYSTICK_RIGHT].dx = 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() { @@ -155,18 +130,28 @@ void SwitchHDLHandler::UpdateInput() if (R_FAILED(rc)) return; - FillHdlState(GetController()->GetNormalizedButtonData()); - rc = UpdateHdlState(); - if (R_FAILED(rc)) - return; + if (!GetController()->IsControllerActive()) + { + hiddbgDetachHdlsVirtualDevice(m_hdlHandle); + } + else + { + FillHdlState(GetController()->GetNormalizedButtonData()); + rc = UpdateHdlState(); + if (R_FAILED(rc)) + return; + } } void SwitchHDLHandler::UpdateOutput() { - if (R_SUCCEEDED(m_controllerHandler.GetController()->OutputBuffer())) + if (R_SUCCEEDED(GetController()->OutputBuffer())) + { + svcSleepThread(1e+7L); return; + } - if (DoesControllerSupport(m_controllerHandler.GetController()->GetType(), SUPPORTS_RUMBLE)) + if (DoesControllerSupport(GetController()->GetType(), SUPPORTS_RUMBLE)) { Result rc; HidVibrationValue value; diff --git a/source/main.cpp b/source/main.cpp index 6400871..784ad3c 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,6 +1,7 @@ #include "switch.h" #include "log.h" #include "mainLoop.h" +#include "log.h" //ISSUES: // when exiting the applet, only one of the controllers is reset @@ -9,8 +10,6 @@ //TODO: // 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) extern "C" @@ -38,7 +37,7 @@ extern "C" #endif - void __attribute__((weak)) userAppInit(void) + void userAppInit(void) { //Seems like every thread on the switch needs to sleep for a little // or it will block the entire console @@ -65,7 +64,7 @@ extern "C" #endif } - void __attribute__((weak)) userAppExit(void) + void userAppExit(void) { #ifndef __APPLET__ hidExit(); diff --git a/source/mainLoop.cpp b/source/mainLoop.cpp index dba6210..def1054 100644 --- a/source/mainLoop.cpp +++ b/source/mainLoop.cpp @@ -28,15 +28,45 @@ Result QueryInterfaces(UsbHsInterface *interfaces, size_t interfaces_size, s32 * return 1; } +std::unique_ptr devicePtr; +std::unique_ptr controllerPtr; +bool useAbstractedPad = hosversionBetween(5, 7); +std::vector> controllerInterfaces; + +Result CallInitHandler() +{ + if (controllerPtr) + { + Result rc; + std::unique_ptr switchHandler; + if (useAbstractedPad) + switchHandler = std::make_unique(std::move(controllerPtr)); + else + switchHandler = std::make_unique(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() { WriteToLog("\n\nNew sysmodule session started"); Result rc = 0; - bool useAbstractedPad = hosversionBetween(5, 7); Event catchAllEvent; Event ds3Event; - std::vector> controllerInterfaces; UTimer filecheckTimer; Waiter filecheckTimerWaiter = waiterForUTimer(&filecheckTimer); @@ -69,8 +99,6 @@ Result mainLoop() } controllerInterfaces.reserve(8); - std::unique_ptr devicePtr; - std::unique_ptr controllerPtr; while (appletMainLoop()) { @@ -97,9 +125,13 @@ Result mainLoop() } 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)); + WriteToLog("Registering Xbox 360 Wireless adapter"); + for (int i = 0; i != total_entries; ++i) + { + devicePtr = std::make_unique(interfaces + i, 1); + controllerPtr = std::make_unique(std::move(devicePtr)); + CallInitHandler(); + } } else if (R_SUCCEEDED(QueryInterfaces(interfaces, sizeof(interfaces), &total_entries, 0x58, 0x42, 0x00))) { @@ -128,26 +160,7 @@ Result mainLoop() controllerPtr = std::make_unique(std::move(devicePtr)); } } - - if (controllerPtr) - { - std::unique_ptr switchHandler; - if (useAbstractedPad) - switchHandler = std::make_unique(std::move(controllerPtr)); - else - switchHandler = std::make_unique(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); - } - } + CallInitHandler(); //On interface change event, check if any devices were removed, and erase them from memory appropriately rc = eventWait(usbHsGetInterfaceStateChangeEvent(), 0);