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)))