dcnet: Power Smash support

This commit is contained in:
Flyinghead 2025-07-03 17:18:46 +02:00
parent 75defb590b
commit 5df5c70994
2 changed files with 79 additions and 11 deletions

View File

@ -578,6 +578,15 @@ void CheatManager::reset(const std::string& gameId)
cheats.emplace_back(Cheat::Type::setValue, "modem automode4 set", true, 32, addr + 0x10, 0x30202020, true); // " 0" cheats.emplace_back(Cheat::Type::setValue, "modem automode4 set", true, 32, addr + 0x10, 0x30202020, true); // " 0"
} }
} }
else if (gameId == "HDR-0113") // Power Smash
{
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe SYN ifeq", true, 16, 0x14d258, 0xbbce, true); // bsr SendNormalSYN
cheats.emplace_back(Cheat::Type::setValue, "no dupe SYN set", true, 16, 0x14d258, 0x0009, true); // nop
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe SYN2 ifeq", true, 16, 0x14d274, 0xbb72, true); // bsr SendFakeSYN
cheats.emplace_back(Cheat::Type::setValue, "no dupe SYN2 set", true, 16, 0x14d274, 0x0009, true); // nop
cheats.emplace_back(Cheat::Type::runNextIfEq, "no dupe ACK ifeq", true, 16, 0x14af42, 0x430b, true); // jsr TCPInternalSendPacket
cheats.emplace_back(Cheat::Type::setValue, "no dupe ACK set", true, 16, 0x14af42, 0x0009, true); // nop
}
if (cheats.size() > cheatCount) if (cheats.size() > cheatCount)
setActive(true); setActive(true);

View File

