diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java new file mode 100644 index 0000000000..51d00ad348 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/Java_GCAdapter.java @@ -0,0 +1,91 @@ +package org.dolphinemu.dolphinemu.utils; + +import android.app.Activity; +import android.hardware.usb.UsbConfiguration; +import android.hardware.usb.UsbConstants; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; +import android.hardware.usb.UsbEndpoint; +import android.hardware.usb.UsbInterface; +import android.hardware.usb.UsbManager; + +import java.util.HashMap; +import java.util.Iterator; + +public class Java_GCAdapter { + public static UsbManager manager; + public static Activity our_activity; + static byte[] controller_payload = new byte[37]; + static byte HasRead; + + static UsbDeviceConnection usb_con; + static UsbInterface usb_intf; + static UsbEndpoint usb_in; + static UsbEndpoint usb_out; + + public static void Shutdown() + { + usb_con.close(); + } + public static int GetFD() { return usb_con.getFileDescriptor(); } + + public static boolean QueryAdapter() + { + HashMap devices = manager.getDeviceList(); + Iterator it = devices.entrySet().iterator(); + while (it.hasNext()) + { + HashMap.Entry pair = (HashMap.Entry) it.next(); + UsbDevice dev = (UsbDevice) pair.getValue(); + if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) + if (manager.hasPermission(dev)) + return true; + } + return false; + } + + public static void InitAdapter() + { + byte[] init = { 0x13 }; + usb_con.bulkTransfer(usb_in, init, init.length, 0); + } + + public static int Input() { + int read = usb_con.bulkTransfer(usb_in, controller_payload, controller_payload.length, 16); + return read; + } + + public static int Output(byte[] rumble) { + int size = usb_con.bulkTransfer(usb_out, rumble, 5, 16); + return size; + } + + public static void OpenAdapter() + { + HashMap devices = manager.getDeviceList(); + Iterator it = devices.entrySet().iterator(); + while (it.hasNext()) + { + HashMap.Entry pair = (HashMap.Entry)it.next(); + UsbDevice dev = (UsbDevice)pair.getValue(); + if (dev.getProductId() == 0x0337 && dev.getVendorId() == 0x057e) { + if (manager.hasPermission(dev)) + { + usb_con = manager.openDevice(dev); + UsbConfiguration conf = dev.getConfiguration(0); + usb_intf = conf.getInterface(0); + usb_con.claimInterface(usb_intf, true); + for (int i = 0; i < usb_intf.getEndpointCount(); ++i) + if (usb_intf.getEndpoint(i).getDirection() == UsbConstants.USB_DIR_IN) + usb_in = usb_intf.getEndpoint(i); + else + usb_out = usb_intf.getEndpoint(i); + + InitAdapter(); + return; + } + } + + } + } +} diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 10a51b4a65..b035b64859 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -113,6 +113,7 @@ set(SRCS ActionReplay.cpp HW/SI_Device.cpp HW/SI_DeviceDanceMat.cpp HW/SI_DeviceGBA.cpp + HW/SI_DeviceGCAdapter.cpp HW/SI_DeviceGCController.cpp HW/SI_DeviceGCSteeringWheel.cpp HW/SI_DeviceKeyboard.cpp @@ -239,8 +240,7 @@ set(LIBS if(LIBUSB_FOUND) # Using shared LibUSB set(LIBS ${LIBS} ${LIBUSB_LIBRARIES}) - set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp - HW/SI_GCAdapter.cpp) + set(SRCS ${SRCS} IPC_HLE/WII_IPC_HLE_Device_hid.cpp) endif(LIBUSB_FOUND) set(LIBS ${LIBS} ${MBEDTLS_LIBRARIES}) diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp index c4a857b82d..20c62d8f8f 100644 --- a/Source/Core/Core/ConfigManager.cpp +++ b/Source/Core/Core/ConfigManager.cpp @@ -254,6 +254,8 @@ void SConfig::SaveCoreSettings(IniFile& ini) for (int i = 0; i < MAX_SI_CHANNELS; ++i) { core->Set(StringFromFormat("SIDevice%i", i), m_SIDevice[i]); + core->Set(StringFromFormat("AdapterRumble%i", i), m_AdapterRumble[i]); + core->Set(StringFromFormat("SimulateKonga%i", i), m_AdapterKonga[i]); } core->Set("WiiSDCard", m_WiiSDCard); core->Set("WiiKeyboard", m_WiiKeyboard); @@ -267,8 +269,6 @@ void SConfig::SaveCoreSettings(IniFile& ini) core->Set("OverclockEnable", m_OCEnable); core->Set("GFXBackend", m_strVideoBackend); core->Set("GPUDeterminismMode", m_strGPUDeterminismMode); - core->Set("GameCubeAdapter", m_GameCubeAdapter); - core->Set("AdapterRumble", m_AdapterRumble); core->Set("PerfMapDir", m_perfDir); } @@ -509,6 +509,8 @@ void SConfig::LoadCoreSettings(IniFile& ini) for (int i = 0; i < MAX_SI_CHANNELS; ++i) { core->Get(StringFromFormat("SIDevice%i", i), (u32*)&m_SIDevice[i], (i == 0) ? SIDEVICE_GC_CONTROLLER : SIDEVICE_NONE); + core->Get(StringFromFormat("AdapterRumble%i", i), &m_AdapterRumble[i], true); + core->Get(StringFromFormat("SimulateKonga%i", i), &m_AdapterKonga[i], false); } core->Get("WiiSDCard", &m_WiiSDCard, false); core->Get("WiiKeyboard", &m_WiiKeyboard, false); @@ -532,8 +534,6 @@ void SConfig::LoadCoreSettings(IniFile& ini) core->Get("FrameSkip", &m_FrameSkip, 0); core->Get("GFXBackend", &m_strVideoBackend, ""); core->Get("GPUDeterminismMode", &m_strGPUDeterminismMode, "auto"); - core->Get("GameCubeAdapter", &m_GameCubeAdapter, false); - core->Get("AdapterRumble", &m_AdapterRumble, true); core->Get("PerfMapDir", &m_perfDir, ""); } diff --git a/Source/Core/Core/ConfigManager.h b/Source/Core/Core/ConfigManager.h index 973f49939a..6971f5de79 100644 --- a/Source/Core/Core/ConfigManager.h +++ b/Source/Core/Core/ConfigManager.h @@ -264,8 +264,8 @@ struct SConfig : NonCopyable // Input settings bool m_BackgroundInput; - bool m_GameCubeAdapter; - bool m_AdapterRumble; + bool m_AdapterRumble[4]; + bool m_AdapterKonga[4]; SysConf* m_SYSCONF; diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index b6669b57d2..b818c5c5b1 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -48,9 +48,6 @@ #include "Core/HW/HW.h" #include "Core/HW/Memmap.h" #include "Core/HW/ProcessorInterface.h" -#if defined(__LIBUSB__) || defined(_WIN32) -#include "Core/HW/SI_GCAdapter.h" -#endif #include "Core/HW/SystemTimers.h" #include "Core/HW/VideoInterface.h" #include "Core/HW/Wiimote.h" @@ -65,6 +62,7 @@ #endif #include "DiscIO/FileMonitor.h" +#include "InputCommon/GCAdapter.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" #include "VideoCommon/OnScreenDisplay.h" #include "VideoCommon/VideoBackendBase.h" @@ -285,7 +283,7 @@ void Stop() // - Hammertime! g_video_backend->Video_ExitLoop(); } #if defined(__LIBUSB__) || defined(_WIN32) - SI_GCAdapter::ResetRumble(); + GCAdapter::ResetRumble(); #endif #ifdef USE_MEMORYWATCHER @@ -630,7 +628,7 @@ void SetState(EState _State) CPU::EnableStepping(true); // Break Wiimote::Pause(); #if defined(__LIBUSB__) || defined(_WIN32) - SI_GCAdapter::ResetRumble(); + GCAdapter::ResetRumble(); #endif break; case CORE_RUN: @@ -741,7 +739,7 @@ bool PauseAndLock(bool doLock, bool unpauseOnUnlock) g_video_backend->PauseAndLock(doLock, unpauseOnUnlock); #if defined(__LIBUSB__) || defined(_WIN32) - SI_GCAdapter::ResetRumble(); + GCAdapter::ResetRumble(); #endif return wasUnpaused; } diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 05af583ed2..490e724006 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -145,16 +145,10 @@ + - - - 4200;%(DisableSpecificWarnings) - @@ -357,10 +351,10 @@ + - diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index a374defc07..1a3df6a407 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -447,6 +447,9 @@ HW %28Flipper/Hollywood%29\SI - Serial Interface + + HW %28Flipper/Hollywood%29\SI - Serial Interface + HW %28Flipper/Hollywood%29\SI - Serial Interface @@ -720,9 +723,6 @@ PowerPC - - HW %28Flipper/Hollywood%29\SI - Serial Interface - PowerPC\JitCommon @@ -991,6 +991,9 @@ HW %28Flipper/Hollywood%29\SI - Serial Interface + + HW %28Flipper/Hollywood%29\SI - Serial Interface + HW %28Flipper/Hollywood%29\SI - Serial Interface @@ -1241,9 +1244,6 @@ HW %28Flipper/Hollywood%29\GCKeyboard - - HW %28Flipper/Hollywood%29\SI - Serial Interface - PowerPC\Jit64Common diff --git a/Source/Core/Core/HW/SI_Device.cpp b/Source/Core/Core/HW/SI_Device.cpp index 9546cba42f..fb9b9ec638 100644 --- a/Source/Core/Core/HW/SI_Device.cpp +++ b/Source/Core/Core/HW/SI_Device.cpp @@ -11,6 +11,7 @@ #include "Core/HW/SI_DeviceAMBaseboard.h" #include "Core/HW/SI_DeviceDanceMat.h" #include "Core/HW/SI_DeviceGBA.h" +#include "Core/HW/SI_DeviceGCAdapter.h" #include "Core/HW/SI_DeviceGCController.h" #include "Core/HW/SI_DeviceGCSteeringWheel.h" #include "Core/HW/SI_DeviceKeyboard.h" @@ -73,6 +74,9 @@ std::unique_ptr SIDevice_Create(const SIDevices device, const int por case SIDEVICE_GC_CONTROLLER: return std::make_unique(device, port_number); + case SIDEVICE_WIIU_ADAPTER: + return std::make_unique(device, port_number); + case SIDEVICE_DANCEMAT: return std::make_unique(device, port_number); diff --git a/Source/Core/Core/HW/SI_Device.h b/Source/Core/Core/HW/SI_Device.h index abaf25cbd3..866ae98e2a 100644 --- a/Source/Core/Core/HW/SI_Device.h +++ b/Source/Core/Core/HW/SI_Device.h @@ -61,7 +61,8 @@ enum SIDevices : int SIDEVICE_GC_STEERING, SIDEVICE_DANCEMAT, SIDEVICE_GC_TARUKONGA, - SIDEVICE_AM_BASEBOARD + SIDEVICE_AM_BASEBOARD, + SIDEVICE_WIIU_ADAPTER, }; diff --git a/Source/Core/Core/HW/SI_DeviceGCAdapter.cpp b/Source/Core/Core/HW/SI_DeviceGCAdapter.cpp new file mode 100644 index 0000000000..0f2c55ca5d --- /dev/null +++ b/Source/Core/Core/HW/SI_DeviceGCAdapter.cpp @@ -0,0 +1,150 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Common/MsgHandler.h" +#include "Common/Logging/Log.h" +#include "Core/ConfigManager.h" +#include "Core/Movie.h" +#include "Core/HW/SI_DeviceGCAdapter.h" + +CSIDevice_GCAdapter::CSIDevice_GCAdapter(SIDevices device, int _iDeviceNumber) + : CSIDevice_GCController(device, _iDeviceNumber) +{ + // get the correct pad number that should rumble locally when using netplay + const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); + m_simulate_konga = SConfig::GetInstance().m_AdapterKonga[numPAD]; +} + +GCPadStatus CSIDevice_GCAdapter::GetPadStatus() +{ + GCPadStatus PadStatus; + memset(&PadStatus, 0, sizeof(PadStatus)); + + GCAdapter::Input(ISIDevice::m_iDeviceNumber, &PadStatus); + + HandleMoviePadStatus(&PadStatus); + + return PadStatus; +} + +int CSIDevice_GCAdapter::RunBuffer(u8* _pBuffer, int _iLength) +{ + // For debug logging only + ISIDevice::RunBuffer(_pBuffer, _iLength); + + // Read the command + EBufferCommands command = static_cast(_pBuffer[3]); + + // get the correct pad number that should rumble locally when using netplay + const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); + if (!GCAdapter::DeviceConnected(numPAD)) + { + reinterpret_cast(_pBuffer)[0] = SI_NONE; + return 4; + } + + // Handle it + switch (command) + { + case CMD_RESET: + case CMD_ID: + *(u32*)&_pBuffer[0] = SI_GC_CONTROLLER; + break; + + case CMD_DIRECT: + { + INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength); + u32 high, low; + GetData(high, low); + for (int i = 0; i < (_iLength - 1) / 2; i++) + { + _pBuffer[i + 0] = (high >> (i * 8)) & 0xff; + _pBuffer[i + 4] = (low >> (i * 8)) & 0xff; + } + } + break; + + case CMD_ORIGIN: + { + INFO_LOG(SERIALINTERFACE, "PAD - Get Origin"); + + Calibrate(); + + u8* pCalibration = reinterpret_cast(&m_Origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + break; + + // Recalibrate (FiRES: i am not 100 percent sure about this) + case CMD_RECALIBRATE: + { + INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate"); + + Calibrate(); + + u8* pCalibration = reinterpret_cast(&m_Origin); + for (int i = 0; i < (int)sizeof(SOrigin); i++) + { + _pBuffer[i ^ 3] = *pCalibration++; + } + } + break; + + // DEFAULT + default: + { + ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command); + PanicAlert("SI: Unknown command (0x%x)", command); + } + break; + } + + return _iLength; +} + +void CSIDevice_GCAdapter::SendCommand(u32 _Cmd, u8 _Poll) +{ + UCommand command(_Cmd); + + switch (command.Command) + { + // Costis sent it in some demos :) + case 0x00: + break; + + case CMD_WRITE: + { + unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard + unsigned int uStrength = command.Parameter2; + + // get the correct pad number that should rumble locally when using netplay + const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); + + if (numPAD < 4) + { + if (uType == 1 && uStrength > 2) + GCAdapter::Output(numPAD, 1); + else + GCAdapter::Output(numPAD, 0); + } + if (!_Poll) + { + m_Mode = command.Parameter2; + INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode); + } + } + break; + + default: + { + ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd); + PanicAlert("SI: Unknown direct command"); + } + break; + } +} + diff --git a/Source/Core/Core/HW/SI_DeviceGCAdapter.h b/Source/Core/Core/HW/SI_DeviceGCAdapter.h new file mode 100644 index 0000000000..e171e3a5a0 --- /dev/null +++ b/Source/Core/Core/HW/SI_DeviceGCAdapter.h @@ -0,0 +1,20 @@ +// Copyright 2008 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include "Core/HW/SI_Device.h" +#include "Core/HW/SI_DeviceGCController.h" +#include "InputCommon/GCAdapter.h" +#include "InputCommon/GCPadStatus.h" + +class CSIDevice_GCAdapter : public CSIDevice_GCController +{ +public: + CSIDevice_GCAdapter(SIDevices device, int _iDeviceNumber); + + GCPadStatus GetPadStatus() override; + int RunBuffer(u8* _pBuffer, int _iLength) override; + void SendCommand(u32 _Cmd, u8 _Poll) override; +}; diff --git a/Source/Core/Core/HW/SI_DeviceGCController.cpp b/Source/Core/Core/HW/SI_DeviceGCController.cpp index ccf27baac4..cf6eb50ff5 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.cpp +++ b/Source/Core/Core/HW/SI_DeviceGCController.cpp @@ -13,9 +13,6 @@ #include "Core/HW/SI.h" #include "Core/HW/SI_Device.h" #include "Core/HW/SI_DeviceGCController.h" -#if defined(__LIBUSB__) || defined (_WIN32) -#include "Core/HW/SI_GCAdapter.h" -#endif #include "Core/HW/SystemTimers.h" #include "InputCommon/GCPadStatus.h" @@ -119,6 +116,30 @@ int CSIDevice_GCController::RunBuffer(u8* _pBuffer, int _iLength) return _iLength; } +void CSIDevice_GCController::HandleMoviePadStatus(GCPadStatus* PadStatus) +{ + Movie::CallGCInputManip(PadStatus, ISIDevice::m_iDeviceNumber); + + Movie::SetPolledDevice(); + if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, PadStatus)) + { + } + else if (Movie::IsPlayingInput()) + { + Movie::PlayController(PadStatus, ISIDevice::m_iDeviceNumber); + Movie::InputUpdate(); + } + else if (Movie::IsRecordingInput()) + { + Movie::RecordInput(PadStatus, ISIDevice::m_iDeviceNumber); + Movie::InputUpdate(); + } + else + { + Movie::CheckPadStatus(PadStatus, ISIDevice::m_iDeviceNumber); + } +} + GCPadStatus CSIDevice_GCController::GetPadStatus() { GCPadStatus PadStatus; @@ -126,31 +147,7 @@ GCPadStatus CSIDevice_GCController::GetPadStatus() Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); -#if defined(__LIBUSB__) || defined (_WIN32) - SI_GCAdapter::Input(ISIDevice::m_iDeviceNumber, &PadStatus); -#endif - - Movie::CallGCInputManip(&PadStatus, ISIDevice::m_iDeviceNumber); - - Movie::SetPolledDevice(); - if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, &PadStatus)) - { - } - else if (Movie::IsPlayingInput()) - { - Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber); - Movie::InputUpdate(); - } - else if (Movie::IsRecordingInput()) - { - Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber); - Movie::InputUpdate(); - } - else - { - Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber); - } - + HandleMoviePadStatus(&PadStatus); return PadStatus; } @@ -163,6 +160,8 @@ GCPadStatus CSIDevice_GCController::GetPadStatus() bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) { GCPadStatus PadStatus = GetPadStatus(); + if (HandleButtonCombos(PadStatus) == COMBO_ORIGIN) + PadStatus.button |= PAD_GET_ORIGIN; _Hi = MapPadStatus(PadStatus); @@ -211,7 +210,12 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low) _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits } - HandleButtonCombos(PadStatus); + // Unset all bits except those that represent + // A, B, X, Y, Start and the error bits, as they + // are not used. + if (m_simulate_konga) + _Hi &= ~0x20FFFFFF; + return true; } @@ -225,7 +229,7 @@ u32 CSIDevice_GCController::MapPadStatus(const GCPadStatus& pad_status) return _Hi; } -void CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) +CSIDevice_GCController::EButtonCombo CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) { // Keep track of the special button combos (embedded in controller hardware... :( ) EButtonCombo tempCombo; @@ -258,8 +262,11 @@ void CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) m_Origin.uTrigger_R = pad_status.triggerRight; } m_LastButtonCombo = COMBO_NONE; + return tempCombo; } } + + return COMBO_NONE; } // SendCommand @@ -281,15 +288,6 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll) // get the correct pad number that should rumble locally when using netplay const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber); -#if defined(__LIBUSB__) || defined (_WIN32) - if (numPAD < 4) - { - if (uType == 1 && uStrength > 2) - SI_GCAdapter::Output(numPAD, 1); - else - SI_GCAdapter::Output(numPAD, 0); - } -#endif if (numPAD < 4) { if (uType == 1 && uStrength > 2) diff --git a/Source/Core/Core/HW/SI_DeviceGCController.h b/Source/Core/Core/HW/SI_DeviceGCController.h index 855ae89127..ca772131dc 100644 --- a/Source/Core/Core/HW/SI_DeviceGCController.h +++ b/Source/Core/Core/HW/SI_DeviceGCController.h @@ -79,6 +79,9 @@ protected: // Type of button combo from the last/current poll EButtonCombo m_LastButtonCombo; + // Set this if we want to simulate the "TaruKonga" DK Bongo controller + bool m_simulate_konga = false; + public: // Constructor @@ -98,14 +101,15 @@ public: virtual GCPadStatus GetPadStatus(); virtual u32 MapPadStatus(const GCPadStatus& pad_status); - virtual void HandleButtonCombos(const GCPadStatus& pad_status); + virtual EButtonCombo HandleButtonCombos(const GCPadStatus& pad_status); // Send and Receive pad input from network static bool NetPlay_GetInput(u8 numPAD, GCPadStatus* status); static u8 NetPlay_InGamePadToLocalPad(u8 numPAD); -private: +protected: void Calibrate(); + void HandleMoviePadStatus(GCPadStatus* PadStatus); }; @@ -113,16 +117,8 @@ private: class CSIDevice_TaruKonga : public CSIDevice_GCController { public: - CSIDevice_TaruKonga(SIDevices device, int _iDeviceNumber) : CSIDevice_GCController(device, _iDeviceNumber) { } - - bool GetData(u32& _Hi, u32& _Low) override + CSIDevice_TaruKonga(SIDevices device, int _iDeviceNumber) : CSIDevice_GCController(device, _iDeviceNumber) { - CSIDevice_GCController::GetData(_Hi, _Low); - - // Unset all bits except those that represent - // A, B, X, Y, Start and the error bits, as they - // are not used. - _Hi &= ~0x20FFFFFF; - return true; + m_simulate_konga = true; } }; diff --git a/Source/Core/DolphinWX/CMakeLists.txt b/Source/Core/DolphinWX/CMakeLists.txt index d9cdb9bd9b..1c17ccd207 100644 --- a/Source/Core/DolphinWX/CMakeLists.txt +++ b/Source/Core/DolphinWX/CMakeLists.txt @@ -10,6 +10,7 @@ set(GUI_SRCS Config/AudioConfigPane.cpp Config/ConfigMain.cpp Config/GameCubeConfigPane.cpp + Config/GCAdapterConfigDiag.cpp Config/GeneralConfigPane.cpp Config/InterfaceConfigPane.cpp Config/PathConfigPane.cpp diff --git a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp new file mode 100644 index 0000000000..06ef12dd80 --- /dev/null +++ b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.cpp @@ -0,0 +1,77 @@ +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#include "Common/CommonTypes.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "DolphinWX/Config/GCAdapterConfigDiag.h" +#include "InputCommon/GCAdapter.h" + +wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent); + + +GCAdapterConfigDiag::GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, const int tab_num) + : wxDialog(parent, wxID_ANY, name, wxPoint(128,-1)), m_pad_id(tab_num) +{ + wxBoxSizer* const szr = new wxBoxSizer(wxVERTICAL); + + + wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble")); + gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble[m_pad_id]); + gamecube_rumble->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterRumble, this); + + wxCheckBox* const gamecube_konga = new wxCheckBox(this, wxID_ANY, _("Simulate DK TaruKonga")); + gamecube_konga->SetValue(SConfig::GetInstance().m_AdapterKonga[m_pad_id]); + gamecube_konga->Bind(wxEVT_CHECKBOX, &GCAdapterConfigDiag::OnAdapterKonga, this); + + m_adapter_status = new wxStaticText(this, wxID_ANY, _("Adapter Not Detected")); + + if (!GCAdapter::IsDetected()) + { + if (!GCAdapter::IsDriverDetected()) + { + m_adapter_status->SetLabelText(_("Driver Not Detected")); + gamecube_rumble->Disable(); + } + } + else + { + m_adapter_status->SetLabelText(_("Adapter Detected")); + } + GCAdapter::SetAdapterCallback(std::bind(&GCAdapterConfigDiag::ScheduleAdapterUpdate, this)); + + szr->Add(m_adapter_status, 0, wxEXPAND); + szr->Add(gamecube_rumble, 0, wxEXPAND); + szr->Add(gamecube_konga, 0, wxEXPAND); + szr->Add(CreateButtonSizer(wxOK | wxNO_DEFAULT), 0, wxEXPAND|wxALL, 5); + + SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); + SetSizerAndFit(szr); + Center(); + + Bind(wxEVT_ADAPTER_UPDATE, &GCAdapterConfigDiag::UpdateAdapter, this); +} + +void GCAdapterConfigDiag::ScheduleAdapterUpdate() +{ + wxQueueEvent(this, new wxCommandEvent(wxEVT_ADAPTER_UPDATE)); +} + +void GCAdapterConfigDiag::UpdateAdapter(wxCommandEvent& ev) +{ + bool unpause = Core::PauseAndLock(true); + if (GCAdapter::IsDetected()) + m_adapter_status->SetLabelText(_("Adapter Detected")); + else + m_adapter_status->SetLabelText(_("Adapter Not Detected")); + Core::PauseAndLock(false, unpause); +} + +GCAdapterConfigDiag::~GCAdapterConfigDiag() +{ + GCAdapter::SetAdapterCallback(nullptr); +} diff --git a/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.h b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.h new file mode 100644 index 0000000000..4c86f55a2e --- /dev/null +++ b/Source/Core/DolphinWX/Config/GCAdapterConfigDiag.h @@ -0,0 +1,40 @@ +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Core/ConfigManager.h" + +class GCAdapterConfigDiag : public wxDialog +{ +public: + GCAdapterConfigDiag(wxWindow* const parent, const wxString& name, const int tab_num = 0); + ~GCAdapterConfigDiag(); + + void ScheduleAdapterUpdate(); + void UpdateAdapter(wxCommandEvent& ev); + +private: + wxStaticText* m_adapter_status; + int m_pad_id; + + void OnAdapterRumble(wxCommandEvent& event) + { + SConfig::GetInstance().m_AdapterRumble[m_pad_id] = event.IsChecked(); + } + + void OnAdapterKonga(wxCommandEvent& event) + { + SConfig::GetInstance().m_AdapterKonga[m_pad_id] = event.IsChecked(); + } +}; diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.cpp b/Source/Core/DolphinWX/ControllerConfigDiag.cpp index 149247dd81..8bc510f7a5 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.cpp +++ b/Source/Core/DolphinWX/ControllerConfigDiag.cpp @@ -26,26 +26,24 @@ #include "Core/HW/GCKeyboard.h" #include "Core/HW/GCPad.h" #include "Core/HW/SI.h" -#if defined(__LIBUSB__) || defined (_WIN32) -#include "Core/HW/SI_GCAdapter.h" -#endif #include "Core/HW/Wiimote.h" #include "Core/HW/WiimoteReal/WiimoteReal.h" #include "DolphinWX/ControllerConfigDiag.h" #include "DolphinWX/InputConfigDiag.h" +#include "DolphinWX/Config/GCAdapterConfigDiag.h" +#include "InputCommon/GCAdapter.h" #if defined(HAVE_XRANDR) && HAVE_XRANDR #include "DolphinWX/X11Utils.h" #endif -wxDEFINE_EVENT(wxEVT_ADAPTER_UPDATE, wxCommandEvent); - ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent) : wxDialog(parent, wxID_ANY, _("Dolphin Controller Configuration")) { m_gc_pad_type_strs = {{ _("None"), _("Standard Controller"), + _("GameCube Adapter for Wii U"), _("Steering Wheel"), _("Dance Mat"), _("TaruKonga (Bongos)"), @@ -70,7 +68,6 @@ ControllerConfigDiag::ControllerConfigDiag(wxWindow* const parent) SetLayoutAdaptationMode(wxDIALOG_ADAPTATION_MODE_ENABLED); SetSizerAndFit(main_sizer); Center(); - Bind(wxEVT_ADAPTER_UPDATE, &ControllerConfigDiag::UpdateAdapter, this); } wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() @@ -113,24 +110,27 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() case SIDEVICE_GC_CONTROLLER: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[1]); break; - case SIDEVICE_GC_STEERING: + case SIDEVICE_WIIU_ADAPTER: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[2]); break; - case SIDEVICE_DANCEMAT: + case SIDEVICE_GC_STEERING: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[3]); break; - case SIDEVICE_GC_TARUKONGA: + case SIDEVICE_DANCEMAT: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[4]); break; - case SIDEVICE_GC_GBA: + case SIDEVICE_GC_TARUKONGA: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[5]); + break; + case SIDEVICE_GC_GBA: + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[6]); gamecube_configure_bt[i]->Disable(); break; case SIDEVICE_GC_KEYBOARD: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[6]); + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[7]); break; case SIDEVICE_AM_BASEBOARD: - pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[7]); + pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[8]); break; default: pad_type_choices[i]->SetStringSelection(m_gc_pad_type_strs[0]); @@ -147,67 +147,9 @@ wxStaticBoxSizer* ControllerConfigDiag::CreateGamecubeSizer() gamecube_static_sizer->Add(gamecube_flex_sizer, 1, wxEXPAND, 5); gamecube_static_sizer->AddSpacer(5); - wxStaticBoxSizer* const gamecube_adapter_group = new wxStaticBoxSizer(wxVERTICAL, this, _("GameCube Adapter")); - wxBoxSizer* const gamecube_adapter_sizer = new wxBoxSizer(wxHORIZONTAL); - - wxCheckBox* const gamecube_adapter = new wxCheckBox(this, wxID_ANY, _("Direct Connect")); - gamecube_adapter->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnGameCubeAdapter, this); - - wxCheckBox* const gamecube_rumble = new wxCheckBox(this, wxID_ANY, _("Rumble")); - gamecube_rumble->SetValue(SConfig::GetInstance().m_AdapterRumble); - gamecube_rumble->Bind(wxEVT_CHECKBOX, &ControllerConfigDiag::OnAdapterRumble, this); - - m_adapter_status = new wxStaticText(this, wxID_ANY, _("Adapter Not Detected")); - - gamecube_adapter_group->Add(m_adapter_status, 0, wxEXPAND); - gamecube_adapter_sizer->Add(gamecube_adapter, 0, wxEXPAND); - gamecube_adapter_sizer->Add(gamecube_rumble, 0, wxEXPAND); - gamecube_adapter_group->Add(gamecube_adapter_sizer, 0, wxEXPAND); - gamecube_static_sizer->Add(gamecube_adapter_group, 0, wxEXPAND); - -#if defined(__LIBUSB__) || defined (_WIN32) - gamecube_adapter->SetValue(SConfig::GetInstance().m_GameCubeAdapter); - if (!SI_GCAdapter::IsDetected()) - { - if (!SI_GCAdapter::IsDriverDetected()) - { - m_adapter_status->SetLabelText(_("Driver Not Detected")); - gamecube_adapter->Disable(); - gamecube_adapter->SetValue(false); - gamecube_rumble->Disable(); - } - } - else - { - m_adapter_status->SetLabelText(_("Adapter Detected")); - } - if (Core::GetState() != Core::CORE_UNINITIALIZED) - { - gamecube_adapter->Disable(); - } - SI_GCAdapter::SetAdapterCallback(std::bind(&ControllerConfigDiag::ScheduleAdapterUpdate, this)); -#endif - return gamecube_static_sizer; } -void ControllerConfigDiag::ScheduleAdapterUpdate() -{ - wxQueueEvent(this, new wxCommandEvent(wxEVT_ADAPTER_UPDATE)); -} - -void ControllerConfigDiag::UpdateAdapter(wxCommandEvent& ev) -{ -#if defined(__LIBUSB__) || defined (_WIN32) - bool unpause = Core::PauseAndLock(true); - if (SI_GCAdapter::IsDetected()) - m_adapter_status->SetLabelText(_("Adapter Detected")); - else - m_adapter_status->SetLabelText(_("Adapter Not Detected")); - Core::PauseAndLock(false, unpause); -#endif -} - wxStaticBoxSizer* ControllerConfigDiag::CreateWiimoteConfigSizer() { wxStaticText* wiimote_label[4]; @@ -504,30 +446,35 @@ void ControllerConfigDiag::OnGameCubePortChanged(wxCommandEvent& event) } else if (device_name == m_gc_pad_type_strs[2]) { - tempType = SIDEVICE_GC_STEERING; + tempType = SIDEVICE_WIIU_ADAPTER; gamecube_configure_bt[device_num]->Enable(); } else if (device_name == m_gc_pad_type_strs[3]) { - tempType = SIDEVICE_DANCEMAT; + tempType = SIDEVICE_GC_STEERING; gamecube_configure_bt[device_num]->Enable(); } else if (device_name == m_gc_pad_type_strs[4]) { - tempType = SIDEVICE_GC_TARUKONGA; + tempType = SIDEVICE_DANCEMAT; gamecube_configure_bt[device_num]->Enable(); } else if (device_name == m_gc_pad_type_strs[5]) + { + tempType = SIDEVICE_GC_TARUKONGA; + gamecube_configure_bt[device_num]->Enable(); + } + else if (device_name == m_gc_pad_type_strs[6]) { tempType = SIDEVICE_GC_GBA; gamecube_configure_bt[device_num]->Disable(); } - else if (device_name == m_gc_pad_type_strs[6]) + else if (device_name == m_gc_pad_type_strs[7]) { tempType = SIDEVICE_GC_KEYBOARD; gamecube_configure_bt[device_num]->Enable(); } - else if (device_name == m_gc_pad_type_strs[7]) + else if (device_name == m_gc_pad_type_strs[8]) { tempType = SIDEVICE_AM_BASEBOARD; gamecube_configure_bt[device_num]->Enable(); @@ -540,6 +487,11 @@ void ControllerConfigDiag::OnGameCubePortChanged(wxCommandEvent& event) SConfig::GetInstance().m_SIDevice[device_num] = tempType; + if (GCAdapter::UseAdapter()) + GCAdapter::StartScanThread(); + else + GCAdapter::StopScanThread(); + if (Core::IsRunning()) SerialInterface::ChangeDevice(tempType, device_num); } @@ -557,6 +509,11 @@ void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event) InputConfigDialog m_ConfigFrame(this, *key_plugin, _("GameCube Controller Configuration"), port_num); m_ConfigFrame.ShowModal(); } + else if (SConfig::GetInstance().m_SIDevice[port_num] == SIDEVICE_WIIU_ADAPTER) + { + GCAdapterConfigDiag m_ConfigFramg(this, _("Wii U Gamecube Controller Adapter Configuration"), port_num); + m_ConfigFramg.ShowModal(); + } else { InputConfigDialog m_ConfigFrame(this, *pad_plugin, _("GameCube Controller Configuration"), port_num); @@ -565,10 +522,3 @@ void ControllerConfigDiag::OnGameCubeConfigButton(wxCommandEvent& event) HotkeyManagerEmu::Enable(true); } - -ControllerConfigDiag::~ControllerConfigDiag() -{ -#if defined(__LIBUSB__) || defined (_WIN32) - SI_GCAdapter::SetAdapterCallback(nullptr); -#endif -} diff --git a/Source/Core/DolphinWX/ControllerConfigDiag.h b/Source/Core/DolphinWX/ControllerConfigDiag.h index f679992b54..8646396b2b 100644 --- a/Source/Core/DolphinWX/ControllerConfigDiag.h +++ b/Source/Core/DolphinWX/ControllerConfigDiag.h @@ -10,8 +10,8 @@ #include "Common/SysConf.h" #include "Core/ConfigManager.h" -#include "Core/HW/SI_GCAdapter.h" #include "Core/HW/Wiimote.h" +#include "InputCommon/GCAdapter.h" class InputConfig; class wxButton; @@ -21,7 +21,6 @@ class ControllerConfigDiag : public wxDialog { public: ControllerConfigDiag(wxWindow* const parent); - ~ControllerConfigDiag(); private: void RefreshRealWiimotes(wxCommandEvent& event); @@ -70,23 +69,6 @@ private: event.Skip(); } - void OnGameCubeAdapter(wxCommandEvent& event) - { - SConfig::GetInstance().m_GameCubeAdapter = event.IsChecked(); -#ifdef __LIBUSB__ - if (event.IsChecked()) - SI_GCAdapter::StartScanThread(); - else - SI_GCAdapter::StopScanThread(); -#endif - event.Skip(); - } - void OnAdapterRumble(wxCommandEvent& event) - { - SConfig::GetInstance().m_AdapterRumble = event.IsChecked(); - } - - wxStaticBoxSizer* CreateGamecubeSizer(); wxStaticBoxSizer* CreateWiimoteConfigSizer(); wxStaticBoxSizer* CreateBalanceBoardSizer(); @@ -96,17 +78,14 @@ private: void Cancel(wxCommandEvent& event); void OnGameCubePortChanged(wxCommandEvent& event); void OnGameCubeConfigButton(wxCommandEvent& event); - void ScheduleAdapterUpdate(); - void UpdateAdapter(wxCommandEvent& ev); std::map m_gc_port_choice_ids; std::map m_gc_port_config_ids; - std::array m_gc_pad_type_strs; + std::array m_gc_pad_type_strs; std::map m_wiimote_index_from_ctrl_id; unsigned int m_orig_wiimote_sources[MAX_BBMOTES]; - wxStaticText* m_adapter_status; wxButton* wiimote_configure_bt[MAX_WIIMOTES]; wxButton* gamecube_configure_bt[4]; std::map m_wiimote_index_from_conf_bt_id; diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj b/Source/Core/DolphinWX/DolphinWX.vcxproj index b4818cf162..13882b44a4 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj @@ -58,6 +58,7 @@ + @@ -113,6 +114,7 @@ + @@ -246,4 +248,4 @@ - \ No newline at end of file + diff --git a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters index 87fb5df32a..5534ec41f8 100644 --- a/Source/Core/DolphinWX/DolphinWX.vcxproj.filters +++ b/Source/Core/DolphinWX/DolphinWX.vcxproj.filters @@ -178,6 +178,9 @@ GUI\Config + + GUI\Config + GUI\Config @@ -339,6 +342,9 @@ GUI\Config + + GUI\Config + GUI\Config @@ -369,4 +375,4 @@ - \ No newline at end of file + diff --git a/Source/Core/InputCommon/CMakeLists.txt b/Source/Core/InputCommon/CMakeLists.txt index b200625000..01eef4532c 100644 --- a/Source/Core/InputCommon/CMakeLists.txt +++ b/Source/Core/InputCommon/CMakeLists.txt @@ -3,8 +3,6 @@ set(SRCS ControllerEmu.cpp ControllerInterface/ControllerInterface.cpp ControllerInterface/Device.cpp ControllerInterface/ExpressionParser.cpp) - - set(LIBS common) if(WIN32) @@ -33,10 +31,18 @@ elseif(X11_FOUND) endif() set(LIBS ${LIBS} ${X11_LIBRARIES} ${XINPUT2_LIBRARIES}) elseif(ANDROID) - set(SRCS ${SRCS} - ControllerInterface/Android/Android.cpp) + set(SRCS ${SRCS} + ControllerInterface/Android/Android.cpp) endif() +if(LIBUSB_FOUND) + set(SRCS ${SRCS} GCAdapter.cpp) +elseif(ANDROID) + set(SRCS ${SRCS} GCAdapter_Android.cpp) +else() + set(SRCS ${SRCS} GCAdapter_Null.cpp) +endif(LIBUSB_FOUND) + if(LIBEVDEV_FOUND AND LIBUDEV_FOUND) set(SRCS ${SRCS} ControllerInterface/evdev/evdev.cpp) set(LIBS ${LIBS} ${LIBEVDEV_LIBRARY} ${LIBUDEV_LIBRARY}) diff --git a/Source/Core/Core/HW/SI_GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp similarity index 88% rename from Source/Core/Core/HW/SI_GCAdapter.cpp rename to Source/Core/InputCommon/GCAdapter.cpp index b6b12bcfdb..b5dc395b49 100644 --- a/Source/Core/Core/HW/SI_GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -8,29 +8,24 @@ #include "Common/Flag.h" #include "Common/Thread.h" +#include "Common/Logging/Log.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/CoreTiming.h" #include "Core/HW/SI.h" -#include "Core/HW/SI_GCAdapter.h" #include "Core/HW/SystemTimers.h" + +#include "InputCommon/GCAdapter.h" #include "InputCommon/GCPadStatus.h" -namespace SI_GCAdapter +namespace GCAdapter { -enum ControllerTypes -{ - CONTROLLER_NONE = 0, - CONTROLLER_WIRED = 1, - CONTROLLER_WIRELESS = 2 -}; - static bool CheckDeviceAccess(libusb_device* device); static void AddGCAdapter(libusb_device* device); static bool s_detected = false; static libusb_device_handle* s_handle = nullptr; -static u8 s_controller_type[MAX_SI_CHANNELS] = { CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE, CONTROLLER_NONE }; +static u8 s_controller_type[MAX_SI_CHANNELS] = { ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE }; static u8 s_controller_rumble[4]; static std::mutex s_mutex; @@ -158,13 +153,16 @@ void Init() } else { - if (SConfig::GetInstance().m_GameCubeAdapter) + if (UseAdapter()) StartScanThread(); } } void StartScanThread() { + if (s_adapter_detect_thread_running.IsSet()) + return; + s_adapter_detect_thread_running.Set(true); s_adapter_detect_thread = std::thread(ScanThreadFunc); } @@ -184,7 +182,7 @@ void Setup() for (int i = 0; i < MAX_SI_CHANNELS; i++) { - s_controller_type[i] = CONTROLLER_NONE; + s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; s_controller_rumble[i] = 0; } @@ -334,7 +332,7 @@ void Reset() } for (int i = 0; i < MAX_SI_CHANNELS; i++) - s_controller_type[i] = CONTROLLER_NONE; + s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; s_detected = false; @@ -351,7 +349,7 @@ void Reset() void Input(int chan, GCPadStatus* pad) { - if (!SConfig::GetInstance().m_GameCubeAdapter) + if (!UseAdapter()) return; if (s_handle == nullptr || !s_detected) @@ -371,15 +369,19 @@ void Input(int chan, GCPadStatus* pad) } else { + bool get_origin = false; u8 type = controller_payload_copy[1 + (9 * chan)] >> 4; - if (type != CONTROLLER_NONE && s_controller_type[chan] == CONTROLLER_NONE) + if (type != ControllerTypes::CONTROLLER_NONE && s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE) + { NOTICE_LOG(SERIALINTERFACE, "New device connected to Port %d of Type: %02x", chan + 1, controller_payload_copy[1 + (9 * chan)]); + get_origin = true; + } s_controller_type[chan] = type; - if (s_controller_type[chan] != CONTROLLER_NONE) + memset(pad, 0, sizeof(*pad)); + if (s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE) { - memset(pad, 0, sizeof(*pad)); u8 b1 = controller_payload_copy[1 + (9 * chan) + 1]; u8 b2 = controller_payload_copy[1 + (9 * chan) + 2]; @@ -398,6 +400,8 @@ void Input(int chan, GCPadStatus* pad) if (b2 & (1 << 2)) pad->button |= PAD_TRIGGER_R; if (b2 & (1 << 3)) pad->button |= PAD_TRIGGER_L; + if (get_origin) pad->button |= PAD_GET_ORIGIN; + pad->stickX = controller_payload_copy[1 + (9 * chan) + 3]; pad->stickY = controller_payload_copy[1 + (9 * chan) + 4]; pad->substickX = controller_payload_copy[1 + (9 * chan) + 5]; @@ -405,12 +409,29 @@ void Input(int chan, GCPadStatus* pad) pad->triggerLeft = controller_payload_copy[1 + (9 * chan) + 7]; pad->triggerRight = controller_payload_copy[1 + (9 * chan) + 8]; } + else + { + pad->button = PAD_ERR_STATUS; + } } } +bool DeviceConnected(int chan) +{ + return s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE; +} + +bool UseAdapter() +{ + return SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[1] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[2] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[3] == SIDEVICE_WIIU_ADAPTER; +} + void ResetRumble() { - if (!SConfig::GetInstance().m_GameCubeAdapter) + if (!UseAdapter()) return; if (s_handle == nullptr || !s_detected) return; @@ -427,11 +448,11 @@ void ResetRumble() void Output(int chan, u8 rumble_command) { - if (s_handle == nullptr || !SConfig::GetInstance().m_GameCubeAdapter || !SConfig::GetInstance().m_AdapterRumble) + if (s_handle == nullptr || !UseAdapter() || !SConfig::GetInstance().m_AdapterRumble[chan]) return; // Skip over rumble commands if it has not changed or the controller is wireless - if (rumble_command != s_controller_rumble[chan] && s_controller_type[chan] != CONTROLLER_WIRELESS) + if (rumble_command != s_controller_rumble[chan] && s_controller_type[chan] != ControllerTypes::CONTROLLER_WIRELESS) { s_controller_rumble[chan] = rumble_command; @@ -458,4 +479,4 @@ bool IsDriverDetected() return !s_libusb_driver_not_supported; } -} // end of namespace SI_GCAdapter +} // end of namespace GCAdapter diff --git a/Source/Core/Core/HW/SI_GCAdapter.h b/Source/Core/InputCommon/GCAdapter.h similarity index 70% rename from Source/Core/Core/HW/SI_GCAdapter.h rename to Source/Core/InputCommon/GCAdapter.h index 13deb8b536..5af8f7b915 100644 --- a/Source/Core/Core/HW/SI_GCAdapter.h +++ b/Source/Core/InputCommon/GCAdapter.h @@ -8,9 +8,14 @@ struct GCPadStatus; -namespace SI_GCAdapter +namespace GCAdapter { - +enum ControllerTypes +{ + CONTROLLER_NONE = 0, + CONTROLLER_WIRED = 1, + CONTROLLER_WIRELESS = 2 +}; void Init(); void Reset(); void ResetRumble(); @@ -23,5 +28,7 @@ void Input(int chan, GCPadStatus* pad); void Output(int chan, u8 rumble_command); bool IsDetected(); bool IsDriverDetected(); +bool DeviceConnected(int chan); +bool UseAdapter(); -} // end of namespace SI_GCAdapter +} // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCAdapter_Android.cpp b/Source/Core/InputCommon/GCAdapter_Android.cpp new file mode 100644 index 0000000000..6e638e2a72 --- /dev/null +++ b/Source/Core/InputCommon/GCAdapter_Android.cpp @@ -0,0 +1,353 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include +#include + +#include "Common/Event.h" +#include "Common/Flag.h" +#include "Common/Thread.h" +#include "Common/Logging/Log.h" +#include "Core/ConfigManager.h" +#include "Core/Core.h" +#include "Core/CoreTiming.h" +#include "Core/HW/SI.h" +#include "Core/HW/SystemTimers.h" + +#include "InputCommon/GCAdapter.h" +#include "InputCommon/GCPadStatus.h" + +// Global java_vm class +extern JavaVM* g_java_vm; + +namespace GCAdapter +{ +// Java classes +static jclass s_adapter_class; + +static bool s_detected = false; +static int s_fd = 0; +static u8 s_controller_type[MAX_SI_CHANNELS] = { ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE }; +static u8 s_controller_rumble[4]; + +// Input handling +static std::mutex s_read_mutex; +static u8 s_controller_payload[37]; +static int s_controller_payload_size = 0; + +// Output handling +static std::mutex s_write_mutex; +static u8 s_controller_write_payload[5]; + +// Adapter running thread +static std::thread s_read_adapter_thread; +static Common::Flag s_read_adapter_thread_running; + +static std::thread s_write_adapter_thread; +static Common::Flag s_write_adapter_thread_running; +static Common::Event s_write_happened; + +// Adapter scanning thread +static std::thread s_adapter_detect_thread; +static Common::Flag s_adapter_detect_thread_running; + +static u64 s_last_init = 0; + +static void ScanThreadFunc() +{ + Common::SetCurrentThreadName("GC Adapter Scanning Thread"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started"); + + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); + + jmethodID queryadapter_func = env->GetStaticMethodID(s_adapter_class, "QueryAdapter", "()Z"); + + while (s_adapter_detect_thread_running.IsSet()) + { + if (!s_detected && UseAdapter() && + env->CallStaticBooleanMethod(s_adapter_class, queryadapter_func)) + Setup(); + Common::SleepCurrentThread(1000); + } + g_java_vm->DetachCurrentThread(); + + NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped"); +} + +static void Read() +{ + Common::SetCurrentThreadName("GC Adapter Read Thread"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter read thread started"); + + bool first_read = true; + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); + + jfieldID payload_field = env->GetStaticFieldID(s_adapter_class, "controller_payload", "[B"); + jobject payload_object = env->GetStaticObjectField(s_adapter_class, payload_field); + jbyteArray* java_controller_payload = reinterpret_cast(&payload_object); + + // Get function pointers + jmethodID getfd_func = env->GetStaticMethodID(s_adapter_class, "GetFD", "()I"); + jmethodID input_func = env->GetStaticMethodID(s_adapter_class, "Input", "()I"); + jmethodID openadapter_func = env->GetStaticMethodID(s_adapter_class, "OpenAdapter", "()V"); + + env->CallStaticVoidMethod(s_adapter_class, openadapter_func); + + // Reset rumble once on initial reading + ResetRumble(); + + while (s_read_adapter_thread_running.IsSet()) + { + s_controller_payload_size = env->CallStaticIntMethod(s_adapter_class, input_func); + + jbyte* java_data = env->GetByteArrayElements(*java_controller_payload, nullptr); + { + std::lock_guard lk(s_read_mutex); + memcpy(s_controller_payload, java_data, 0x37); + } + env->ReleaseByteArrayElements(*java_controller_payload, java_data, 0); + + if (first_read) + { + first_read = false; + s_fd = env->CallStaticIntMethod(s_adapter_class, getfd_func); + } + + Common::YieldCPU(); + } + + g_java_vm->DetachCurrentThread(); + + NOTICE_LOG(SERIALINTERFACE, "GC Adapter read thread stopped"); +} + +static void Write() +{ + Common::SetCurrentThreadName("GC Adapter Write Thread"); + NOTICE_LOG(SERIALINTERFACE, "GC Adapter write thread started"); + + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); + jmethodID output_func = env->GetStaticMethodID(s_adapter_class, "Output", "([B)I"); + + while (s_write_adapter_thread_running.IsSet()) + { + jbyteArray jrumble_array = env->NewByteArray(5); + jbyte* jrumble = env->GetByteArrayElements(jrumble_array, NULL); + + s_write_happened.Wait(); + { + std::lock_guard lk(s_write_mutex); + memcpy(jrumble, s_controller_write_payload, 5); + } + + env->ReleaseByteArrayElements(jrumble_array, jrumble, 0); + int size = env->CallStaticIntMethod(s_adapter_class, output_func, jrumble_array); + // Netplay sends invalid data which results in size = 0x00. Ignore it. + if (size != 0x05 && size != 0x00) + { + ERROR_LOG(SERIALINTERFACE, "error writing rumble (size: %d)", size); + Reset(); + } + + Common::YieldCPU(); + } + + g_java_vm->DetachCurrentThread(); + + NOTICE_LOG(SERIALINTERFACE, "GC Adapter write thread stopped"); +} + +void Init() +{ + if (s_fd) + return; + + if (Core::GetState() != Core::CORE_UNINITIALIZED) + { + if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond()) + return; + + s_last_init = CoreTiming::GetTicks(); + } + + JNIEnv* env; + g_java_vm->AttachCurrentThread(&env, NULL); + + jclass adapter_class = env->FindClass("org/dolphinemu/dolphinemu/utils/Java_GCAdapter"); + s_adapter_class = reinterpret_cast(env->NewGlobalRef(adapter_class)); + + if (UseAdapter()) + StartScanThread(); +} + +void Setup() +{ + s_read_adapter_thread_running.Set(true); + s_read_adapter_thread = std::thread(Read); + + s_write_adapter_thread_running.Set(true); + s_write_adapter_thread = std::thread(Write); + + s_detected = true; +} + +void Reset() +{ + if (!s_detected) + return; + + if (s_read_adapter_thread_running.TestAndClear()) + s_read_adapter_thread.join(); + + if (s_write_adapter_thread_running.TestAndClear()) + { + s_write_happened.Set(); // Kick the waiting event + s_write_adapter_thread.join(); + } + + for (int i = 0; i < MAX_SI_CHANNELS; i++) + s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; + + s_detected = false; + s_fd = 0; + NOTICE_LOG(SERIALINTERFACE, "GC Adapter detached"); +} + +void Shutdown() +{ + StopScanThread(); + Reset(); +} + +void StartScanThread() +{ + if (s_adapter_detect_thread_running.IsSet()) + return; + + s_adapter_detect_thread_running.Set(true); + s_adapter_detect_thread = std::thread(ScanThreadFunc); +} + +void StopScanThread() +{ + if (s_adapter_detect_thread_running.TestAndClear()) + s_adapter_detect_thread.join(); +} + +void Input(int chan, GCPadStatus* pad) +{ + if (!UseAdapter() || !s_detected || !s_fd) + return; + + u8 controller_payload_copy[37]; + + { + std::lock_guard lk(s_read_mutex); + std::copy(std::begin(s_controller_payload), std::end(s_controller_payload), std::begin(controller_payload_copy)); + } + + if (s_controller_payload_size != sizeof(controller_payload_copy)) + { + ERROR_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", s_controller_payload_size, controller_payload_copy[0]); + Reset(); + } + else + { + bool get_origin = false; + u8 type = controller_payload_copy[1 + (9 * chan)] >> 4; + if (type != ControllerTypes::CONTROLLER_NONE && s_controller_type[chan] == ControllerTypes::CONTROLLER_NONE) + { + ERROR_LOG(SERIALINTERFACE, "New device connected to Port %d of Type: %02x", chan + 1, controller_payload_copy[1 + (9 * chan)]); + get_origin = true; + } + + s_controller_type[chan] = type; + + memset(pad, 0, sizeof(*pad)); + if (s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE) + { + u8 b1 = controller_payload_copy[1 + (9 * chan) + 1]; + u8 b2 = controller_payload_copy[1 + (9 * chan) + 2]; + + if (b1 & (1 << 0)) pad->button |= PAD_BUTTON_A; + if (b1 & (1 << 1)) pad->button |= PAD_BUTTON_B; + if (b1 & (1 << 2)) pad->button |= PAD_BUTTON_X; + if (b1 & (1 << 3)) pad->button |= PAD_BUTTON_Y; + + if (b1 & (1 << 4)) pad->button |= PAD_BUTTON_LEFT; + if (b1 & (1 << 5)) pad->button |= PAD_BUTTON_RIGHT; + if (b1 & (1 << 6)) pad->button |= PAD_BUTTON_DOWN; + if (b1 & (1 << 7)) pad->button |= PAD_BUTTON_UP; + + if (b2 & (1 << 0)) pad->button |= PAD_BUTTON_START; + if (b2 & (1 << 1)) pad->button |= PAD_TRIGGER_Z; + if (b2 & (1 << 2)) pad->button |= PAD_TRIGGER_R; + if (b2 & (1 << 3)) pad->button |= PAD_TRIGGER_L; + + if (get_origin) pad->button |= PAD_GET_ORIGIN; + + pad->stickX = controller_payload_copy[1 + (9 * chan) + 3]; + pad->stickY = controller_payload_copy[1 + (9 * chan) + 4]; + pad->substickX = controller_payload_copy[1 + (9 * chan) + 5]; + pad->substickY = controller_payload_copy[1 + (9 * chan) + 6]; + pad->triggerLeft = controller_payload_copy[1 + (9 * chan) + 7]; + pad->triggerRight = controller_payload_copy[1 + (9 * chan) + 8]; + } + else + { + pad->button = PAD_ERR_STATUS; + } + } +} + +void Output(int chan, u8 rumble_command) +{ + if (!UseAdapter() || !s_detected || !s_fd) + return; + + // Skip over rumble commands if it has not changed or the controller is wireless + if (rumble_command != s_controller_rumble[chan] && s_controller_type[chan] != ControllerTypes::CONTROLLER_WIRELESS) + { + s_controller_rumble[chan] = rumble_command; + unsigned char rumble[5] = { 0x11, s_controller_rumble[0], s_controller_rumble[1], s_controller_rumble[2], s_controller_rumble[3] }; + { + std::lock_guard lk(s_write_mutex); + memcpy(s_controller_write_payload, rumble, 5); + } + s_write_happened.Set(); + } +} + +bool IsDetected() { return s_detected; } +bool IsDriverDetected() { return true; } +bool DeviceConnected(int chan) +{ + return s_controller_type[chan] != ControllerTypes::CONTROLLER_NONE; +} + +bool UseAdapter() +{ + return SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[1] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[2] == SIDEVICE_WIIU_ADAPTER || + SConfig::GetInstance().m_SIDevice[3] == SIDEVICE_WIIU_ADAPTER; +} + +void ResetRumble() +{ + unsigned char rumble[5] = {0x11, 0, 0, 0, 0}; + { + std::lock_guard lk(s_read_mutex); + memcpy(s_controller_write_payload, rumble, 5); + } + s_write_happened.Set(); +} + +void SetAdapterCallback(std::function func) { } + +} // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCAdapter_Null.cpp b/Source/Core/InputCommon/GCAdapter_Null.cpp new file mode 100644 index 0000000000..0936eb33f1 --- /dev/null +++ b/Source/Core/InputCommon/GCAdapter_Null.cpp @@ -0,0 +1,23 @@ +// Copyright 2014 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "InputCommon/GCAdapter.h" +namespace GCAdapter +{ +void Init() {} +void Reset() {} +void ResetRumble() {} +void Setup() {} +void Shutdown() {} +void SetAdapterCallback(std::function func) {} +void StartScanThread() {} +void StopScanThread() {} +void Input(int chan, GCPadStatus* pad) {} +void Output(int chan, u8 rumble_command) {} +bool IsDetected() { return false; } +bool IsDriverDetected() { return false; } +bool DeviceConnected(int chan) { return false; } +bool UseAdapter() { return false; } + +} // end of namespace GCAdapter diff --git a/Source/Core/InputCommon/GCPadStatus.h b/Source/Core/InputCommon/GCPadStatus.h index d6bb972de1..deecb30523 100644 --- a/Source/Core/InputCommon/GCPadStatus.h +++ b/Source/Core/InputCommon/GCPadStatus.h @@ -17,6 +17,8 @@ enum PadError enum { PAD_USE_ORIGIN = 0x0080, + PAD_GET_ORIGIN = 0x2000, + PAD_ERR_STATUS = 0x8000, }; enum PadButton diff --git a/Source/Core/InputCommon/InputCommon.vcxproj b/Source/Core/InputCommon/InputCommon.vcxproj index 347c06e770..3e63243949 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj +++ b/Source/Core/InputCommon/InputCommon.vcxproj @@ -52,6 +52,13 @@ + + + 4200;%(DisableSpecificWarnings) + @@ -66,6 +73,7 @@ + @@ -80,4 +88,4 @@ - \ No newline at end of file + diff --git a/Source/Core/InputCommon/InputCommon.vcxproj.filters b/Source/Core/InputCommon/InputCommon.vcxproj.filters index 3c16ad5f26..6a63852303 100644 --- a/Source/Core/InputCommon/InputCommon.vcxproj.filters +++ b/Source/Core/InputCommon/InputCommon.vcxproj.filters @@ -16,6 +16,7 @@ + ControllerInterface\DInput @@ -47,6 +48,7 @@ + @@ -83,4 +85,4 @@ - \ No newline at end of file + diff --git a/Source/Core/UICommon/UICommon.cpp b/Source/Core/UICommon/UICommon.cpp index 5ba825f5e2..10e00584a2 100644 --- a/Source/Core/UICommon/UICommon.cpp +++ b/Source/Core/UICommon/UICommon.cpp @@ -11,11 +11,10 @@ #include "Common/Logging/LogManager.h" #include "Core/ConfigManager.h" -#if defined(__LIBUSB__) || defined (_WIN32) -#include "Core/HW/SI_GCAdapter.h" -#endif #include "Core/HW/Wiimote.h" +#include "InputCommon/GCAdapter.h" + #include "UICommon/UICommon.h" #include "VideoCommon/VideoBackendBase.h" @@ -29,9 +28,7 @@ void Init() SConfig::Init(); VideoBackend::PopulateList(); WiimoteReal::LoadSettings(); -#if defined(__LIBUSB__) || defined (_WIN32) - SI_GCAdapter::Init(); -#endif + GCAdapter::Init(); VideoBackend::ActivateBackend(SConfig::GetInstance().m_strVideoBackend); SetEnableAlert(SConfig::GetInstance().bUsePanicHandlers); @@ -39,9 +36,7 @@ void Init() void Shutdown() { -#if defined(__LIBUSB__) || defined (_WIN32) - SI_GCAdapter::Shutdown(); -#endif + GCAdapter::Shutdown(); WiimoteReal::Shutdown(); VideoBackend::ClearList(); SConfig::Shutdown();