diff --git a/src/Platform.h b/src/Platform.h index ea50f53b..6d7eaeb3 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -157,10 +157,11 @@ void WriteGBASave(const u8* savedata, u32 savelen, u32 writeoffset, u32 writelen bool MP_Init(); void MP_DeInit(); int MP_SendPacket(u8* data, int len, u64 timestamp); -int MP_RecvPacket(u8* data, bool block, u64* timestamp); +int MP_RecvPacket(u8* data, u64* timestamp); int MP_SendCmd(u8* data, int len, u64 timestamp); int MP_SendReply(u8* data, int len, u64 timestamp, u16 aid); int MP_SendAck(u8* data, int len, u64 timestamp); +int MP_RecvHostPacket(u8* data, u64* timestamp); u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask); diff --git a/src/Wifi.cpp b/src/Wifi.cpp index 3173e9a4..a54ff7f2 100644 --- a/src/Wifi.cpp +++ b/src/Wifi.cpp @@ -1150,6 +1150,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames if (IOPORT(W_RXBufBegin) == IOPORT(W_RXBufEnd)) return false; + int rxlen; u16 framelen; u16 framectl; u8 txrate; @@ -1160,9 +1161,24 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames for (;;) { timestamp = 0; - int rxlen = Platform::MP_RecvPacket(RXBuffer, (type != 0), ×tamp); - if ((rxlen == 0) && (type == 0)) rxlen = WifiAP::RecvPacket(RXBuffer); - if (rxlen == 0) return false; + + if (type == 0) + { + rxlen = Platform::MP_RecvPacket(RXBuffer, ×tamp); + if (rxlen <= 0) + rxlen = WifiAP::RecvPacket(RXBuffer); + } + else + { + rxlen = Platform::MP_RecvHostPacket(RXBuffer, ×tamp); + if (rxlen < 0) + { + // host is gone + IsMPClient = false; + } + } + + if (rxlen <= 0) return false; if (rxlen < 12+24) continue; framelen = *(u16*)&RXBuffer[10]; diff --git a/src/frontend/qt_sdl/LocalMP.cpp b/src/frontend/qt_sdl/LocalMP.cpp index 573952df..d06d776e 100644 --- a/src/frontend/qt_sdl/LocalMP.cpp +++ b/src/frontend/qt_sdl/LocalMP.cpp @@ -81,6 +81,8 @@ const u32 kReplyEnd = kQueueSize; const int RecvTimeout = 500; +int LastHostID; + // we need to come up with our own abstraction layer for named semaphores // because QSystemSemaphore doesn't support waiting with a timeout @@ -220,6 +222,8 @@ bool Init() SemInit(InstanceID); SemInit(16+InstanceID); + LastHostID = -1; + printf("MP comm init OK, instance ID %d\n", InstanceID); return true; @@ -363,12 +367,7 @@ int SendPacketGeneric(u32 type, u8* packet, int len, u64 timestamp) return len; } -int SendPacket(u8* packet, int len, u64 timestamp) -{ - return SendPacketGeneric(0, packet, len, timestamp); -} - -int RecvPacket(u8* packet, bool block, u64* timestamp) +int RecvPacketGeneric(u8* packet, bool block, u64* timestamp) { for (;;) { @@ -402,14 +401,29 @@ int RecvPacket(u8* packet, bool block, u64* timestamp) } if (pktheader.Length) + { FIFORead(0, packet, pktheader.Length); + if (pktheader.Type == 1) + LastHostID = pktheader.SenderID; + } + if (timestamp) *timestamp = pktheader.Timestamp; MPQueue->unlock(); return pktheader.Length; } } +int SendPacket(u8* packet, int len, u64 timestamp) +{ + return SendPacketGeneric(0, packet, len, timestamp); +} + +int RecvPacket(u8* packet, u64* timestamp) +{ + return RecvPacketGeneric(packet, false, timestamp); +} + int SendCmd(u8* packet, int len, u64 timestamp) { @@ -426,10 +440,42 @@ int SendAck(u8* packet, int len, u64 timestamp) return SendPacketGeneric(3, packet, len, timestamp); } +int RecvHostPacket(u8* packet, u64* timestamp) +{ + if (LastHostID != -1) + { + // check if the host is still connected + + MPQueue->lock(); + u8* data = (u8*)MPQueue->data(); + MPQueueHeader* header = (MPQueueHeader*)&data[0]; + u16 curinstmask = header->InstanceBitmask; + MPQueue->unlock(); + + if (!(curinstmask & (1 << LastHostID))) + return -1; + } + + return RecvPacketGeneric(packet, true, timestamp); +} + u16 RecvReplies(u8* packets, u64 timestamp, u16 aidmask) { u16 ret = 0; - u16 instmask = (1 << InstanceID); + u16 myinstmask = (1 << InstanceID); + u16 curinstmask; + + { + MPQueue->lock(); + u8* data = (u8*)MPQueue->data(); + MPQueueHeader* header = (MPQueueHeader*)&data[0]; + curinstmask = header->InstanceBitmask; + MPQueue->unlock(); + } + + // if all clients have left: return early + if ((myinstmask & curinstmask) == curinstmask) + return 0; for (;;) { @@ -472,8 +518,8 @@ u16 RecvReplies(u8* packets, u64 timestamp, u16 aidmask) ret |= (1 << aid); } - instmask |= (1 << pktheader.SenderID); - if ((instmask & header->InstanceBitmask) == header->InstanceBitmask) + myinstmask |= (1 << pktheader.SenderID); + if ((myinstmask & curinstmask) == curinstmask) { // all the clients have sent their reply diff --git a/src/frontend/qt_sdl/LocalMP.h b/src/frontend/qt_sdl/LocalMP.h index b2a44288..f152400a 100644 --- a/src/frontend/qt_sdl/LocalMP.h +++ b/src/frontend/qt_sdl/LocalMP.h @@ -27,10 +27,11 @@ namespace LocalMP bool Init(); void DeInit(); int SendPacket(u8* data, int len, u64 timestamp); -int RecvPacket(u8* data, bool block, 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); } diff --git a/src/frontend/qt_sdl/Platform.cpp b/src/frontend/qt_sdl/Platform.cpp index 62bd21db..d47402a8 100644 --- a/src/frontend/qt_sdl/Platform.cpp +++ b/src/frontend/qt_sdl/Platform.cpp @@ -374,9 +374,9 @@ int MP_SendPacket(u8* data, int len, u64 timestamp) return LocalMP::SendPacket(data, len, timestamp); } -int MP_RecvPacket(u8* data, bool block, u64* timestamp) +int MP_RecvPacket(u8* data, u64* timestamp) { - return LocalMP::RecvPacket(data, block, timestamp); + return LocalMP::RecvPacket(data, timestamp); } int MP_SendCmd(u8* data, int len, u64 timestamp) @@ -394,6 +394,11 @@ int MP_SendAck(u8* data, int len, u64 timestamp) return LocalMP::SendAck(data, len, timestamp); } +int MP_RecvHostPacket(u8* data, u64* timestamp) +{ + return LocalMP::RecvHostPacket(data, timestamp); +} + u16 MP_RecvReplies(u8* data, u64 timestamp, u16 aidmask) { return LocalMP::RecvReplies(data, timestamp, aidmask);