@ -55,11 +55,10 @@ public:
void receiveEthFrame(const u8 *frame, u32 size) override; void receiveEthFrame(const u8 *frame, u32 size) override;
}; };
template<typename SocketT>
class PPPSocket class PPPSocket
{ {
public: public:
PPPSocket(asio::io_context& io_context, const typename SocketT::endpoint_type& endpoint, PPPSocket(asio::io_context& io_context, const asio::ip::tcp::endpoint& endpoint,
const std::string& endpointName = "") const std::string& endpointName = "")
: socket(io_context) : socket(io_context)
{ {
@ -71,7 +70,7 @@ public:
receive(); receive();
} }
~PPPSocket() { virtual ~PPPSocket() {
if (dumpfp != nullptr) if (dumpfp != nullptr)
fclose(dumpfp); fclose(dumpfp);
} }
@ -86,8 +85,8 @@ public:
doSend(); doSend();
} }
private: protected:
void receive() virtual void receive()
{ {
socket.async_read_some(asio::buffer(recvBuffer), socket.async_read_some(asio::buffer(recvBuffer),
[this](const std::error_code& ec, size_t len) [this](const std::error_code& ec, size_t len)
@ -172,7 +171,7 @@ private:
#endif #endif
} }
SocketT socket; asio::ip::tcp::socket socket;
std::array<u8, 1542> recvBuffer; std::array<u8, 1542> recvBuffer;
std::array<u8, 1542> sendBuffer; std::array<u8, 1542> sendBuffer;
u32 sendBufSize = 0; u32 sendBufSize = 0;
@ -182,7 +181,55 @@ private:
u64 dump_last_time_ms; u64 dump_last_time_ms;
}; };
using PPPTcpSocket = PPPSocket<asio::ip::tcp::socket>; class PowerSmashPPPSocket : public PPPSocket
{
public:
PowerSmashPPPSocket(asio::io_context& io_context, const asio::ip::tcp::endpoint& endpoint,
const std::string& endpointName = "")
: PPPSocket(io_context, endpoint, endpointName) {}
private:
void receive() override
{
socket.async_read_some(asio::buffer(&recvBuffer[recvBufSize], recvBuffer.size() - recvBufSize),
[this](const std::error_code& ec, size_t len)
{
if (ec || len == 0)
{
if (ec)
ERROR_LOG(NETWORK, "Receive error: %s", ec.message().c_str());
close();
return;
}
recvBufSize += len;
while (recvBufSize != 0)
{
u32 frameSize = 0;
for (u32 i = 1; i < recvBufSize; i++)
{
if (recvBuffer[i] == '~') {
frameSize = i + 1;
break;
}
}
if (frameSize == 0)
break;
pppdump(recvBuffer.data(), frameSize, false);
// Power Smash requires both start and end Flag Sequences
if (recvBuffer[0] != '~')
toModem.push('~');
for (size_t i = 0; i < frameSize; i++)
toModem.push(recvBuffer[i]);
recvBufSize -= frameSize;
if (recvBufSize != 0)
memmove(&recvBuffer[0], &recvBuffer[frameSize], recvBufSize);
}
receive();
});
}
u32 recvBufSize = 0;
};
class EthSocket class EthSocket
{ {
@ -609,11 +656,12 @@ private:
std::thread thread; std::thread thread;
std::unique_ptr<asio::io_context> io_context; std::unique_ptr<asio::io_context> io_context;
std::unique_ptr<PPPTcpSocket> pppSocket; std::unique_ptr<PPPSocket> pppSocket;
std::unique_ptr<EthSocket> ethSocket; std::unique_ptr<EthSocket> ethSocket;
static constexpr uint16_t PPP_PORT = 7654; static constexpr uint16_t PPP_PORT = 7654;
static constexpr uint16_t TAP_PORT = 7655; static constexpr uint16_t TAP_PORT = 7655;
static constexpr uint16_t POWER_SMASH_PPP_PORT = 7656;
friend DCNetService; friend DCNetService;
}; };
static DCNetThread thread; static DCNetThread thread;
@ -679,6 +727,7 @@ void DCNetService::receiveEthFrame(u8 const *frame, unsigned int len)
void DCNetThread::connect(const asio::ip::address& address, const std::string& apname) void DCNetThread::connect(const asio::ip::address& address, const std::string& apname)
{ {
const bool powerSmash = settings.content.gameId == "HDR-0113";
asio::ip::tcp::endpoint endpoint; asio::ip::tcp::endpoint endpoint;
if (address.is_unspecified()) if (address.is_unspecified())
{ {
@ -689,6 +738,8 @@ void DCNetThread::connect(const asio::ip::address& address, const std::string& a
std::string port; std::string port;
if (config::EmulateBBA) if (config::EmulateBBA)
port = std::to_string(TAP_PORT); port = std::to_string(TAP_PORT);
else if (powerSmash)
port = std::to_string(POWER_SMASH_PPP_PORT);
else else
port = std::to_string(PPP_PORT); port = std::to_string(PPP_PORT);
asio::ip::tcp::resolver resolver(*io_context); asio::ip::tcp::resolver resolver(*io_context);
@ -700,14 +751,22 @@ void DCNetThread::connect(const asio::ip::address& address, const std::string& a
throw FlycastException("Host not found"); throw FlycastException("Host not found");
endpoint = *it.begin(); endpoint = *it.begin();
} }
else { else
{
endpoint.address(address); endpoint.address(address);
endpoint.port(config::EmulateBBA ? TAP_PORT : PPP_PORT); if (config::EmulateBBA)
endpoint.port(TAP_PORT);
else if (powerSmash)
endpoint.port(POWER_SMASH_PPP_PORT);
else
endpoint.port(PPP_PORT);
} }
if (config::EmulateBBA) if (config::EmulateBBA)
ethSocket = std::make_unique<EthSocket>(*io_context, endpoint, apname); ethSocket = std::make_unique<EthSocket>(*io_context, endpoint, apname);
else if (powerSmash)
pppSocket = std::make_unique<PowerSmashPPPSocket>(*io_context, endpoint, apname);
else else
pppSocket = std::make_unique<PPPTcpSocket>(*io_context, endpoint, apname); pppSocket = std::make_unique<PPPSocket>(*io_context, endpoint, apname);
} }
void DCNetThread::run() void DCNetThread::run()