diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 0fed2e0b8a..d0ad3c615d 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -111,6 +111,7 @@ set(SRCS Src/ActionReplay.cpp Src/HW/SI.cpp Src/HW/SI_DeviceAMBaseboard.cpp Src/HW/SI_Device.cpp + Src/HW/SI_DeviceDanceMat.cpp Src/HW/SI_DeviceGBA.cpp Src/HW/SI_DeviceGCController.cpp Src/HW/SI_DeviceGCSteeringWheel.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 5d0d3b2754..a191d86282 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -298,6 +298,7 @@ + @@ -498,6 +499,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index c38d68c303..75c592a685 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -289,6 +289,9 @@ HW %28Flipper/Hollywood%29\SI - Serial Interface + + HW %28Flipper/Hollywood%29\SI - Serial Interface + HW %28Flipper/Hollywood%29\VI - Video Interface @@ -810,6 +813,9 @@ HW %28Flipper/Hollywood%29\SI - Serial Interface + + HW %28Flipper/Hollywood%29\SI - Serial Interface + HW %28Flipper/Hollywood%29\SI - Serial Interface diff --git a/Source/Core/Core/Src/HW/SI_Device.cpp b/Source/Core/Core/Src/HW/SI_Device.cpp index baa144c83d..e9674bcab6 100644 --- a/Source/Core/Core/Src/HW/SI_Device.cpp +++ b/Source/Core/Core/Src/HW/SI_Device.cpp @@ -5,6 +5,7 @@ #include "SI_Device.h" #include "SI_DeviceGCController.h" #include "SI_DeviceGCSteeringWheel.h" +#include "SI_DeviceDanceMat.h" #include "SI_DeviceGBA.h" #include "SI_DeviceAMBaseboard.h" @@ -64,6 +65,10 @@ ISIDevice* SIDevice_Create(const SIDevices device, const int port_number) return new CSIDevice_GCController(device, port_number); break; + case SIDEVICE_DANCEMAT: + return new CSIDevice_DanceMat(device, port_number); + break; + case SIDEVICE_GC_STEERING: return new CSIDevice_GCSteeringWheel(device, port_number); break; diff --git a/Source/Core/Core/Src/HW/SI_Device.h b/Source/Core/Core/Src/HW/SI_Device.h index bf3e1fc506..62614656c7 100644 --- a/Source/Core/Core/Src/HW/SI_Device.h +++ b/Source/Core/Core/Src/HW/SI_Device.h @@ -34,6 +34,7 @@ enum TSIDevices SI_GC_CONTROLLER = (SI_TYPE_GC | SI_GC_STANDARD), SI_GC_KEYBOARD = (SI_TYPE_GC | 0x00200000), SI_GC_STEERING = SI_TYPE_GC, // (shuffle2)I think the "chainsaw" is the same (Or else it's just standard) + SI_DANCEMAT = (SI_TYPE_GC | SI_GC_STANDARD | 0x00000300), SI_AM_BASEBOARD = 0x10110800 // gets ORd with dipswitch state }; @@ -49,6 +50,7 @@ enum SIDevices SIDEVICE_GC_CONTROLLER, SIDEVICE_GC_KEYBOARD, SIDEVICE_GC_STEERING, + SIDEVICE_DANCEMAT, SIDEVICE_GC_TARUKONGA, SIDEVICE_AM_BASEBOARD }; diff --git a/Source/Core/Core/Src/HW/SI_DeviceDanceMat.cpp b/Source/Core/Core/Src/HW/SI_DeviceDanceMat.cpp new file mode 100644 index 0000000000..30237286e6 --- /dev/null +++ b/Source/Core/Core/Src/HW/SI_DeviceDanceMat.cpp @@ -0,0 +1,264 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "SI.h" +#include "SI_Device.h" +#include "SI_DeviceDanceMat.h" + +#include "EXI_Device.h" +#include "EXI_DeviceMic.h" + +#include "GCPad.h" + +#include "../Movie.h" + +#include "../CoreTiming.h" +#include "SystemTimers.h" +#include "ProcessorInterface.h" +#include "../Core.h" + +// --- Dance mat gamecube controller --- +CSIDevice_DanceMat::CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber) + : ISIDevice(device, _iDeviceNumber) + , m_TButtonComboStart(0) + , m_TButtonCombo(0) + , m_LastButtonCombo(COMBO_NONE) +{ + memset(&m_Origin, 0, sizeof(SOrigin)); + m_Origin.uCommand = CMD_ORIGIN; + m_Origin.uOriginStickX = 0x80; // center + m_Origin.uOriginStickY = 0x80; + m_Origin.uSubStickStickX = 0x80; + m_Origin.uSubStickStickY = 0x80; + m_Origin.uTrigger_L = 0x00; + m_Origin.uTrigger_R = 0x00; + + // Dunno if we need to do this, game/lib should set it? + m_Mode = 0x03; +} + +int CSIDevice_DanceMat::RunBuffer(u8* _pBuffer, int _iLength) +{ + // For debug logging only + ISIDevice::RunBuffer(_pBuffer, _iLength); + + // Read the command + EBufferCommands command = static_cast(_pBuffer[3]); + + // Handle it + switch (command) + { + case CMD_RESET: + *(u32*)&_pBuffer[0] = SI_DANCEMAT; + 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[0 + i] = (high >> (i * 8)) & 0xff; + _pBuffer[4 + i] = (low >> (i * 8)) & 0xff; + } + } + break; + + case CMD_ORIGIN: + { + INFO_LOG(SERIALINTERFACE, "PAD - Get Origin"); + 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"); + 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; +} + + +// GetData + +// Return true on new data (max 7 Bytes and 6 bits ;) +// [00?SYXBA] [1LRZUDRL] [x] [y] [cx] [cy] [l] [r] +// |\_ ERR_LATCH (error latched - check SISR) +// |_ ERR_STATUS (error on last GetData or SendCmd?) +bool CSIDevice_DanceMat::GetData(u32& _Hi, u32& _Low) +{ + SPADStatus PadStatus; + memset(&PadStatus, 0, sizeof(PadStatus)); + + Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus); + Movie::CallInputManip(&PadStatus, ISIDevice::m_iDeviceNumber); + + u32 netValues[2]; + if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, PadStatus, netValues)) + { + _Hi = netValues[0]; // first 4 bytes + _Low = netValues[1]; // last 4 bytes + return true; + } + + Movie::SetPolledDevice(); + + 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); + } + + // Map the dpad to the blue arrows, the buttons to the orange arrows + // Z = + button, Start = - button + u16 map = 0; + if (PadStatus.button & PAD_BUTTON_UP) + map |= 0x1000; + if (PadStatus.button & PAD_BUTTON_DOWN) + map |= 0x2; + if (PadStatus.button & PAD_BUTTON_LEFT) + map |= 0x8; + if (PadStatus.button & PAD_BUTTON_RIGHT) + map |= 0x4; + if (PadStatus.button & PAD_BUTTON_Y) + map |= 0x200; + if (PadStatus.button & PAD_BUTTON_A) + map |= 0x10; + if (PadStatus.button & PAD_BUTTON_B) + map |= 0x100; + if (PadStatus.button & PAD_BUTTON_X) + map |= 0x800; + if (PadStatus.button & PAD_TRIGGER_Z) + map |= 0x400; + if (PadStatus.button & PAD_BUTTON_START) + map |= 0x1; + + _Hi = (u32)(map << 16) | 0x8080; + + // Low bits are packed differently per mode + if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7) + { + _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.substickY) << 16); // All 8 bits + _Low |= (u32)((u8)(PadStatus.substickX) << 24); // All 8 bits + } + else if (m_Mode == 1) + { + _Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits + _Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits + _Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits + _Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits + _Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits + } + else if (m_Mode == 2) + { + // Identifies the dance mat + _Low = 0x8080ffff; + } + else if (m_Mode == 3) + { + // Analog A/B are always 0 + _Low = (u8)PadStatus.triggerRight; // All 8 bits + _Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits + } + else if (m_Mode == 4) + { + _Low = (u8)(PadStatus.analogB); // All 8 bits + _Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits + // triggerLeft/Right are always 0 + _Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits + _Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits + } + return true; +} + + +// SendCommand +void CSIDevice_DanceMat::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_GetPadNum(ISIDevice::m_iDeviceNumber); + + if (numPAD < 4) + Pad::Rumble(numPAD, uType, uStrength); + + 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; + } +} + +// Savestate support +void CSIDevice_DanceMat::DoState(PointerWrap& p) +{ + p.Do(m_Origin); + p.Do(m_Mode); + p.Do(m_TButtonComboStart); + p.Do(m_TButtonCombo); + p.Do(m_LastButtonCombo); +} diff --git a/Source/Core/Core/Src/HW/SI_DeviceDanceMat.h b/Source/Core/Core/Src/HW/SI_DeviceDanceMat.h new file mode 100644 index 0000000000..b30c107847 --- /dev/null +++ b/Source/Core/Core/Src/HW/SI_DeviceDanceMat.h @@ -0,0 +1,105 @@ +// Copyright 2013 Dolphin Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#ifndef _SI_DEVICEDANCEMAT_H +#define _SI_DEVICEDANCEMAT_H + +#include "SI_Device.h" +#include "GCPadStatus.h" + + +// standard gamecube controller +class CSIDevice_DanceMat : public ISIDevice +{ +private: + + // Commands + enum EBufferCommands + { + CMD_RESET = 0x00, + CMD_DIRECT = 0x40, + CMD_ORIGIN = 0x41, + CMD_RECALIBRATE = 0x42, + }; + + struct SOrigin + { + u8 uCommand;// Maybe should be button bits? + u8 unk_1; // ..and this would be the other half + u8 uOriginStickX; + u8 uOriginStickY; + u8 uSubStickStickX; + u8 uSubStickStickY; + u8 uTrigger_L; + u8 uTrigger_R; + u8 unk_4; + u8 unk_5; + u8 unk_6; + u8 unk_7; + }; + + enum EDirectCommands + { + CMD_WRITE = 0x40 + }; + + union UCommand + { + u32 Hex; + struct + { + u32 Parameter1 : 8; + u32 Parameter2 : 8; + u32 Command : 8; + u32 : 8; + }; + UCommand() {Hex = 0;} + UCommand(u32 _iValue) {Hex = _iValue;} + }; + + enum EButtonCombo + { + COMBO_NONE = 0, + COMBO_ORIGIN, + COMBO_RESET + }; + + // struct to compare input against + // Set on connection and (standard pad only) on button combo + SOrigin m_Origin; + + // PADAnalogMode + u8 m_Mode; + + // Timer to track special button combos: + // y, X, start for 3 seconds updates origin with current status + // Technically, the above is only on standard pad, wavebird does not support it for example + // b, x, start for 3 seconds triggers reset (PI reset button interrupt) + u64 m_TButtonComboStart, m_TButtonCombo; + // Type of button combo from the last/current poll + EButtonCombo m_LastButtonCombo; + +public: + + // Constructor + CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber); + + // Run the SI Buffer + virtual int RunBuffer(u8* _pBuffer, int _iLength); + + // Send and Receive pad input from network + static bool NetPlay_GetInput(u8 numPAD, SPADStatus status, u32 *PADStatus); + static u8 NetPlay_GetPadNum(u8 numPAD); + + // Return true on new data + virtual bool GetData(u32& _Hi, u32& _Low); + + // Send a command directly + virtual void SendCommand(u32 _Cmd, u8 _Poll); + + // Savestate support + virtual void DoState(PointerWrap& p); +}; + +#endif diff --git a/Source/Core/Core/Src/NetPlay.cpp b/Source/Core/Core/Src/NetPlay.cpp index 96c4a69f98..7f4b838ffc 100644 --- a/Source/Core/Core/Src/NetPlay.cpp +++ b/Source/Core/Core/Src/NetPlay.cpp @@ -10,6 +10,7 @@ // for gcpad #include "HW/SI_DeviceGCController.h" #include "HW/SI_DeviceGCSteeringWheel.h" +#include "HW/SI_DeviceDanceMat.h" // for gctime #include "HW/EXI_DeviceIPL.h" // for wiimote/ OSD messages @@ -299,6 +300,11 @@ bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus); } +bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus) +{ + return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus); +} + // called from ---CPU--- thread // so all players' games get the same time u32 CEXIIPL::NetPlay_GetGCTime() @@ -328,6 +334,11 @@ u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD) return CSIDevice_GCController::NetPlay_GetPadNum(numPAD); } +u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD) +{ + return CSIDevice_GCController::NetPlay_GetPadNum(numPAD); +} + // called from ---CPU--- thread // wiimote update / used for frame counting //void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number) diff --git a/Source/Core/DolphinWX/Src/ConfigMain.cpp b/Source/Core/DolphinWX/Src/ConfigMain.cpp index edbc45a50d..4ae51d78a1 100644 --- a/Source/Core/DolphinWX/Src/ConfigMain.cpp +++ b/Source/Core/DolphinWX/Src/ConfigMain.cpp @@ -87,6 +87,7 @@ static const wxLanguage langIds[] = #define SIDEV_STDCONT_STR _trans("Standard Controller") #define SIDEV_STEERING_STR _trans("Steering Wheel") +#define SIDEV_DANCEMAT_STR _trans("Dance Mat") #define SIDEV_BONGO_STR _trans("TaruKonga (Bongos)") #define SIDEV_GBA_STR "GBA" #define SIDEV_AM_BB_STR _trans("AM-Baseboard") @@ -388,6 +389,7 @@ void CConfigMain::InitializeGUIValues() SIDevices.Add(_(DEV_NONE_STR)); SIDevices.Add(_(SIDEV_STDCONT_STR)); SIDevices.Add(_(SIDEV_STEERING_STR)); + SIDevices.Add(_(SIDEV_DANCEMAT_STR)); SIDevices.Add(_(SIDEV_BONGO_STR)); SIDevices.Add(_(SIDEV_GBA_STR)); SIDevices.Add(_(SIDEV_AM_BB_STR)); @@ -443,15 +445,18 @@ void CConfigMain::InitializeGUIValues() case SIDEVICE_GC_STEERING: GCSIDevice[i]->SetStringSelection(SIDevices[2]); break; - case SIDEVICE_GC_TARUKONGA: + case SIDEVICE_DANCEMAT: GCSIDevice[i]->SetStringSelection(SIDevices[3]); break; - case SIDEVICE_GC_GBA: + case SIDEVICE_GC_TARUKONGA: GCSIDevice[i]->SetStringSelection(SIDevices[4]); break; - case SIDEVICE_AM_BASEBOARD: + case SIDEVICE_GC_GBA: GCSIDevice[i]->SetStringSelection(SIDevices[5]); break; + case SIDEVICE_AM_BASEBOARD: + GCSIDevice[i]->SetStringSelection(SIDevices[6]); + break; default: GCSIDevice[i]->SetStringSelection(SIDevices[0]); break; @@ -1103,6 +1108,8 @@ void CConfigMain::ChooseSIDevice(wxString deviceName, int deviceNum) tempType = SIDEVICE_GC_CONTROLLER; else if (!deviceName.compare(WXSTR_TRANS(SIDEV_STEERING_STR))) tempType = SIDEVICE_GC_STEERING; + else if (!deviceName.compare(WXSTR_TRANS(SIDEV_DANCEMAT_STR))) + tempType = SIDEVICE_DANCEMAT; else if (!deviceName.compare(WXSTR_TRANS(SIDEV_BONGO_STR))) tempType = SIDEVICE_GC_TARUKONGA; else if (!deviceName.compare(wxT(SIDEV_GBA_STR)))