/* Copyright 2023 flyinghead This file is part of Flycast. Flycast is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version. Flycast is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Flycast. If not, see . */ #pragma once #include "gdcartridge.h" #include "network/net_platform.h" class NetDimm : public GDCartridge { public: NetDimm(u32 size); ~NetDimm() override; void Init(LoadProgress *progress = nullptr, std::vector *digest = nullptr) override; u32 ReadMem(u32 address, u32 size) override; void WriteMem(u32 address, u32 data, u32 size) override; bool Write(u32 offset, u32 size, u32 data) override; void Serialize(Serializer &ser) const override; void Deserialize(Deserializer &deser) override; private: void returnToNaomi(bool failed, u16 offsetl, u32 parameter); static int schedCallback(int tag, int sch_cycl, int jitter, void *arg); int schedCallback(); void process(); void systemCmd(int cmd); void netCmd(int cmd); template void poke(u32 address, T value) { static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4); int size; switch (sizeof(T)) { case 1: size = 8; break; case 2: size = 9; break; case 4: size = 10; break; } dimm_command = ((address >> 16) & 0x1ff) | (size << 9) | 0x8000; dimm_offsetl = address & 0xffff; dimm_parameterl = value & 0xffff; dimm_parameterh = value >> 16; } template void peek(u32 address) { static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4); int size; switch (sizeof(T)) { case 1: size = 4; break; case 2: size = 5; break; case 4: size = 6; break; } dimm_command = ((address >> 16) & 0x1ff) | (size << 9) | 0x8000; dimm_offsetl = address & 0xffff; dimm_parameterl = 0; dimm_parameterh = 0; } sock_t getSocket(int idx) { if (idx < 1 || idx > (int)sockets.size()) return INVALID_SOCKET; return sockets[idx - 1].fd; } bool isBusy() const { for (const Socket& sock : sockets) if (sock.isBusy()) return true; return false; } u16 dimm_command; u16 dimm_offsetl; u16 dimm_parameterl; u16 dimm_parameterh; static constexpr u16 DIMM_STATUS = 0x111; int schedId; struct Socket { Socket() = default; Socket(sock_t fd) : fd(fd) {} int close() { int rc = 0; if (fd != INVALID_SOCKET) rc = ::closesocket(fd); fd = INVALID_SOCKET; connecting = false; receiving = false; sending = false; connectTimeout = 0; connectTime = 0; sendTimeout = 0; sendTime = 0; recvTimeout = 0; recvTime = 0; return rc; } bool isClosed() const { return fd == INVALID_SOCKET; } bool isBusy() const { return connecting || receiving || sending; } sock_t fd = INVALID_SOCKET; bool connecting = false; bool receiving = false; u8 *recvData = nullptr; u32 recvLen = 0; bool sending = false; const u8 *sendData = nullptr; u32 sendLen = 0; u64 connectTimeout = 0; u64 connectTime = 0; u64 sendTimeout = 0; u64 sendTime = 0; u64 recvTimeout = 0; u64 recvTime = 0; int lastError = 0; }; std::vector sockets; bool dnsInProgress = false; u32 serverIp = 0; //0x0100007f for testing only bool finalTuned = false; u32 dimmBufferOffset = 0x0f000000; static constexpr int POLL_CYCLES = SH4_MAIN_CLOCK / 60; };