fix up LocalMP
This commit is contained in:
parent
153f01ec54
commit
15bb45d069
|
@ -38,6 +38,7 @@
|
|||
#include "EmuInstance.h"
|
||||
#include "Config.h"
|
||||
#include "Platform.h"
|
||||
#include "LocalMP.h"
|
||||
|
||||
#include "NDS.h"
|
||||
#include "DSi.h"
|
||||
|
@ -99,6 +100,8 @@ EmuInstance::~EmuInstance()
|
|||
{
|
||||
// TODO window cleanup and shit?
|
||||
|
||||
LocalMP::End(instanceID);
|
||||
|
||||
emuThread->emuExit();
|
||||
emuThread->wait();
|
||||
delete emuThread;
|
||||
|
|
|
@ -33,6 +33,8 @@
|
|||
|
||||
#include <string>
|
||||
#include <QSharedMemory>
|
||||
#include <QMutex>
|
||||
#include <QSemaphore>
|
||||
|
||||
#include "Config.h"
|
||||
#include "LocalMP.h"
|
||||
|
@ -47,17 +49,12 @@ using Platform::LogLevel;
|
|||
namespace LocalMP
|
||||
{
|
||||
|
||||
u32 MPUniqueID;
|
||||
u8 PacketBuffer[2048];
|
||||
|
||||
struct MPQueueHeader
|
||||
struct MPStatusData
|
||||
{
|
||||
u16 NumInstances;
|
||||
u16 InstanceBitmask; // bitmask of all instances present
|
||||
u16 ConnectedBitmask; // bitmask of which instances are ready to send/receive packets
|
||||
u32 PacketWriteOffset;
|
||||
u32 ReplyWriteOffset;
|
||||
u16 MPHostInstanceID; // instance ID from which the last CMD frame was sent
|
||||
u16 MPHostinst; // instance ID from which the last CMD frame was sent
|
||||
u16 MPReplyBitmask; // bitmask of which clients replied in time
|
||||
};
|
||||
|
||||
|
@ -70,23 +67,15 @@ struct MPPacketHeader
|
|||
u64 Timestamp;
|
||||
};
|
||||
|
||||
struct MPSync
|
||||
{
|
||||
u32 Magic;
|
||||
u32 SenderID;
|
||||
u16 ClientMask;
|
||||
u16 Type;
|
||||
u64 Timestamp;
|
||||
};
|
||||
|
||||
QSharedMemory* MPQueue;
|
||||
int InstanceID;
|
||||
u32 PacketReadOffset;
|
||||
u32 ReplyReadOffset;
|
||||
QMutex MPQueueLock;
|
||||
MPStatusData MPStatus;
|
||||
u8* MPQueue = nullptr;
|
||||
u32 PacketReadOffset[16];
|
||||
u32 ReplyReadOffset[16];
|
||||
|
||||
const u32 kQueueSize = 0x20000;
|
||||
const u32 kMaxFrameSize = 0x800;
|
||||
const u32 kPacketStart = sizeof(MPQueueHeader);
|
||||
const u32 kPacketStart = 0;
|
||||
const u32 kReplyStart = kQueueSize / 2;
|
||||
const u32 kPacketEnd = kReplyStart;
|
||||
const u32 kReplyEnd = kQueueSize;
|
||||
|
@ -96,204 +85,57 @@ int RecvTimeout;
|
|||
int LastHostID;
|
||||
|
||||
|
||||
// we need to come up with our own abstraction layer for named semaphores
|
||||
// because QSystemSemaphore doesn't support waiting with a timeout
|
||||
// and, as such, is unsuitable to our needs
|
||||
|
||||
#ifdef __WIN32__
|
||||
|
||||
bool SemInited[32];
|
||||
HANDLE SemPool[32];
|
||||
QSemaphore SemPool[32];
|
||||
|
||||
void SemPoolInit()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
SemPool[i] = INVALID_HANDLE_VALUE;
|
||||
SemInited[i] = false;
|
||||
SemPool[i].acquire(SemPool[i].available());
|
||||
}
|
||||
}
|
||||
|
||||
void SemDeinit(int num);
|
||||
|
||||
void SemPoolDeinit()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
SemDeinit(i);
|
||||
}
|
||||
|
||||
bool SemInit(int num)
|
||||
{
|
||||
if (SemInited[num])
|
||||
return true;
|
||||
|
||||
char semname[64];
|
||||
sprintf(semname, "Local\\melonNIFI_Sem%02d", num);
|
||||
|
||||
HANDLE sem = CreateSemaphoreA(nullptr, 0, 64, semname);
|
||||
SemPool[num] = sem;
|
||||
SemInited[num] = true;
|
||||
return sem != INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
void SemDeinit(int num)
|
||||
{
|
||||
if (SemPool[num] != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
CloseHandle(SemPool[num]);
|
||||
SemPool[num] = INVALID_HANDLE_VALUE;
|
||||
}
|
||||
|
||||
SemInited[num] = false;
|
||||
}
|
||||
|
||||
bool SemPost(int num)
|
||||
{
|
||||
SemInit(num);
|
||||
return ReleaseSemaphore(SemPool[num], 1, nullptr) != 0;
|
||||
}
|
||||
|
||||
bool SemWait(int num, int timeout)
|
||||
{
|
||||
return WaitForSingleObject(SemPool[num], timeout) == WAIT_OBJECT_0;
|
||||
}
|
||||
|
||||
void SemReset(int num)
|
||||
{
|
||||
while (WaitForSingleObject(SemPool[num], 0) == WAIT_OBJECT_0);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool SemInited[32];
|
||||
sem_t* SemPool[32];
|
||||
|
||||
void SemPoolInit()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
{
|
||||
SemPool[i] = SEM_FAILED;
|
||||
SemInited[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
void SemDeinit(int num);
|
||||
|
||||
void SemPoolDeinit()
|
||||
{
|
||||
for (int i = 0; i < 32; i++)
|
||||
SemDeinit(i);
|
||||
}
|
||||
|
||||
bool SemInit(int num)
|
||||
{
|
||||
if (SemInited[num])
|
||||
return true;
|
||||
|
||||
char semname[64];
|
||||
sprintf(semname, "/melonNIFI_Sem%02d", num);
|
||||
|
||||
sem_t* sem = sem_open(semname, O_CREAT, 0644, 0);
|
||||
SemPool[num] = sem;
|
||||
SemInited[num] = true;
|
||||
return sem != SEM_FAILED;
|
||||
}
|
||||
|
||||
void SemDeinit(int num)
|
||||
{
|
||||
if (SemPool[num] != SEM_FAILED)
|
||||
{
|
||||
sem_close(SemPool[num]);
|
||||
SemPool[num] = SEM_FAILED;
|
||||
}
|
||||
|
||||
SemInited[num] = false;
|
||||
}
|
||||
|
||||
bool SemPost(int num)
|
||||
{
|
||||
SemInit(num);
|
||||
return sem_post(SemPool[num]) == 0;
|
||||
SemPool[num].release(1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SemWait(int num, int timeout)
|
||||
{
|
||||
if (!timeout)
|
||||
return sem_trywait(SemPool[num]) == 0;
|
||||
return SemPool[num].tryAcquire(1);
|
||||
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_REALTIME, &ts);
|
||||
ts.tv_nsec += timeout * 1000000;
|
||||
long sec = ts.tv_nsec / 1000000000;
|
||||
ts.tv_nsec -= sec * 1000000000;
|
||||
ts.tv_sec += sec;
|
||||
|
||||
return sem_timedwait(SemPool[num], &ts) == 0;
|
||||
return SemPool[num].tryAcquire(1, timeout);
|
||||
}
|
||||
|
||||
void SemReset(int num)
|
||||
{
|
||||
while (sem_trywait(SemPool[num]) == 0);
|
||||
SemPool[num].acquire(SemPool[num].available());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
bool Init()
|
||||
{
|
||||
MPQueue = new QSharedMemory("melonNIFI");
|
||||
MPQueueLock.lock();
|
||||
|
||||
if (!MPQueue->attach())
|
||||
{
|
||||
Log(LogLevel::Info, "MP sharedmem doesn't exist. creating\n");
|
||||
if (!MPQueue->create(kQueueSize))
|
||||
{
|
||||
Log(LogLevel::Error, "MP sharedmem create failed :( (%d)\n", MPQueue->error());
|
||||
delete MPQueue;
|
||||
MPQueue = nullptr;
|
||||
return false;
|
||||
}
|
||||
MPQueue = new u8[kQueueSize];
|
||||
memset(MPQueue, 0, kQueueSize);
|
||||
memset(&MPStatus, 0, sizeof(MPStatus));
|
||||
memset(PacketReadOffset, 0, sizeof(PacketReadOffset));
|
||||
memset(ReplyReadOffset, 0, sizeof(ReplyReadOffset));
|
||||
|
||||
MPQueue->lock();
|
||||
memset(MPQueue->data(), 0, MPQueue->size());
|
||||
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||
header->PacketWriteOffset = kPacketStart;
|
||||
header->ReplyWriteOffset = kReplyStart;
|
||||
MPQueue->unlock();
|
||||
}
|
||||
|
||||
MPQueue->lock();
|
||||
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||
|
||||
u16 mask = header->InstanceBitmask;
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if (!(mask & (1<<i)))
|
||||
{
|
||||
InstanceID = i;
|
||||
header->InstanceBitmask |= (1<<i);
|
||||
//header->ConnectedBitmask |= (1 << i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
header->NumInstances++;
|
||||
|
||||
PacketReadOffset = header->PacketWriteOffset;
|
||||
ReplyReadOffset = header->ReplyWriteOffset;
|
||||
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.unlock();
|
||||
|
||||
// prepare semaphores
|
||||
// semaphores 0-15: regular frames; semaphore I is posted when instance I needs to process a new frame
|
||||
// semaphores 16-31: MP replies; semaphore I is posted when instance I needs to process a new MP reply
|
||||
|
||||
SemPoolInit();
|
||||
SemInit(InstanceID);
|
||||
SemInit(16+InstanceID);
|
||||
|
||||
LastHostID = -1;
|
||||
|
||||
Log(LogLevel::Info, "MP comm init OK, instance ID %d\n", InstanceID);
|
||||
Log(LogLevel::Info, "MP comm init OK\n");
|
||||
|
||||
RecvTimeout = 25;
|
||||
|
||||
|
@ -302,23 +144,6 @@ bool Init()
|
|||
|
||||
void DeInit()
|
||||
{
|
||||
if (MPQueue)
|
||||
{
|
||||
MPQueue->lock();
|
||||
if (MPQueue->data() != nullptr)
|
||||
{
|
||||
MPQueueHeader *header = (MPQueueHeader *) MPQueue->data();
|
||||
header->ConnectedBitmask &= ~(1 << InstanceID);
|
||||
header->InstanceBitmask &= ~(1 << InstanceID);
|
||||
header->NumInstances--;
|
||||
}
|
||||
MPQueue->unlock();
|
||||
|
||||
SemPoolDeinit();
|
||||
|
||||
MPQueue->detach();
|
||||
}
|
||||
|
||||
delete MPQueue;
|
||||
MPQueue = nullptr;
|
||||
}
|
||||
|
@ -328,44 +153,42 @@ void SetRecvTimeout(int timeout)
|
|||
RecvTimeout = timeout;
|
||||
}
|
||||
|
||||
void Begin()
|
||||
void Begin(int inst)
|
||||
{
|
||||
if (!MPQueue) return;
|
||||
MPQueue->lock();
|
||||
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||
PacketReadOffset = header->PacketWriteOffset;
|
||||
ReplyReadOffset = header->ReplyWriteOffset;
|
||||
SemReset(InstanceID);
|
||||
SemReset(16+InstanceID);
|
||||
header->ConnectedBitmask |= (1 << InstanceID);
|
||||
MPQueue->unlock();
|
||||
|
||||
MPQueueLock.lock();
|
||||
PacketReadOffset[inst] = MPStatus.PacketWriteOffset;
|
||||
ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset;
|
||||
SemReset(inst);
|
||||
SemReset(16+inst);
|
||||
MPStatus.ConnectedBitmask |= (1 << inst);
|
||||
MPQueueLock.unlock();
|
||||
}
|
||||
|
||||
void End()
|
||||
void End(int inst)
|
||||
{
|
||||
if (!MPQueue) return;
|
||||
MPQueue->lock();
|
||||
MPQueueHeader* header = (MPQueueHeader*)MPQueue->data();
|
||||
//SemReset(InstanceID);
|
||||
//SemReset(16+InstanceID);
|
||||
header->ConnectedBitmask &= ~(1 << InstanceID);
|
||||
MPQueue->unlock();
|
||||
|
||||
MPQueueLock.lock();
|
||||
MPStatus.ConnectedBitmask &= ~(1 << inst);
|
||||
MPQueueLock.unlock();
|
||||
}
|
||||
|
||||
void FIFORead(int fifo, void* buf, int len)
|
||||
void FIFORead(int inst, int fifo, void* buf, int len)
|
||||
{
|
||||
u8* data = (u8*)MPQueue->data();
|
||||
u8* data = MPQueue;
|
||||
|
||||
u32 offset, start, end;
|
||||
if (fifo == 0)
|
||||
{
|
||||
offset = PacketReadOffset;
|
||||
offset = PacketReadOffset[inst];
|
||||
start = kPacketStart;
|
||||
end = kPacketEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = ReplyReadOffset;
|
||||
offset = ReplyReadOffset[inst];
|
||||
start = kReplyStart;
|
||||
end = kReplyEnd;
|
||||
}
|
||||
|
@ -383,25 +206,24 @@ void FIFORead(int fifo, void* buf, int len)
|
|||
offset += len;
|
||||
}
|
||||
|
||||
if (fifo == 0) PacketReadOffset = offset;
|
||||
else ReplyReadOffset = offset;
|
||||
if (fifo == 0) PacketReadOffset[inst] = offset;
|
||||
else ReplyReadOffset[inst] = offset;
|
||||
}
|
||||
|
||||
void FIFOWrite(int fifo, void* buf, int len)
|
||||
void FIFOWrite(int inst, int fifo, void* buf, int len)
|
||||
{
|
||||
u8* data = (u8*)MPQueue->data();
|
||||
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||
u8* data = MPQueue;
|
||||
|
||||
u32 offset, start, end;
|
||||
if (fifo == 0)
|
||||
{
|
||||
offset = header->PacketWriteOffset;
|
||||
offset = MPStatus.PacketWriteOffset;
|
||||
start = kPacketStart;
|
||||
end = kPacketEnd;
|
||||
}
|
||||
else
|
||||
{
|
||||
offset = header->ReplyWriteOffset;
|
||||
offset = MPStatus.ReplyWriteOffset;
|
||||
start = kReplyStart;
|
||||
end = kReplyEnd;
|
||||
}
|
||||
|
@ -419,53 +241,51 @@ void FIFOWrite(int fifo, void* buf, int len)
|
|||
offset += len;
|
||||
}
|
||||
|
||||
if (fifo == 0) header->PacketWriteOffset = offset;
|
||||
else header->ReplyWriteOffset = offset;
|
||||
if (fifo == 0) MPStatus.PacketWriteOffset = offset;
|
||||
else MPStatus.ReplyWriteOffset = offset;
|
||||
}
|
||||
|
||||
int SendPacketGeneric(u32 type, u8* packet, int len, u64 timestamp)
|
||||
int SendPacketGeneric(int inst, u32 type, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
if (!MPQueue) return 0;
|
||||
MPQueue->lock();
|
||||
u8* data = (u8*)MPQueue->data();
|
||||
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||
MPQueueLock.lock();
|
||||
|
||||
u16 mask = header->ConnectedBitmask;
|
||||
u16 mask = MPStatus.ConnectedBitmask;
|
||||
|
||||
// TODO: check if the FIFO is full!
|
||||
|
||||
MPPacketHeader pktheader;
|
||||
pktheader.Magic = 0x4946494E;
|
||||
pktheader.SenderID = InstanceID;
|
||||
pktheader.SenderID = inst;
|
||||
pktheader.Type = type;
|
||||
pktheader.Length = len;
|
||||
pktheader.Timestamp = timestamp;
|
||||
|
||||
type &= 0xFFFF;
|
||||
int nfifo = (type == 2) ? 1 : 0;
|
||||
FIFOWrite(nfifo, &pktheader, sizeof(pktheader));
|
||||
FIFOWrite(inst, nfifo, &pktheader, sizeof(pktheader));
|
||||
if (len)
|
||||
FIFOWrite(nfifo, packet, len);
|
||||
FIFOWrite(inst, nfifo, packet, len);
|
||||
|
||||
if (type == 1)
|
||||
{
|
||||
// NOTE: this is not guarded against, say, multiple multiplay games happening on the same machine
|
||||
// we would need to pass the packet's SenderID through the wifi module for that
|
||||
header->MPHostInstanceID = InstanceID;
|
||||
header->MPReplyBitmask = 0;
|
||||
ReplyReadOffset = header->ReplyWriteOffset;
|
||||
SemReset(16 + InstanceID);
|
||||
MPStatus.MPHostinst = inst;
|
||||
MPStatus.MPReplyBitmask = 0;
|
||||
ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset;
|
||||
SemReset(16 + inst);
|
||||
}
|
||||
else if (type == 2)
|
||||
{
|
||||
header->MPReplyBitmask |= (1 << InstanceID);
|
||||
MPStatus.MPReplyBitmask |= (1 << inst);
|
||||
}
|
||||
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.unlock();
|
||||
|
||||
if (type == 2)
|
||||
{
|
||||
SemPost(16 + header->MPHostInstanceID);
|
||||
SemPost(16 + MPStatus.MPHostinst);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -479,84 +299,82 @@ int SendPacketGeneric(u32 type, u8* packet, int len, u64 timestamp)
|
|||
return len;
|
||||
}
|
||||
|
||||
int RecvPacketGeneric(u8* packet, bool block, u64* timestamp)
|
||||
int RecvPacketGeneric(int inst, u8* packet, bool block, u64* timestamp)
|
||||
{
|
||||
if (!MPQueue) return 0;
|
||||
for (;;)
|
||||
{
|
||||
if (!SemWait(InstanceID, block ? RecvTimeout : 0))
|
||||
if (!SemWait(inst, block ? RecvTimeout : 0))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
MPQueue->lock();
|
||||
u8* data = (u8*)MPQueue->data();
|
||||
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||
MPQueueLock.lock();
|
||||
|
||||
MPPacketHeader pktheader;
|
||||
FIFORead(0, &pktheader, sizeof(pktheader));
|
||||
FIFORead(inst, 0, &pktheader, sizeof(pktheader));
|
||||
|
||||
if (pktheader.Magic != 0x4946494E)
|
||||
{
|
||||
Log(LogLevel::Warn, "PACKET FIFO OVERFLOW\n");
|
||||
PacketReadOffset = header->PacketWriteOffset;
|
||||
SemReset(InstanceID);
|
||||
MPQueue->unlock();
|
||||
PacketReadOffset[inst] = MPStatus.PacketWriteOffset;
|
||||
SemReset(inst);
|
||||
MPQueueLock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (pktheader.SenderID == InstanceID)
|
||||
if (pktheader.SenderID == inst)
|
||||
{
|
||||
// skip this packet
|
||||
PacketReadOffset += pktheader.Length;
|
||||
if (PacketReadOffset >= kPacketEnd)
|
||||
PacketReadOffset += kPacketStart - kPacketEnd;
|
||||
PacketReadOffset[inst] += pktheader.Length;
|
||||
if (PacketReadOffset[inst] >= kPacketEnd)
|
||||
PacketReadOffset[inst] += kPacketStart - kPacketEnd;
|
||||
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pktheader.Length)
|
||||
{
|
||||
FIFORead(0, packet, pktheader.Length);
|
||||
FIFORead(inst, 0, packet, pktheader.Length);
|
||||
|
||||
if (pktheader.Type == 1)
|
||||
LastHostID = pktheader.SenderID;
|
||||
}
|
||||
|
||||
if (timestamp) *timestamp = pktheader.Timestamp;
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.unlock();
|
||||
return pktheader.Length;
|
||||
}
|
||||
}
|
||||
|
||||
int SendPacket(u8* packet, int len, u64 timestamp)
|
||||
int SendPacket(int inst, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
return SendPacketGeneric(0, packet, len, timestamp);
|
||||
return SendPacketGeneric(inst, 0, packet, len, timestamp);
|
||||
}
|
||||
|
||||
int RecvPacket(u8* packet, u64* timestamp)
|
||||
int RecvPacket(int inst, u8* packet, u64* timestamp)
|
||||
{
|
||||
return RecvPacketGeneric(packet, false, timestamp);
|
||||
return RecvPacketGeneric(inst, packet, false, timestamp);
|
||||
}
|
||||
|
||||
|
||||
int SendCmd(u8* packet, int len, u64 timestamp)
|
||||
int SendCmd(int inst, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
return SendPacketGeneric(1, packet, len, timestamp);
|
||||
return SendPacketGeneric(inst, 1, packet, len, timestamp);
|
||||
}
|
||||
|
||||
int SendReply(u8* packet, int len, u64 timestamp, u16 aid)
|
||||
int SendReply(int inst, u8* packet, int len, u64 timestamp, u16 aid)
|
||||
{
|
||||
return SendPacketGeneric(2 | (aid<<16), packet, len, timestamp);
|
||||
return SendPacketGeneric(inst, 2 | (aid<<16), packet, len, timestamp);
|
||||
}
|
||||
|
||||
int SendAck(u8* packet, int len, u64 timestamp)
|
||||
int SendAck(int inst, u8* packet, int len, u64 timestamp)
|
||||
{
|
||||
return SendPacketGeneric(3, packet, len, timestamp);
|
||||
return SendPacketGeneric(inst, 3, packet, len, timestamp);
|
||||
}
|
||||
|
||||
int RecvHostPacket(u8* packet, u64* timestamp)
|
||||
int RecvHostPacket(int inst, u8* packet, u64* timestamp)
|
||||
{
|
||||
if (!MPQueue) return -1;
|
||||
|
||||
|
@ -564,33 +382,30 @@ int RecvHostPacket(u8* packet, u64* timestamp)
|
|||
{
|
||||
// check if the host is still connected
|
||||
|
||||
MPQueue->lock();
|
||||
u8* data = (u8*)MPQueue->data();
|
||||
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||
u16 curinstmask = header->ConnectedBitmask;
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.lock();
|
||||
u8* data = MPQueue;
|
||||
u16 curinstmask = MPStatus.ConnectedBitmask;
|
||||
MPQueueLock.unlock();
|
||||
|
||||
if (!(curinstmask & (1 << LastHostID)))
|
||||
return -1;
|
||||
}
|
||||
|
||||
return RecvPacketGeneric(packet, true, timestamp);
|
||||
return RecvPacketGeneric(inst, packet, true, timestamp);
|
||||
}
|
||||
|
||||
u16 RecvReplies(u8* packets, u64 timestamp, u16 aidmask)
|
||||
u16 RecvReplies(int inst, u8* packets, u64 timestamp, u16 aidmask)
|
||||
{
|
||||
if (!MPQueue) return 0;
|
||||
|
||||
u16 ret = 0;
|
||||
u16 myinstmask = (1 << InstanceID);
|
||||
u16 myinstmask = (1 << inst);
|
||||
u16 curinstmask;
|
||||
|
||||
{
|
||||
MPQueue->lock();
|
||||
u8* data = (u8*)MPQueue->data();
|
||||
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||
curinstmask = header->ConnectedBitmask;
|
||||
MPQueue->unlock();
|
||||
//MPQueueLock.lock();
|
||||
curinstmask = MPStatus.ConnectedBitmask;
|
||||
//MPQueueLock.unlock();
|
||||
}
|
||||
|
||||
// if all clients have left: return early
|
||||
|
@ -599,44 +414,42 @@ u16 RecvReplies(u8* packets, u64 timestamp, u16 aidmask)
|
|||
|
||||
for (;;)
|
||||
{
|
||||
if (!SemWait(16+InstanceID, RecvTimeout))
|
||||
if (!SemWait(16+inst, RecvTimeout))
|
||||
{
|
||||
// no more replies available
|
||||
return ret;
|
||||
}
|
||||
|
||||
MPQueue->lock();
|
||||
u8* data = (u8*)MPQueue->data();
|
||||
MPQueueHeader* header = (MPQueueHeader*)&data[0];
|
||||
MPQueueLock.lock();
|
||||
|
||||
MPPacketHeader pktheader;
|
||||
FIFORead(1, &pktheader, sizeof(pktheader));
|
||||
FIFORead(inst, 1, &pktheader, sizeof(pktheader));
|
||||
|
||||
if (pktheader.Magic != 0x4946494E)
|
||||
{
|
||||
Log(LogLevel::Warn, "REPLY FIFO OVERFLOW\n");
|
||||
ReplyReadOffset = header->ReplyWriteOffset;
|
||||
SemReset(16+InstanceID);
|
||||
MPQueue->unlock();
|
||||
ReplyReadOffset[inst] = MPStatus.ReplyWriteOffset;
|
||||
SemReset(16+inst);
|
||||
MPQueueLock.unlock();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((pktheader.SenderID == InstanceID) || // packet we sent out (shouldn't happen, but hey)
|
||||
if ((pktheader.SenderID == inst) || // packet we sent out (shouldn't happen, but hey)
|
||||
(pktheader.Timestamp < (timestamp - 32))) // stale packet
|
||||
{
|
||||
// skip this packet
|
||||
ReplyReadOffset += pktheader.Length;
|
||||
if (ReplyReadOffset >= kReplyEnd)
|
||||
ReplyReadOffset += kReplyStart - kReplyEnd;
|
||||
ReplyReadOffset[inst] += pktheader.Length;
|
||||
if (ReplyReadOffset[inst] >= kReplyEnd)
|
||||
ReplyReadOffset[inst] += kReplyStart - kReplyEnd;
|
||||
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.unlock();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pktheader.Length)
|
||||
{
|
||||
u32 aid = (pktheader.Type >> 16);
|
||||
FIFORead(1, &packets[(aid-1)*1024], pktheader.Length);
|
||||
FIFORead(inst, 1, &packets[(aid-1)*1024], pktheader.Length);
|
||||
ret |= (1 << aid);
|
||||
}
|
||||
|
||||
|
@ -646,11 +459,11 @@ u16 RecvReplies(u8* packets, u64 timestamp, u16 aidmask)
|
|||
{
|
||||
// all the clients have sent their reply
|
||||
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.unlock();
|
||||
return ret;
|
||||
}
|
||||
|
||||
MPQueue->unlock();
|
||||
MPQueueLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,16 +30,16 @@ void DeInit();
|
|||
|
||||
void SetRecvTimeout(int timeout);
|
||||
|
||||
void Begin();
|
||||
void End();
|
||||
void Begin(int inst);
|
||||
void End(int inst);
|
||||
|
||||
int SendPacket(u8* data, int len, u64 timestamp);
|
||||
int RecvPacket(u8* data, u64* timestamp);
|
||||
int SendCmd(u8* data, int len, u64 timestamp);
|
||||
int SendReply(u8* data, int len, u64 timestamp, u16 aid);
|
||||
int SendAck(u8* data, int len, u64 timestamp);
|
||||
int RecvHostPacket(u8* data, u64* timestamp);
|
||||
u16 RecvReplies(u8* data, u64 timestamp, u16 aidmask);
|
||||
int SendPacket(int inst, u8* data, int len, u64 timestamp);
|
||||
int RecvPacket(int inst, u8* data, u64* timestamp);
|
||||
int SendCmd(int inst, u8* data, int len, u64 timestamp);
|
||||
int SendReply(int inst, u8* data, int len, u64 timestamp, u16 aid);
|
||||
int SendAck(int inst, u8* data, int len, u64 timestamp);
|
||||
int RecvHostPacket(int inst, u8* data, u64* timestamp);
|
||||
u16 RecvReplies(int inst, u8* data, u64 timestamp, u16 aidmask);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -50,12 +50,6 @@
|
|||
|
||||
extern CameraManager* camManager[2];
|
||||
|
||||
void emuStop();
|
||||
|
||||
// TEMP
|
||||
//#include "main.h"
|
||||
//extern MainWindow* mainWindow;
|
||||
|
||||
|
||||
namespace melonDS::Platform
|
||||
{
|
||||
|
@ -454,65 +448,65 @@ void WriteDateTime(int year, int month, int day, int hour, int minute, int secon
|
|||
|
||||
bool MP_Init(void* userdata)
|
||||
{
|
||||
//return LocalMP::Init();
|
||||
return true;
|
||||
}
|
||||
|
||||
void MP_DeInit(void* userdata)
|
||||
{
|
||||
//return LocalMP::DeInit();
|
||||
}
|
||||
|
||||
void MP_Begin(void* userdata)
|
||||
{
|
||||
//return LocalMP::Begin();
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
LocalMP::Begin(inst);
|
||||
}
|
||||
|
||||
void MP_End(void* userdata)
|
||||
{
|
||||
//return LocalMP::End();
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
LocalMP::End(inst);
|
||||
}
|
||||
|
||||
int MP_SendPacket(u8* data, int len, u64 timestamp, void* userdata)
|
||||
{
|
||||
//return LocalMP::SendPacket(data, len, timestamp);
|
||||
return 0;
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
return LocalMP::SendPacket(inst, data, len, timestamp);
|
||||
}
|
||||
|
||||
int MP_RecvPacket(u8* data, u64* timestamp, void* userdata)
|
||||
{
|
||||
//return LocalMP::RecvPacket(data, timestamp);
|
||||
return 0;
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
return LocalMP::RecvPacket(inst, data, timestamp);
|
||||
}
|
||||
|
||||
int MP_SendCmd(u8* data, int len, u64 timestamp, void* userdata)
|
||||
{
|
||||
//return LocalMP::SendCmd(data, len, timestamp);
|
||||
return 0;
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
return LocalMP::SendCmd(inst, data, len, timestamp);
|
||||
}
|
||||
|
||||
int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid, void* userdata)
|
||||
{
|
||||
//return LocalMP::SendReply(data, len, timestamp, aid);
|
||||
return 0;
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
return LocalMP::SendReply(inst, data, len, timestamp, aid);
|
||||
}
|
||||
|
||||
int MP_SendAck(u8* data, int len, u64 timestamp, void* userdata)
|
||||
{
|
||||
//return LocalMP::SendAck(data, len, timestamp);
|
||||
return 0;
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
return LocalMP::SendAck(inst, data, len, timestamp);
|
||||
}
|
||||
|
||||
int MP_RecvHostPacket(u8* data, u64* timestamp, void* userdata)
|
||||
{
|
||||
//return LocalMP::RecvHostPacket(data, timestamp);
|
||||
return 0;
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
return LocalMP::RecvHostPacket(inst, data, timestamp);
|
||||
}
|
||||
|
||||
u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask, void* userdata)
|
||||
{
|
||||
//return LocalMP::RecvReplies(data, timestamp, aidmask);
|
||||
return 0;
|
||||
int inst = ((EmuInstance*)userdata)->getInstanceID();
|
||||
return LocalMP::RecvReplies(inst, data, timestamp, aidmask);
|
||||
}
|
||||
|
||||
bool LAN_Init(void* userdata)
|
||||
|
|
|
@ -74,6 +74,7 @@
|
|||
#include "EmuInstance.h"
|
||||
#include "ArchiveUtil.h"
|
||||
#include "CameraManager.h"
|
||||
#include "LocalMP.h"
|
||||
|
||||
#include "CLI.h"
|
||||
|
||||
|
@ -266,6 +267,8 @@ int main(int argc, char** argv)
|
|||
}
|
||||
}
|
||||
|
||||
LocalMP::Init();
|
||||
|
||||
/* mainWindow = new MainWindow();
|
||||
if (options->fullscreen)
|
||||
ToggleFullscreen(mainWindow);
|
||||
|
@ -318,6 +321,8 @@ int main(int argc, char** argv)
|
|||
// but with this we make extra sure they are all deleted
|
||||
deleteAllEmuInstances();
|
||||
|
||||
LocalMP::DeInit();
|
||||
|
||||
//AudioInOut::DeInit();
|
||||
delete camManager[0];
|
||||
delete camManager[1];
|
||||
|
|
Loading…
Reference in New Issue