mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 13:47:57 +03:00

Some checks failed
Build macOS / build_macos (push) Has been cancelled
Build Android / build_android (apk) (push) Has been cancelled
Build Android / build_android (libretro) (push) Has been cancelled
Build Linux ARM32 / build_linux_arm32 (push) Has been cancelled
Build Linux ARM64 / build_linux_arm64 (push) Has been cancelled
Build Windows Psf / build_windows_psf (off, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows Psf / build_windows_psf (on, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows / build_windows (x86_32, Visual Studio 16 2019, installer32.nsi, win32_msvc2019, Win32) (push) Has been cancelled
Build Windows / build_windows (x86_64, Visual Studio 16 2019, installer64.nsi, win64_msvc2019_64, x64) (push) Has been cancelled
Check Format / run_clangformat (push) Has been cancelled
Build iOS / build_ios (push) Has been cancelled
Build JavaScript / build_js (push) Has been cancelled
Build Linux / build_linux (push) Has been cancelled
786 lines
22 KiB
C++
786 lines
22 KiB
C++
#include <cstring>
|
|
#include "Iop_NamcoSys147.h"
|
|
#include "Log.h"
|
|
#include "StdStreamUtils.h"
|
|
#include "PathUtils.h"
|
|
#include "AppConfig.h"
|
|
#include "PS2VM_Preferences.h"
|
|
|
|
using namespace Iop;
|
|
using namespace Iop::Namco;
|
|
|
|
#define LOG_NAME ("iop_namco_sys147")
|
|
|
|
//Switch IDs for games
|
|
//--------------------
|
|
|
|
//Animal Kaiser
|
|
//-------------
|
|
// 108 - Test
|
|
// 109 - Enter
|
|
// 110 - Up
|
|
// 111 - Down
|
|
// 114 - Service
|
|
// 116 - 1P Left
|
|
// 117 - 1P Right
|
|
// 118 - 2P Right
|
|
// 119 - 2P Left
|
|
|
|
//Pac-Man Arcade Party
|
|
//--------------------
|
|
// Note: Game seems to be reading from SIO2
|
|
// 84 - Test
|
|
// 86 - Up
|
|
// 87 - Down
|
|
// 88 - Enter
|
|
|
|
CSys147::CSys147(CSifMan& sifMan, const std::string& gameId)
|
|
: m_gameId(gameId)
|
|
{
|
|
m_module000 = CSifModuleAdapter(std::bind(&CSys147::Invoke000, this,
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
|
m_module001 = CSifModuleAdapter(std::bind(&CSys147::Invoke001, this,
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
|
m_module002 = CSifModuleAdapter(std::bind(&CSys147::Invoke002, this,
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
|
m_module003 = CSifModuleAdapter(std::bind(&CSys147::Invoke003, this,
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
|
m_module200 = CSifModuleAdapter(std::bind(&CSys147::Invoke200, this,
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
|
m_module201 = CSifModuleAdapter(std::bind(&CSys147::Invoke201, this,
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
|
m_module99 = CSifModuleAdapter(std::bind(&CSys147::Invoke99, this,
|
|
std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6));
|
|
|
|
sifMan.RegisterModule(MODULE_ID_000, &m_module000);
|
|
sifMan.RegisterModule(MODULE_ID_001, &m_module001);
|
|
sifMan.RegisterModule(MODULE_ID_002, &m_module002);
|
|
sifMan.RegisterModule(MODULE_ID_003, &m_module003);
|
|
sifMan.RegisterModule(MODULE_ID_200, &m_module200);
|
|
sifMan.RegisterModule(MODULE_ID_201, &m_module201);
|
|
sifMan.RegisterModule(MODULE_ID_99, &m_module99);
|
|
|
|
if(CAppConfig::GetInstance().GetPreferenceBoolean(PREF_PS2_ARCADE_IO_SERVER_ENABLED))
|
|
{
|
|
fs::path logPath = CAppConfig::GetInstance().GetBasePath() / "arcade_io_server.log";
|
|
uint16 port = CAppConfig::GetInstance().GetPreferenceInteger(PREF_PS2_ARCADE_IO_SERVER_PORT);
|
|
m_ioServer = std::make_unique<Framework::CHttpServer>(port, std::bind(&CSys147::HandleIoServerRequest, this, std::placeholders::_1), logPath);
|
|
}
|
|
}
|
|
|
|
std::string CSys147::GetId() const
|
|
{
|
|
return "sys147";
|
|
}
|
|
|
|
std::string CSys147::GetFunctionName(unsigned int functionId) const
|
|
{
|
|
return "unknown";
|
|
}
|
|
|
|
void CSys147::SetIoMode(IO_MODE ioMode)
|
|
{
|
|
m_ioMode = ioMode;
|
|
}
|
|
|
|
void CSys147::SetButton(unsigned int switchIndex, unsigned int padNumber, PS2::CControllerInfo::BUTTON button)
|
|
{
|
|
m_switchBindings[{padNumber, button}] = switchIndex;
|
|
}
|
|
|
|
void CSys147::SetButtonState(unsigned int padNumber, PS2::CControllerInfo::BUTTON button, bool pressed, uint8* ram)
|
|
{
|
|
const auto& binding = m_switchBindings.find({padNumber, button});
|
|
if(binding != std::end(m_switchBindings))
|
|
{
|
|
m_switchStates[binding->second] = pressed ? 0xFF : 0x00;
|
|
}
|
|
|
|
if(m_ioMode == IO_MODE::AI)
|
|
{
|
|
//Player Switches
|
|
//4 nibbles, one for each player
|
|
//In one nibble:
|
|
//Bit 0 - Up
|
|
//Bit 1 - Down
|
|
//Bit 2 - Right
|
|
//Bit 3 - Left
|
|
|
|
//System Switches
|
|
//Bit 0 - Select Down
|
|
//Bit 1 - Select Up
|
|
//Bit 2 - Enter
|
|
//Bit 3 - Test
|
|
//Bit 5 - Service
|
|
//Bit 8 - P4 Enter
|
|
//Bit 9 - P3 Enter
|
|
//Bit 10 - P2 Enter
|
|
//Bit 11 - P1 Enter
|
|
uint16 systemSwitchMask = 0;
|
|
uint16 playerSwitchMask = 0;
|
|
if(padNumber == 0)
|
|
{
|
|
switch(button)
|
|
{
|
|
case PS2::CControllerInfo::L1:
|
|
systemSwitchMask = 0x0008; //Test Button
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_UP:
|
|
systemSwitchMask = 0x0002; //Select Up
|
|
playerSwitchMask = 0x1000; //P1 Up
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_DOWN:
|
|
systemSwitchMask = 0x0001; //Select Down
|
|
playerSwitchMask = 0x2000; //P1 Down
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_LEFT:
|
|
playerSwitchMask = 0x8000; //P1 Left
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_RIGHT:
|
|
playerSwitchMask = 0x4000; //P1 Right
|
|
break;
|
|
case PS2::CControllerInfo::CROSS:
|
|
systemSwitchMask = 0x0804; //P1 Start + Enter
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if(padNumber == 1)
|
|
{
|
|
switch(button)
|
|
{
|
|
case PS2::CControllerInfo::DPAD_UP:
|
|
playerSwitchMask = 0x0010; //P2 Up
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_DOWN:
|
|
playerSwitchMask = 0x0020; //P2 Down
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_LEFT:
|
|
playerSwitchMask = 0x0080; //P2 Left
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_RIGHT:
|
|
playerSwitchMask = 0x0040; //P2 Right
|
|
break;
|
|
case PS2::CControllerInfo::CROSS:
|
|
systemSwitchMask = 0x0400; //P2 Start
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if(padNumber == 2)
|
|
{
|
|
switch(button)
|
|
{
|
|
case PS2::CControllerInfo::DPAD_UP:
|
|
playerSwitchMask = 0x0100; //P3 Up
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_DOWN:
|
|
playerSwitchMask = 0x0200; //P3 Down
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_LEFT:
|
|
playerSwitchMask = 0x0800; //P3 Left
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_RIGHT:
|
|
playerSwitchMask = 0x0400; //P3 Right
|
|
break;
|
|
case PS2::CControllerInfo::CROSS:
|
|
systemSwitchMask = 0x0200; //P3 Start
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else if(padNumber == 3)
|
|
{
|
|
switch(button)
|
|
{
|
|
case PS2::CControllerInfo::DPAD_UP:
|
|
playerSwitchMask = 0x0001; //P4 Up
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_DOWN:
|
|
playerSwitchMask = 0x0002; //P4 Down
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_LEFT:
|
|
playerSwitchMask = 0x0008; //P4 Left
|
|
break;
|
|
case PS2::CControllerInfo::DPAD_RIGHT:
|
|
playerSwitchMask = 0x0004; //P4 Right
|
|
break;
|
|
case PS2::CControllerInfo::CROSS:
|
|
systemSwitchMask = 0x0100; //P4 Start
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
m_systemSwitchState &= ~systemSwitchMask;
|
|
m_playerSwitchState &= ~playerSwitchMask;
|
|
if(!pressed)
|
|
{
|
|
m_systemSwitchState |= systemSwitchMask;
|
|
m_playerSwitchState |= playerSwitchMask;
|
|
}
|
|
}
|
|
}
|
|
|
|
void CSys147::SetAxisState(unsigned int padNumber, PS2::CControllerInfo::BUTTON button, uint8 axisValue, uint8* ram)
|
|
{
|
|
}
|
|
|
|
void CSys147::Invoke(CMIPS& context, unsigned int functionId)
|
|
{
|
|
throw std::runtime_error("Not implemented.");
|
|
}
|
|
|
|
bool CSys147::Invoke000(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
|
{
|
|
switch(method)
|
|
{
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X, 0x%08X).\r\n", 0x000, method);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CSys147::Invoke001(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
|
{
|
|
switch(method)
|
|
{
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X, 0x%08X).\r\n", 0x001, method);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CSys147::Invoke002(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
|
{
|
|
switch(method)
|
|
{
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X, 0x%08X).\r\n", 0x002, method);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CSys147::Invoke003(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
|
{
|
|
switch(method)
|
|
{
|
|
case 4:
|
|
{
|
|
//Read RTC
|
|
assert(argsSize == 0x10);
|
|
assert(retSize == 0x20);
|
|
ret[0] = 0x24; //Year
|
|
ret[1] = 0x02; //Month
|
|
ret[2] = 0x07; //Day
|
|
ret[3] = 0x01; //Day of Week (?)
|
|
ret[4] = 0x04; //Hours
|
|
ret[5] = 0x04; //Minutes
|
|
ret[6] = 0x05; //Seconds;
|
|
}
|
|
break;
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X, 0x%08X).\r\n", 0x003, method);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CSys147::Invoke200(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
|
{
|
|
switch(method)
|
|
{
|
|
case 0:
|
|
{
|
|
//Write
|
|
//0 -> 0x400 -> Data to write
|
|
//0x400 -> Offset
|
|
//0x404 -> Size
|
|
uint32 offset = args[0x100];
|
|
uint32 size = args[0x101];
|
|
assert(size <= 0x400);
|
|
WriteBackupRam(offset, reinterpret_cast<const uint8*>(args), size);
|
|
}
|
|
break;
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X, 0x%08X).\r\n", 0x200, method);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CSys147::Invoke201(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
|
{
|
|
switch(method)
|
|
{
|
|
case 0:
|
|
{
|
|
//Read
|
|
//0x0 -> Offset
|
|
//0x4 -> Size
|
|
uint32 offset = args[0];
|
|
uint32 size = args[1];
|
|
assert(size <= 0x400);
|
|
ReadBackupRam(offset, reinterpret_cast<uint8*>(ret), size);
|
|
}
|
|
break;
|
|
default:
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X, 0x%08X).\r\n", 0x201, method);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool CSys147::Invoke99(uint32 method, uint32* args, uint32 argsSize, uint32* ret, uint32 retSize, uint8* ram)
|
|
{
|
|
switch(method)
|
|
{
|
|
case 0x02000000:
|
|
//Command 0x02000000
|
|
//Ret 0 -> size (0x40 blocks)
|
|
//Ret 1... -> some data (in blocks of 0x40 bytes)
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_02000000();\r\n");
|
|
//Receive Responses?
|
|
{
|
|
uint16 maxPackets = reinterpret_cast<uint16*>(args)[0];
|
|
assert(m_pendingReplies.size() < 0x10000);
|
|
uint16 xferPackets = std::min(maxPackets, static_cast<uint16>(m_pendingReplies.size()));
|
|
auto outputPacket = reinterpret_cast<MODULE_99_PACKET*>(ret + 1);
|
|
for(int i = 0; i < xferPackets; i++)
|
|
{
|
|
memcpy(outputPacket, &m_pendingReplies.front(), sizeof(MODULE_99_PACKET));
|
|
m_pendingReplies.erase(m_pendingReplies.begin());
|
|
outputPacket++;
|
|
}
|
|
reinterpret_cast<uint16*>(ret)[0] = xferPackets;
|
|
}
|
|
break;
|
|
case 0x03004002:
|
|
//Send Command?
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_03004002();\r\n");
|
|
{
|
|
assert(argsSize == 0x40);
|
|
auto packet = reinterpret_cast<const MODULE_99_PACKET*>(args);
|
|
CLog::GetInstance().Warn(LOG_NAME, "Recv Command 0x%02X.\r\n", packet->command);
|
|
|
|
//0x0D -> ???
|
|
//0x0F -> Get PCB info
|
|
//0x10 -> System Switches (?)
|
|
//0x18 -> Switch
|
|
//0x38 -> SCI
|
|
//0x39 -> ???
|
|
//0x58 -> Mechanical Counter
|
|
//0x48 -> Coin Sensor
|
|
//0x68 -> Hopper
|
|
|
|
if(packet->command == 0x0F)
|
|
{
|
|
MODULE_99_PACKET reply = {};
|
|
|
|
//Stuff that is displayed
|
|
//00:01 -> ??
|
|
//02:03 -> Version, needs to be 0x104 (MSB first)
|
|
//04
|
|
|
|
reply.type = 2;
|
|
reply.command = 0x0F;
|
|
reply.data[2] = 0x01;
|
|
reply.data[3] = 0x04;
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
if(packet->command == 0x48)
|
|
{
|
|
//Coin Sensor
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x48;
|
|
reply.data[0] = packet->data[0];
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
else if(packet->command == 0x18)
|
|
{
|
|
//Switch
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x18;
|
|
reply.data[0] = packet->data[0];
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
else if(packet->command == 0x58)
|
|
{
|
|
//Mechanical Counter
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x58;
|
|
reply.data[0] = packet->data[0];
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
else if(packet->command == 0xD8)
|
|
{
|
|
//???
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0xD8;
|
|
reply.data[0] = packet->data[0];
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
else if(packet->command == 0x31)
|
|
{
|
|
//Barcode Reader & IC Card
|
|
//data[0] = channel?
|
|
//data[1] = size of data
|
|
//data[4] = start of data
|
|
uint8 channel = packet->data[0];
|
|
uint8 inputSize = packet->data[1];
|
|
CLog::GetInstance().Warn(LOG_NAME, "Received command buffer channel: %d, size: %d\r\n",
|
|
channel, inputSize);
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x31;
|
|
if(channel == 0)
|
|
{
|
|
assert(inputSize == 4);
|
|
//Barcode Reader
|
|
reply.data[0] = channel;
|
|
reply.data[1] = 0x6; //Data Size
|
|
reply.data[4 + 0] = 0x02;
|
|
reply.data[4 + 1] = 0x02;
|
|
reply.data[4 + 2] = 0x80;
|
|
reply.data[4 + 3] = 0x02; //This is used for result
|
|
reply.data[4 + 4] = 0x03;
|
|
reply.data[4 + 5] = 0x03;
|
|
}
|
|
else if(channel == 2)
|
|
{
|
|
ProcessIcCard(reply, *packet);
|
|
}
|
|
else
|
|
{
|
|
assert(false);
|
|
}
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
else if(packet->command == 0x39)
|
|
{
|
|
//Seems to be related to switch values?
|
|
for(const auto& switchState : m_switchStates)
|
|
{
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x39;
|
|
reply.data[0] = switchState.first;
|
|
reply.data[4] = switchState.second;
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
|
|
{
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x31;
|
|
//Barcode Reader
|
|
reply.data[0] = 0;
|
|
reply.data[1] = 6; //Data Size
|
|
|
|
reply.data[4 + 0] = 0x02;
|
|
reply.data[4 + 1] = 0x02;
|
|
reply.data[4 + 2] = 0x80;
|
|
reply.data[4 + 3] = 0x02; //This is used for result
|
|
reply.data[4 + 4] = 0x03;
|
|
reply.data[4 + 5] = 0x03;
|
|
|
|
//Barcode Payload
|
|
{
|
|
std::unique_lock barcodeMutexLock(m_barcodeMutex);
|
|
if(m_currentBarcode.size() == 8)
|
|
{
|
|
reply.data[1] += 10; //Add more data to payload
|
|
|
|
//0x02 = Header
|
|
//8 bytes of data (0x62,0x6E,0x30,0x63,0x30,0x7D,0x58,0x31)
|
|
//0x03 = Footer
|
|
|
|
reply.data[4 + 6] = 0x02;
|
|
for(int i = 0; i < 8; i++)
|
|
{
|
|
reply.data[4 + 7 + i] = m_currentBarcode[i];
|
|
}
|
|
reply.data[4 + 15] = 0x03;
|
|
}
|
|
m_currentBarcode.clear();
|
|
}
|
|
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
}
|
|
else if(packet->command == 0x0D)
|
|
{
|
|
//???
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x0D;
|
|
reply.data[0] = packet->data[0];
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
else if(packet->command == 0x38)
|
|
{
|
|
//SCI
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x38;
|
|
reply.data[0] = packet->data[0];
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
else if(packet->command == 0x10)
|
|
{
|
|
//Some kind of I/O device related response
|
|
//Animal Kaiser uses this for dispenser
|
|
//Pac Man Battle Royale uses this for switch state
|
|
if(m_ioMode == IO_MODE::AI)
|
|
{
|
|
{
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x10;
|
|
reply.data[0] = static_cast<uint8>(m_systemSwitchState);
|
|
reply.data[1] = static_cast<uint8>(m_systemSwitchState >> 8);
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
|
|
{
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 3;
|
|
reply.command = 0x10;
|
|
reply.data[0x32] = 0x20;
|
|
reply.data[0x36] = static_cast<uint8>(m_playerSwitchState);
|
|
reply.data[0x37] = static_cast<uint8>(m_playerSwitchState >> 8);
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
MODULE_99_PACKET reply = {};
|
|
reply.type = 2;
|
|
reply.command = 0x10;
|
|
reply.data[0] = packet->data[0];
|
|
reply.checksum = ComputePacketChecksum(reply);
|
|
m_pendingReplies.emplace_back(reply);
|
|
}
|
|
}
|
|
reinterpret_cast<uint16*>(ret)[0] = 1;
|
|
}
|
|
break;
|
|
case 0x08000000:
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_08000000();\r\n");
|
|
reinterpret_cast<uint16*>(ret)[0] = 1;
|
|
break;
|
|
case 0x09000002:
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_09000002();\r\n");
|
|
reinterpret_cast<uint16*>(ret)[0] = 0;
|
|
break;
|
|
case 0x09000003:
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_09000003();\r\n");
|
|
reinterpret_cast<uint16*>(ret)[0] = 0;
|
|
break;
|
|
case 0x0C000002:
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_0C000002();\r\n");
|
|
reinterpret_cast<uint16*>(ret)[0] = 0;
|
|
break;
|
|
case 0x0C000003:
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_0C000003();\r\n");
|
|
reinterpret_cast<uint16*>(ret)[0] = 0;
|
|
break;
|
|
case 0x0D003803:
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_0D003803();\r\n");
|
|
reinterpret_cast<uint16*>(ret)[0] = 0;
|
|
break;
|
|
case 0x11000000:
|
|
CLog::GetInstance().Warn(LOG_NAME, "LINK_11000000();\r\n");
|
|
reinterpret_cast<uint16*>(ret)[0] = 0;
|
|
break;
|
|
default:
|
|
reinterpret_cast<uint16*>(ret)[0] = 1;
|
|
CLog::GetInstance().Warn(LOG_NAME, "Unknown method invoked (0x%08X, 0x%08X).\r\n", 0x99, method);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void CSys147::ProcessIcCard(MODULE_99_PACKET& output, const MODULE_99_PACKET& input)
|
|
{
|
|
uint32 channel = input.data[0];
|
|
assert(channel == 2);
|
|
uint32 dataSize = input.data[1];
|
|
uint32 commandId = input.data[5];
|
|
uint32 replySize = 0;
|
|
static const uint32 replyBase = 4;
|
|
output.data[replyBase + 0] = 0x02;
|
|
output.data[replyBase + 1] = commandId; //Command ID
|
|
switch(commandId)
|
|
{
|
|
case 0x78:
|
|
{
|
|
//??
|
|
assert(dataSize == 0x07);
|
|
replySize = 6;
|
|
output.data[replyBase + 3] = 0x00; //Command result?
|
|
output.data[replyBase + 4] = 0x00;
|
|
output.data[replyBase + 5] = 0xFF;
|
|
}
|
|
break;
|
|
case 0x7A:
|
|
{
|
|
//Ok next?
|
|
assert(dataSize == 0x12);
|
|
replySize = 4;
|
|
output.data[replyBase + 3] = 0x00; //Command result?
|
|
}
|
|
break;
|
|
case 0x7B:
|
|
{
|
|
assert(dataSize == 0x05);
|
|
replySize = 6;
|
|
output.data[replyBase + 3] = 0x00; //Command result? (0x03 -> No IC card)
|
|
output.data[replyBase + 4] = 0x00; //??
|
|
output.data[replyBase + 5] = 0x00; //??
|
|
}
|
|
break;
|
|
case 0x80:
|
|
{
|
|
//??
|
|
assert(dataSize == 0x05);
|
|
replySize = 4;
|
|
output.data[replyBase + 3] = 0x0D; //Command result?
|
|
}
|
|
break;
|
|
case 0x9F:
|
|
{
|
|
//??
|
|
assert(dataSize == 0x0D);
|
|
replySize = 4;
|
|
output.data[replyBase + 3] = 0x00; //Command result?
|
|
}
|
|
break;
|
|
case 0xA7:
|
|
{
|
|
//Init?
|
|
assert(dataSize == 0x0D);
|
|
replySize = 4;
|
|
output.data[replyBase + 3] = 0x00; //Command result?
|
|
}
|
|
break;
|
|
case 0xAC:
|
|
{
|
|
//Some key stuff (parity)? (game expects 8 bytes in payload)
|
|
assert(dataSize == 0x05);
|
|
replySize = 12;
|
|
output.data[replyBase + 3] = 0x00; //Command result?
|
|
output.data[replyBase + 4] = 0xAA;
|
|
output.data[replyBase + 5] = 0xAA;
|
|
output.data[replyBase + 6] = 0xAA;
|
|
output.data[replyBase + 7] = 0xAA;
|
|
output.data[replyBase + 8] = 0x55;
|
|
output.data[replyBase + 9] = 0x55;
|
|
output.data[replyBase + 10] = 0x55;
|
|
output.data[replyBase + 11] = 0x55;
|
|
}
|
|
break;
|
|
case 0xAF:
|
|
{
|
|
//More key stuff (checksum)? (game expects 16 bytes in payload)
|
|
assert(dataSize == 0x05);
|
|
replySize = 20;
|
|
output.data[replyBase + 3] = 0x00; //Command result?
|
|
}
|
|
break;
|
|
default:
|
|
assert(false);
|
|
break;
|
|
}
|
|
uint8 replySizePlusParity = replySize + 1;
|
|
assert(replySizePlusParity >= 5);
|
|
output.data[0] = channel;
|
|
output.data[1] = replySizePlusParity; //This needs to be at least 5
|
|
output.data[replyBase + 2] = replySizePlusParity - 5;
|
|
uint8 parity = 0;
|
|
for(int i = 1; i < replySize; i++)
|
|
{
|
|
parity ^= output.data[replyBase + i];
|
|
}
|
|
output.data[replyBase + replySize] = parity;
|
|
}
|
|
|
|
uint8 CSys147::ComputePacketChecksum(const MODULE_99_PACKET& packet)
|
|
{
|
|
uint8 checksum = 0;
|
|
for(const auto& value : packet.data)
|
|
{
|
|
checksum += value;
|
|
}
|
|
return checksum;
|
|
}
|
|
|
|
//TODO: This is copied from Sys246/256. Move this somewhere else
|
|
|
|
fs::path GetArcadeSavePath()
|
|
{
|
|
return CAppConfig::GetInstance().GetBasePath() / fs::path("arcadesaves");
|
|
}
|
|
|
|
void CSys147::ReadBackupRam(uint32 backupRamAddr, uint8* buffer, uint32 size)
|
|
{
|
|
memset(buffer, 0, size);
|
|
if((backupRamAddr >= BACKUP_RAM_SIZE) || ((backupRamAddr + size) > BACKUP_RAM_SIZE))
|
|
{
|
|
CLog::GetInstance().Warn(LOG_NAME, "Reading outside of backup RAM bounds.\r\n");
|
|
return;
|
|
}
|
|
auto backupRamPath = GetArcadeSavePath() / (m_gameId + ".backupram");
|
|
if(!fs::exists(backupRamPath))
|
|
{
|
|
return;
|
|
}
|
|
auto stream = Framework::CreateInputStdStream(backupRamPath.native());
|
|
stream.Seek(backupRamAddr, Framework::STREAM_SEEK_SET);
|
|
stream.Read(buffer, size);
|
|
}
|
|
|
|
void CSys147::WriteBackupRam(uint32 backupRamAddr, const uint8* buffer, uint32 size)
|
|
{
|
|
if((backupRamAddr >= BACKUP_RAM_SIZE) || ((backupRamAddr + size) > BACKUP_RAM_SIZE))
|
|
{
|
|
CLog::GetInstance().Warn(LOG_NAME, "Writing outside of backup RAM bounds.\r\n");
|
|
return;
|
|
}
|
|
auto arcadeSavePath = GetArcadeSavePath();
|
|
auto backupRamPath = arcadeSavePath / (m_gameId + ".backupram");
|
|
Framework::PathUtils::EnsurePathExists(arcadeSavePath);
|
|
auto stream = fs::exists(backupRamPath) ? Framework::CreateUpdateExistingStdStream(backupRamPath.native()) : Framework::CreateOutputStdStream(backupRamPath.native());
|
|
stream.Seek(backupRamAddr, Framework::STREAM_SEEK_SET);
|
|
stream.Write(buffer, size);
|
|
}
|
|
|
|
void CSys147::HandleIoServerRequest(const Framework::CHttpServer::Request& request)
|
|
{
|
|
if(request.url.find("/sys147/barcode") == 0)
|
|
{
|
|
std::unique_lock barcodeMutexLock(m_barcodeMutex);
|
|
m_currentBarcode = std::string(reinterpret_cast<const char*>(request.body.data()), request.body.size());
|
|
}
|
|
}
|