wifi: implement CMD retries

This commit is contained in:
Arisotura 2023-07-27 21:54:30 +02:00
parent c3943b29ec
commit 9c5cde8109
1 changed files with 55 additions and 35 deletions

View File

@ -101,6 +101,8 @@ u16 MPClientMask, MPClientFail;
u8 MPClientReplies[15*1024]; u8 MPClientReplies[15*1024];
u16 MPLastSeqno;
bool MPInited; bool MPInited;
bool LANInited; bool LANInited;
@ -259,6 +261,8 @@ void Reset()
MPClientFail = 0; MPClientFail = 0;
memset(MPClientReplies, 0, sizeof(MPClientReplies)); memset(MPClientReplies, 0, sizeof(MPClientReplies));
MPLastSeqno = 0xFFFF;
CmdCounter = 0; CmdCounter = 0;
USUntilPowerOn = 0; USUntilPowerOn = 0;
@ -335,6 +339,8 @@ void DoSavestate(Savestate* file)
file->VarArray(MPClientReplies, sizeof(MPClientReplies)); file->VarArray(MPClientReplies, sizeof(MPClientReplies));
file->Var16(&MPLastSeqno);
file->Var32((u32*)&USUntilPowerOn); file->Var32((u32*)&USUntilPowerOn);
file->Bool32(&ForcePowerOn); file->Bool32(&ForcePowerOn);
@ -591,6 +597,7 @@ void TXSendFrame(TXSlot* slot, int num)
break; break;
case 1: case 1:
*(u16*)&TXBuffer[12 + 24+2] = MPClientMask;
Platform::MP_SendCmd(TXBuffer, 12+len, USTimestamp); Platform::MP_SendCmd(TXBuffer, 12+len, USTimestamp);
break; break;
@ -642,9 +649,11 @@ void StartTX_Cmd()
if (rate == 0x14) slot->Rate = 2; if (rate == 0x14) slot->Rate = 2;
else slot->Rate = 1; else slot->Rate = 1;
MPClientMask = *(u16*)&RAM[slot->Addr + 12 + 24 + 2] & MPClientFail;
MPClientFail &= MPClientMask;
u32 duration = PreambleLen(slot->Rate) + (slot->Length * (slot->Rate==2 ? 4:8)); u32 duration = PreambleLen(slot->Rate) + (slot->Length * (slot->Rate==2 ? 4:8));
u16 clientmask = *(u16*)&RAM[slot->Addr + 12 + 24 + 2] & 0xFFFE; duration += 112 + ((10 + IOPORT(W_CmdReplyTime)) * NumClients(MPClientMask));
duration += 112 + ((10 + IOPORT(W_CmdReplyTime)) * NumClients(clientmask));
duration += (32 * (slot->Rate==2 ? 4:8)); duration += (32 * (slot->Rate==2 ? 4:8));
if (CmdCounter > (duration + 100)) if (CmdCounter > (duration + 100))
@ -711,6 +720,7 @@ void FireTX()
if (txstart & 0x0002) if (txstart & 0x0002)
{ {
MPClientFail = 0xFFFE;
StartTX_Cmd(); StartTX_Cmd();
return; return;
} }
@ -724,7 +734,7 @@ void FireTX()
void SendMPDefaultReply() void SendMPDefaultReply()
{ {
u8 reply[12 + 32]; u8 reply[12 + 28];
*(u16*)&reply[0xA] = 28; // length *(u16*)&reply[0xA] = 28; // length
@ -961,20 +971,17 @@ bool ProcessTX(TXSlot* slot, int num)
} }
SetStatus(5); SetStatus(5);
u16 clientmask = *(u16*)&RAM[slot->Addr + 12 + 24 + 2] & 0xFFFE;
MPReplyTimer = 16 + PreambleLen(slot->Rate); MPReplyTimer = 16 + PreambleLen(slot->Rate);
MPClientMask = clientmask;
MPClientFail = clientmask;
u16 res = 0; u16 res = 0;
if (clientmask) if (MPClientMask)
res = Platform::MP_RecvReplies(MPClientReplies, USTimestamp, clientmask); res = Platform::MP_RecvReplies(MPClientReplies, USTimestamp, MPClientMask);
MPClientFail &= ~res; MPClientFail &= ~res;
// TODO: 112 likely includes the ack preamble, which needs adjusted // TODO: 112 likely includes the ack preamble, which needs adjusted
// for long-preamble settings // for long-preamble settings
slot->CurPhase = 2; slot->CurPhase = 2;
slot->CurPhaseTime = 112 + ((10 + IOPORT(W_CmdReplyTime)) * NumClients(clientmask)); slot->CurPhaseTime = 112 + ((10 + IOPORT(W_CmdReplyTime)) * NumClients(MPClientMask));
break; break;
} }
@ -1051,10 +1058,6 @@ bool ProcessTX(TXSlot* slot, int num)
case 3: // MP host ack transfer (reply wait done) case 3: // MP host ack transfer (reply wait done)
{ {
// checkme
IOPORT(W_TXBusy) &= ~(1<<1);
IOPORT(W_TXSlotCmd) &= 0x7FFF; // confirmed
if (!MPClientFail) if (!MPClientFail)
*(u16*)&RAM[slot->Addr] = 0x0001; *(u16*)&RAM[slot->Addr] = 0x0001;
else else
@ -1072,15 +1075,24 @@ bool ProcessTX(TXSlot* slot, int num)
IOPORT(W_TXStat) = 0x0B01; IOPORT(W_TXStat) = 0x0B01;
SetIRQ(1); SetIRQ(1);
} }
SetStatus(1);
// TODO: retry the whole cycle if some clients failed to respond if (MPClientFail)
// AND if there is enough time left in CMDCOUNT {
// (games seem to always configure CMDCOUNT such that there is no time for retries) // if some clients failed to respond: try again
StartTX_Cmd();
break;
}
else
{
IOPORT(W_TXBusy) &= ~(1<<1);
IOPORT(W_TXSlotCmd) &= 0x7FFF;
SetStatus(1);
SetIRQ(12); SetIRQ(12);
FireTX(); FireTX();
} }
}
return true; return true;
case 13: // MP transfer failed (timeout) case 13: // MP transfer failed (timeout)
@ -1159,6 +1171,7 @@ void FinishRX()
// TODO: RX stats // TODO: RX stats
u16 framectl = *(u16*)&RXBuffer[12]; u16 framectl = *(u16*)&RXBuffer[12];
u16 seqno = *(u16*)&RXBuffer[12 + 22];
// check the frame's destination address // check the frame's destination address
// note: the hardware always checks the first address field, regardless of the frame type/etc // note: the hardware always checks the first address field, regardless of the frame type/etc
@ -1187,6 +1200,7 @@ void FinishRX()
// * MP CMD frames with a duplicate sequence number are ignored // * MP CMD frames with a duplicate sequence number are ignored
u16 rxflags = 0x0010; u16 rxflags = 0x0010;
bool cmd_dupe = false;
switch ((framectl >> 2) & 0x3) switch ((framectl >> 2) & 0x3)
{ {
@ -1288,6 +1302,9 @@ void FinishRX()
} }
else if (MACEqual(&RXBuffer[12 + 4], MPCmdMAC)) else if (MACEqual(&RXBuffer[12 + 4], MPCmdMAC))
{ {
if (seqno == MPLastSeqno) cmd_dupe = true;
MPLastSeqno = seqno;
rxflags |= 0x000C; rxflags |= 0x000C;
} }
else if (MACEqual(&RXBuffer[12 + 4], MPAckMAC)) else if (MACEqual(&RXBuffer[12 + 4], MPAckMAC))
@ -1353,6 +1370,8 @@ void FinishRX()
break; break;
} }
if (!cmd_dupe)
{
// build the RX header // build the RX header
u16 headeraddr = IOPORT(W_RXBufWriteCursor) << 1; u16 headeraddr = IOPORT(W_RXBufWriteCursor) << 1;
@ -1373,6 +1392,7 @@ void FinishRX()
IOPORT(W_RXBufWriteCursor) = (addr & ~0x3) >> 1; IOPORT(W_RXBufWriteCursor) = (addr & ~0x3) >> 1;
SetIRQ(0); SetIRQ(0);
}
if ((rxflags & 0x800F) == 0x800C) if ((rxflags & 0x800F) == 0x800C)
{ {