Added Dance Mat support for the Family Trainer/Active Life series.

Select the dance mat via Configure > Gamecube > Port 1 > Dance Mat

The dance mat is mapped to the GC Pad:

D-Pad Up = Blue Arrow Up
D-Pad Down = Blue Arrow Down
D-Pad Left = Blue Arrow Left
D-Pad Right = Blue Square
Y Button = Orange Arrow Up
A Button = Orange Arrow Down
X Button = Orange Arrow Right
B Button = Oranage Square
This commit is contained in:
skidau 2013-04-30 23:36:46 +10:00
parent e5fdd301a9
commit e70a277af2
9 changed files with 406 additions and 3 deletions

View file

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

View file

@ -298,6 +298,7 @@
<ClCompile Include="Src\HW\SI.cpp" />
<ClCompile Include="Src\HW\SI_Device.cpp" />
<ClCompile Include="Src\HW\SI_DeviceAMBaseboard.cpp" />
<ClCompile Include="Src\HW\SI_DeviceDanceMat.cpp" />
<ClCompile Include="Src\HW\SI_DeviceGBA.cpp" />
<ClCompile Include="Src\HW\SI_DeviceGCController.cpp" />
<ClCompile Include="Src\HW\SI_DeviceGCSteeringWheel.cpp" />
@ -498,6 +499,7 @@
<ClInclude Include="Src\HW\SI.h" />
<ClInclude Include="Src\HW\SI_Device.h" />
<ClInclude Include="Src\HW\SI_DeviceAMBaseboard.h" />
<ClInclude Include="Src\HW\SI_DeviceDanceMat.h" />
<ClInclude Include="Src\HW\SI_DeviceGBA.h" />
<ClInclude Include="Src\HW\SI_DeviceGCController.h" />
<ClInclude Include="Src\HW\SI_DeviceGCSteeringWheel.h" />

View file

@ -289,6 +289,9 @@
<ClCompile Include="Src\HW\SI_DeviceGCSteeringWheel.cpp">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClCompile>
<ClCompile Include="Src\HW\SI_DeviceDanceMat.cpp">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClCompile>
<ClCompile Include="Src\HW\VideoInterface.cpp">
<Filter>HW %28Flipper/Hollywood%29\VI - Video Interface</Filter>
</ClCompile>
@ -810,6 +813,9 @@
<ClInclude Include="Src\HW\SI_DeviceGCSteeringWheel.h">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClInclude>
<ClInclude Include="Src\HW\SI_DeviceDanceMat.h">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClInclude>
<ClInclude Include="Src\HW\SI.h">
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
</ClInclude>

View file

@ -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;

View file

@ -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
};

View file

@ -0,0 +1,264 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include <stdio.h>
#include <stdlib.h>
#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<EBufferCommands>(_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<u8*>(&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<u8*>(&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);
}

View file

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

View file

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

View file

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