aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArisotura <thetotalworm@gmail.com>2023-07-27 21:11:30 +0200
committerArisotura <thetotalworm@gmail.com>2023-07-27 21:11:30 +0200
commitc3943b29ec57721ee21d332d4f3bdf9bf5e28a1d (patch)
treef976558b05c5eb12f84f28c1f7fd6d6f807953f5
parentb04c250e2ff78f793cdafaf6cc09731bc667da71 (diff)
wifi:
* rework and clean up frame transfer code * disable melonAP during local multiplayer comm
-rw-r--r--src/Wifi.cpp191
1 files changed, 88 insertions, 103 deletions
diff --git a/src/Wifi.cpp b/src/Wifi.cpp
index 482802e..a1c8267 100644
--- a/src/Wifi.cpp
+++ b/src/Wifi.cpp
@@ -85,6 +85,7 @@ struct TXSlot
};
TXSlot TXSlots[6];
+u8 TXBuffer[0x2000];
u8 RXBuffer[2048];
u32 RXBufferPtr;
@@ -107,6 +108,7 @@ int USUntilPowerOn;
bool ForcePowerOn;
// MULTIPLAYER SYNC APPARATUS
+bool IsMP;
bool IsMPClient;
u64 NextSync; // for clients: timestamp for next sync point
u64 RXTimestamp;
@@ -242,6 +244,7 @@ void Reset()
BlockBeaconIRQ14 = false;
memset(TXSlots, 0, sizeof(TXSlots));
+ memset(TXBuffer, 0, sizeof(TXBuffer));
ComStatus = 0;
TXCurSlot = -1;
RXCounter = 0;
@@ -261,6 +264,7 @@ void Reset()
USUntilPowerOn = 0;
ForcePowerOn = false;
+ IsMP = false;
IsMPClient = false;
NextSync = 0;
RXTimestamp = 0;
@@ -314,6 +318,8 @@ void DoSavestate(Savestate* file)
file->Var32(&slot->HalfwordTimeMask);
}
+ file->VarArray(TXBuffer, sizeof(TXBuffer));
+
file->VarArray(RXBuffer, sizeof(RXBuffer));
file->Var32(&RXBufferPtr);
file->Var32((u32*)&RXTime);
@@ -332,6 +338,7 @@ void DoSavestate(Savestate* file)
file->Var32((u32*)&USUntilPowerOn);
file->Bool32(&ForcePowerOn);
+ file->Bool32(&IsMP);
file->Bool32(&IsMPClient);
file->Var64(&NextSync);
file->Var64(&RXTimestamp);
@@ -530,16 +537,73 @@ void ReportMPReplyErrors(u16 clientfail)
}
}
-void PreTXAdjust(TXSlot* slot, int num)
+void TXSendFrame(TXSlot* slot, int num)
{
u32 noseqno = 0;
- if (num == 1) noseqno = (IOPORT(W_TXSlotCmd) & 0x4000);
+
+ if (RAM[slot->Addr + 0x4])
+ {
+ noseqno = 2;
+ }
+ else
+ {
+ if (num == 1) noseqno = (IOPORT(W_TXSlotCmd) & 0x4000) ? 1:0;
+ }
if (!noseqno)
{
- *(u16*)&RAM[slot->Addr + 0xC + 22] = IOPORT(W_TXSeqNo) << 4;
+ if (!(IOPORT(W_TXHeaderCnt) & (1<<2)))
+ *(u16*)&RAM[slot->Addr + 0xC + 22] = IOPORT(W_TXSeqNo) << 4;
IOPORT(W_TXSeqNo) = (IOPORT(W_TXSeqNo) + 1) & 0x0FFF;
}
+
+ u16 framectl = *(u16*)&RAM[slot->Addr + 0xC];
+ if (framectl & (1<<14))
+ {
+ // WEP frame
+ // TODO: what happens when sending a WEP frame while WEP processing is off?
+ // TODO: some form of actual WEP processing?
+ // for now we just set the WEP FCS to a nonzero value, because some games require it
+
+ if (IOPORT(W_WEPCnt) & (1<<15))
+ {
+ u32 wep_fcs = (slot->Addr + 0xC + slot->Length - 7) & ~0x1;
+ *(u32*)&RAM[wep_fcs] = 0x22334466;
+ }
+ }
+
+ int len = slot->Length;
+ if ((slot->Addr + len) > 0x1FF4)
+ len = 0x1FF4 - slot->Addr;
+
+ memcpy(TXBuffer, &RAM[slot->Addr], 12+len);
+
+ if (noseqno == 2)
+ *(u16*)&TXBuffer[0xC] |= (1<<11);
+
+ switch (num)
+ {
+ case 0:
+ case 2:
+ case 3:
+ Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp);
+ if (!IsMP) WifiAP::SendPacket(TXBuffer, 12+len);
+ break;
+
+ case 1:
+ Platform::MP_SendCmd(TXBuffer, 12+len, USTimestamp);
+ break;
+
+ case 5:
+ IncrementTXCount(slot);
+ Platform::MP_SendReply(TXBuffer, 12+len, USTimestamp, IOPORT(W_AIDLow));
+ break;
+
+ case 4:
+ *(u64*)&TXBuffer[0xC + 24] = USCounter;
+ Platform::MP_SendPacket(TXBuffer, 12+len, USTimestamp);
+ break;
+ }
}
void StartTX_LocN(int nslot, int loc)
@@ -549,6 +613,8 @@ void StartTX_LocN(int nslot, int loc)
if (IOPORT(W_TXSlotLoc1 + (loc*4)) & 0x7000)
Log(LogLevel::Warn, "wifi: unusual loc%d bits set %04X\n", loc, IOPORT(W_TXSlotLoc1 + (loc*4)));
+ slot->Valid = true;
+
slot->Addr = (IOPORT(W_TXSlotLoc1 + (loc*4)) & 0x0FFF) << 1;
slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF;
@@ -567,6 +633,8 @@ void StartTX_Cmd()
if (IOPORT(W_TXSlotCmd) & 0x3000)
Log(LogLevel::Warn,"wifi: !! unusual TXSLOT_CMD bits set %04X\n", IOPORT(W_TXSlotCmd));
+ slot->Valid = true;
+
slot->Addr = (IOPORT(W_TXSlotCmd) & 0x0FFF) << 1;
slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF;
@@ -595,6 +663,8 @@ void StartTX_Beacon()
{
TXSlot* slot = &TXSlots[4];
+ slot->Valid = true;
+
slot->Addr = (IOPORT(W_TXSlotBeacon) & 0x0FFF) << 1;
slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF;
@@ -716,21 +786,13 @@ void SendMPReply(u16 clienttime, u16 clientmask)
slot->Valid = false;
}
- //if (RAM[slot->Addr+4] > 0)
- // printf("REPLY RETRY COUNTER %d (%04X)\n", RAM[slot->Addr+4], IOPORT(W_TXSlotReply2));
-
// this seems to be set upon IRQ0
// TODO: how does it behave if the packet addr is changed before it gets sent? (maybe just not possible)
if (slot->Valid)
{
- //*(u16*)&RAM[slot->Addr + 0x4] = 0x0001;
- IncrementTXCount(slot);
-
slot->CurPhase = 0;
- PreTXAdjust(slot, 5);
- int txlen = Platform::MP_SendReply(&RAM[slot->Addr], 12 + slot->Length, USTimestamp, IOPORT(W_AIDLow));
- WIFI_LOG("wifi: sent %d/%d bytes of MP reply\n", txlen, 12 + slot->Length);
+ TXSendFrame(slot, 5);
}
else
{
@@ -804,15 +866,6 @@ bool ProcessTX(TXSlot* slot, int num)
u32 curclient = 1 << nclient;
- /*if (CheckRX(1))
- {
- // we received a reply, mark it as such
- // TODO: is any received packet considered a good reply?
- // hardware probably requires a specific frame-control and/or destination MAC
-
- MPClientFail &= ~curclient;
- }
- else printf("REPLY %04X NOT RECEIVED\n");*/
if (!(MPClientFail & curclient))
MPClientReplyRX(nclient);
@@ -831,23 +884,7 @@ bool ProcessTX(TXSlot* slot, int num)
SetIRQ(7);
if (num == 5)
- {
- // MP reply slot
- // setup needs to be done now as port 098 can get changed in the meantime
-
SetStatus(8);
-
- //slot->Addr = (IOPORT(W_TXSlotReply2) & 0x0FFF) << 1;
- //slot->Length = *(u16*)&RAM[slot->Addr + 0xA] & 0x3FFF;
-
- /*u8 rate = RAM[slot->Addr + 0x8];
- if (rate == 0x14) slot->Rate = 2;
- else slot->Rate = 1;*/
-
- // TODO: duration should be set by hardware
- // doesn't seem to be important
- //RAM[slot->Addr + 0xC + 2] = 0x00F0;
- }
else
SetStatus(3);
@@ -866,68 +903,19 @@ bool ProcessTX(TXSlot* slot, int num)
slot->CurPhase = 1;
slot->CurPhaseTime = len;
- u16 framectl = *(u16*)&RAM[slot->Addr + 0xC];
- if (framectl & (1<<14))
- {
- // WEP frame
- // TODO: what happens when sending a WEP frame while WEP processing is off?
- // TODO: some form of actual WEP processing?
- // for now we just set the WEP FCS to a nonzero value, because some games require it
-
- if (IOPORT(W_WEPCnt) & (1<<15))
- {
- u32 wep_fcs = (slot->Addr + 0xC + slot->Length - 7) & ~0x1;
- *(u32*)&RAM[wep_fcs] = 0x22334466;
- }
- }
-
- u64 oldts;
- if (num == 4)
- {
- // beacon timestamp
- oldts = *(u64*)&RAM[slot->Addr + 0xC + 24];
- *(u64*)&RAM[slot->Addr + 0xC + 24] = USCounter;
- }
-
- if ((num != 5) && (RAM[slot->Addr+4] > 0))
- Log(LogLevel::Debug, "SLOT %d RETRY COUNTER %d\n", num, RAM[slot->Addr+4]);
-
// set TX addr
IOPORT(W_RXTXAddr) = slot->Addr >> 1;
- if (num == 1)
+ if (num != 5)
{
- PreTXAdjust(slot, num);
-
- // send
- int txlen = Platform::MP_SendCmd(&RAM[slot->Addr], 12 + slot->Length, USTimestamp);
- WIFI_LOG("wifi: sent %d/%d bytes of slot%d packet, addr=%04X, framectl=%04X, %04X %04X\n",
- txlen, slot->Length+12, num, slot->Addr, *(u16*)&RAM[slot->Addr + 0xC],
- *(u16*)&RAM[slot->Addr + 0x24], *(u16*)&RAM[slot->Addr + 0x26]);
- }
- else if (num == 5)
- {
- // send
- /*int txlen = Platform::MP_SendReply(&RAM[slot->Addr], 12 + slot->Length, USTimestamp, IOPORT(W_AIDLow));
- WIFI_LOG("wifi: sent %d/%d bytes of slot%d packet, addr=%04X, framectl=%04X, %04X %04X\n",
- txlen, slot->Length+12, num, slot->Addr, *(u16*)&RAM[slot->Addr + 0xC],
- *(u16*)&RAM[slot->Addr + 0x24], *(u16*)&RAM[slot->Addr + 0x26]);*/
- }
- else //if (num != 5)
- {
- PreTXAdjust(slot, num);
-
- // send
- int txlen = Platform::MP_SendPacket(&RAM[slot->Addr], 12 + slot->Length, USTimestamp);
- WIFI_LOG("wifi: sent %d/%d bytes of slot%d packet, addr=%04X, framectl=%04X, %04X %04X\n",
- txlen, slot->Length+12, num, slot->Addr, *(u16*)&RAM[slot->Addr + 0xC],
- *(u16*)&RAM[slot->Addr + 0x24], *(u16*)&RAM[slot->Addr + 0x26]);
+ TXSendFrame(slot, num);
}
// if the packet is being sent via LOC1..3, send it to the AP
// any packet sent via CMD/REPLY/BEACON isn't going to have much use outside of local MP
if (num == 0 || num == 2 || num == 3)
{
+ u16 framectl = *(u16*)&RAM[slot->Addr + 0xC];
if ((framectl & 0x00FF) == 0x0010)
{
u16 aid = *(u16*)&RAM[slot->Addr + 0xC + 24 + 4];
@@ -938,16 +926,10 @@ bool ProcessTX(TXSlot* slot, int num)
if (IsMPClient)
{
Log(LogLevel::Info, "[CLIENT] deauth\n");
+ IsMP = false;
IsMPClient = false;
}
}
-
- WifiAP::SendPacket(&RAM[slot->Addr], 12 + slot->Length);
- }
-
- if (num == 4)
- {
- *(u64*)&RAM[slot->Addr + 0xC + 24] = oldts;
}
}
break;
@@ -957,10 +939,6 @@ bool ProcessTX(TXSlot* slot, int num)
SetIRQ(7);
SetStatus(8);
- //SendMPDefaultReply();
-
- //slot->Addr = 0;
- //slot->Length = 28;
slot->CurPhase = 11;
slot->CurPhaseTime = 28*4;
slot->HalfwordTimeMask = 0xFFFFFFFF;
@@ -984,7 +962,6 @@ bool ProcessTX(TXSlot* slot, int num)
SetStatus(5);
u16 clientmask = *(u16*)&RAM[slot->Addr + 12 + 24 + 2] & 0xFFFE;
- //MPNumReplies = NumClients(clientmask);
MPReplyTimer = 16 + PreambleLen(slot->Rate);
MPClientMask = clientmask;
MPClientFail = clientmask;
@@ -1085,7 +1062,8 @@ bool ProcessTX(TXSlot* slot, int num)
// this is set to indicate which clients failed to reply
*(u16*)&RAM[slot->Addr + 0x2] = MPClientFail;
- IncrementTXCount(slot);
+ if (!MPClientFail)
+ IncrementTXCount(slot);
IOPORT(W_TXSeqNo) = (IOPORT(W_TXSeqNo) + 1) & 0x0FFF;
@@ -1497,7 +1475,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
if (type == 0)
{
rxlen = Platform::MP_RecvPacket(RXBuffer, &timestamp);
- if (rxlen <= 0)
+ if ((rxlen <= 0) && (!IsMP))
rxlen = WifiAP::RecvPacket(RXBuffer);
}
else
@@ -1507,6 +1485,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
{
// host is gone
// TODO: make this more resilient
+ IsMP = false;
IsMPClient = false;
}
}
@@ -1556,6 +1535,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
{
Log(LogLevel::Debug, "[CLIENT %01X] host sync=%016llX\n", aid&0xF, timestamp);
+ IsMP = true;
IsMPClient = true;
USTimestamp = timestamp;
NextSync = RXTimestamp + (framelen * (txrate==0x14 ? 4:8));
@@ -1566,6 +1546,7 @@ bool CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
}
else if (((framectl & 0x00FF) == 0x00C0) && timestamp && macgood && IsMPClient)
{
+ IsMP = false;
IsMPClient = false;
NextSync = 0;
@@ -2251,6 +2232,10 @@ void Write(u32 addr, u16 val)
val &= 0x0FFF;
break;
+ case W_TXSlotBeacon:
+ IsMP = (val & 0x8000) != 0;
+ break;
+
case W_TXSlotCmd:
if (CmdCounter == 0)
val = (val & 0x7FFF) | (IOPORT(W_TXSlotCmd) & 0x8000);