wifi: proper TX/RX status switch and RX check

readme: little update
This commit is contained in:
StapleButter 2017-06-15 21:41:18 +02:00
parent 49f8aec656
commit 402a60ea34
2 changed files with 167 additions and 98 deletions

View File

@ -15,7 +15,10 @@ melonDS requires BIOS/firmware copies from a DS. Files required:
* bios9.bin, 4KB: ARM9 BIOS
* firmware.bin, 256KB: firmware
Note: the DS-mode firmware in the 3DS isn't bootable, it only contains the bare minimum to run games.
Firmware boot requires a firmware dump from an original DS or DS Lite.
DS firmwares dumped from a DSi or 3DS aren't bootable and only contain configuration data, thus they are only suitable when booting games directly.
DS BIOS dumps from a 3DS can be used with no compatibility issues. DSi BIOS dumps should be usable too, provided they were dumped properly.
As for the rest, the interface should be pretty straightforward. If you have a question, don't hesitate to ask, though!

View File

@ -67,6 +67,10 @@ u8 RXBuffer[2048];
u32 RXTime;
u16 RXEndAddr;
u32 ComStatus; // 0=waiting for packets 1=receiving 2=sending
u32 TXCurSlot;
u32 RXCounter;
bool MPInited;
@ -75,10 +79,11 @@ bool MPInited;
// 1. preamble
// 2. IRQ7
// 3. send data
// 4. wait for client replies (duration: 112 + ((10 * CMD_REPLYTIME) * numclients))
// 5. IRQ7
// 6. send ack (16 bytes, 1Mbps)
// 7. optional IRQ1, along with IRQ12 if the transfer was successful or if
// 4. optional IRQ1
// 5. wait for client replies (duration: 112 + ((10 * CMD_REPLYTIME) * numclients))
// 6. IRQ7
// 7. send ack (16 bytes, 1Mbps)
// 8. optional IRQ1, along with IRQ12 if the transfer was successful or if
// there's no time left for a retry
//
// if the transfer has to be retried (for example, didn't get replies from all clients)
@ -89,14 +94,14 @@ bool MPInited;
//
// RFSTATUS values:
// 0 = initial
// 1 = RX????
// 1 = waiting for incoming packets
// 2 = switching from RX to TX
// 3 = TX
// 4 = switching from TX to RX
// 5 = MP host data sent, waiting for replies (RFPINS=0x0084)
// 6 = RX
// 7 = ??
// 8 = MP host sending ack (RFPINS=0x0046)
// 8 = MP client sending reply, MP host sending ack (RFPINS=0x0046)
// 9 = idle
@ -176,6 +181,10 @@ void Reset()
USCompare = 0;
BlockBeaconIRQ14 = false;
ComStatus = 0;
TXCurSlot = -1;
RXCounter = 0;
CmdCounter = 0;
}
@ -427,12 +436,12 @@ u32 NumClients(u16 bitmask)
return ret;
}
void CheckRX(bool block);
bool CheckRX(bool block);
void ProcessTX(TXSlot* slot, int num)
bool ProcessTX(TXSlot* slot, int num)
{
slot->CurPhaseTime--;
if (slot->CurPhaseTime > 0) return;
if (slot->CurPhaseTime > 0) return false;
switch (slot->CurPhase)
{
@ -448,13 +457,13 @@ void ProcessTX(TXSlot* slot, int num)
// CHECKME
// hardware seems to do this automatically?
// I saw it done on captured packets, but saw no code to do it
if (num == 1)
/*if (num == 1)
{
if (slot->Length > 32)
{
*(u16*)&RAM[slot->Addr + 0xC + (slot->Length-6)] = *(u16*)&RAM[slot->Addr + 0x26];
}
}
}*/
if (num != 5) SetIRQ(7);
*(u16*)&RAM[slot->Addr + 0xC + 22] = IOPORT(W_TXSeqNo) << 4;
@ -480,7 +489,7 @@ void ProcessTX(TXSlot* slot, int num)
slot->CurPhase = 2;
slot->CurPhaseTime = 112 + ((10 + IOPORT(W_CmdReplyTime)) * nclients);
printf("tx done. listen to replies\n");
CheckRX(true);
if (CheckRX(true)) ComStatus |= 0x2;
// TODO: RFSTATUS/RFPINS
@ -517,7 +526,7 @@ printf("tx done. listen to replies\n");
FireTX();
}
break;
return true;
case 2: // MP host transfer done
{
@ -554,103 +563,107 @@ printf("tx done. listen to replies\n");
printf("MP TX over\n");
FireTX();
}
break;
return true;
}
return false;
}
void CheckRX(bool block)
bool CheckRX(bool block)
{
if (!(IOPORT(W_RXCnt) & 0x8000))
return;
return false;
int rxlen = Platform::MP_RecvPacket(RXBuffer, block);
if (rxlen < 12+24) return;
u16 framelen;
u16 framectl;
u8 txrate;
bool bssidmatch;
u16 rxflags;
u16 framelen = *(u16*)&RXBuffer[10];
if (framelen != rxlen-12)
for (;;)
{
printf("bad frame length\n");
return;
}
framelen -= 4;
int rxlen = Platform::MP_RecvPacket(RXBuffer, block);
if (rxlen == 0) return false;
if (rxlen < 12+24) continue;
/*if (RXTime > 0)
{
printf("!! getting packet while already receiving\n");
return;
}
if (IOPORT(W_TXBusy) & 0x9D)
{
printf("!! getting packet while sending\n");
return;
}*/
u16 framectl = *(u16*)&RXBuffer[12+0];
u8 txrate = RXBuffer[8];
u32 a_src, a_dst, a_bss;
u16 rxflags = 0x0010;
switch (framectl & 0x000C)
{
case 0x0000: // management
a_src = 10;
a_dst = 4;
a_bss = 16;
if ((framectl & 0x00F0) == 0x0080)
rxflags |= 0x0001;
break;
case 0x0004: // control
printf("blarg\n");
return;
case 0x0008: // data
switch (framectl & 0x0300)
framelen = *(u16*)&RXBuffer[10];
if (framelen != rxlen-12)
{
case 0x0000: // STA to STA
printf("bad frame length\n");
continue;
}
framelen -= 4;
framectl = *(u16*)&RXBuffer[12+0];
txrate = RXBuffer[8];
u32 a_src, a_dst, a_bss;
rxflags = 0x0010;
switch (framectl & 0x000C)
{
case 0x0000: // management
a_src = 10;
a_dst = 4;
a_bss = 16;
if ((framectl & 0x00F0) == 0x0080)
rxflags |= 0x0001;
break;
case 0x0100: // STA to DS
a_src = 10;
a_dst = 16;
a_bss = 4;
break;
case 0x0200: // DS to STA
a_src = 16;
a_dst = 4;
a_bss = 10;
break;
case 0x0300: // DS to DS
case 0x0004: // control
printf("blarg\n");
return;
continue;
case 0x0008: // data
switch (framectl & 0x0300)
{
case 0x0000: // STA to STA
a_src = 10;
a_dst = 4;
a_bss = 16;
break;
case 0x0100: // STA to DS
a_src = 10;
a_dst = 16;
a_bss = 4;
break;
case 0x0200: // DS to STA
a_src = 16;
a_dst = 4;
a_bss = 10;
break;
case 0x0300: // DS to DS
printf("blarg\n");
continue;
}
framectl &= 0xE7FF;
if (framectl == 0x0228) rxflags |= 0x000C;
else if (framectl == 0x0218) rxflags |= 0x000D;
else if (framectl == 0x0118) rxflags |= 0x000E; // checkme
else if (framectl == 0x0158) rxflags |= 0x000F; // wild guess. those two might be swapped
else rxflags |= 0x0008;
break;
}
framectl &= 0xE7FF;
if (framectl == 0x0228) rxflags |= 0x000C;
else if (framectl == 0x0218) rxflags |= 0x000D;
else if (framectl == 0x0118) rxflags |= 0x000E; // checkme
else if (framectl == 0x0158) rxflags |= 0x000F; // wild guess. those two might be swapped
else rxflags |= 0x0008;
if (MACEqual(&RXBuffer[12 + a_src], (u8*)&IOPORT(W_MACAddr0)))
continue; // oops. we received a packet we just sent.
bssidmatch = MACEqual(&RXBuffer[12 + a_bss], (u8*)&IOPORT(W_BSSID0));
if (!(IOPORT(W_BSSID0) & 0x0001) && !(RXBuffer[12 + a_bss] & 0x01) &&
!bssidmatch)
{
printf("received packet %04X but it didn't pass the BSSID check\n", framectl);
continue;
}
break;
}
if (MACEqual(&RXBuffer[12 + a_src], (u8*)&IOPORT(W_MACAddr0)))
return; // oops. we received a packet we just sent.
bool bssidmatch = MACEqual(&RXBuffer[12 + a_bss], (u8*)&IOPORT(W_BSSID0));
if (!(IOPORT(W_BSSID0) & 0x0001) && !(RXBuffer[12 + a_bss] & 0x01) &&
!bssidmatch)
{
printf("received packet %04X but it didn't pass the BSSID check\n", framectl);
return;
}
//if (framectl != 0x0080 && framectl != 0x0228)
printf("wifi: received packet FC:%04X SN:%04X CL:%04X\n", framectl, *(u16*)&RXBuffer[12+4+6+6+6], *(u16*)&RXBuffer[12+4+6+6+6+2+2]);
// make RX header
// TODO: make it upon RX end
if (bssidmatch) rxflags |= 0x8000;
@ -679,7 +692,7 @@ void CheckRX(bool block)
{
printf("wifi: RX buffer full\n");
// TODO: proper error management
return;
return false;
}
}
@ -690,6 +703,7 @@ void CheckRX(bool block)
RXEndAddr = (addr & ~0x3) >> 1;
SetIRQ(6);
return true;
}
@ -735,7 +749,7 @@ void USTimer(u32 param)
if (!uspart) MSTimer();
if (!(uspart & 0x1FF)) CheckRX(false);
//if (!(uspart & 0x1FF)) CheckRX(false);
}
if (IOPORT(W_CmdCountCnt) & 0x0001)
@ -749,17 +763,54 @@ void USTimer(u32 param)
if (IOPORT(W_ContentFree) != 0)
IOPORT(W_ContentFree)--;
u16 txbusy = IOPORT(W_TXBusy);
if (txbusy)
if (ComStatus == 0)
{
if (txbusy & 0x0080) ProcessTX(&TXSlots[5], 5);
else if (txbusy & 0x0010) ProcessTX(&TXSlots[4], 4);
else if (txbusy & 0x0008) ProcessTX(&TXSlots[3], 3);
else if (txbusy & 0x0004) ProcessTX(&TXSlots[2], 2);
else if (txbusy & 0x0002) ProcessTX(&TXSlots[1], 1);
else if (txbusy & 0x0001) ProcessTX(&TXSlots[0], 0);
u16 txbusy = IOPORT(W_TXBusy);
if (txbusy)
{
ComStatus = 0x2;
if (txbusy & 0x0080) TXCurSlot = 5;
else if (txbusy & 0x0010) TXCurSlot = 4;
else if (txbusy & 0x0008) TXCurSlot = 3;
else if (txbusy & 0x0004) TXCurSlot = 2;
else if (txbusy & 0x0002) TXCurSlot = 1;
else if (txbusy & 0x0001) TXCurSlot = 0;
}
else
{
if ((!(RXCounter & 0x1FF)))
{
if (CheckRX(false))
ComStatus = 0x1;
}
RXCounter++;
}
}
if (RXTime)
if (ComStatus & 0x2)
{
bool finished = ProcessTX(&TXSlots[TXCurSlot], TXCurSlot);
if (finished)
{
// transfer finished, see if there's another slot to do
// checkme: priority order of beacon/reply
u16 txbusy = IOPORT(W_TXBusy);
if (txbusy & 0x0080) TXCurSlot = 5;
else if (txbusy & 0x0010) TXCurSlot = 4;
else if (txbusy & 0x0008) TXCurSlot = 3;
else if (txbusy & 0x0004) TXCurSlot = 2;
else if (txbusy & 0x0002) TXCurSlot = 1;
else if (txbusy & 0x0001) TXCurSlot = 0;
else
{
TXCurSlot = -1;
ComStatus = 0;
RXCounter = 0;
}
}
}
if (ComStatus & 0x1)
{
// TODO: make sure it isn't possible to send and receive at the same time
RXTime--;
@ -768,6 +819,12 @@ void USTimer(u32 param)
IOPORT(W_RXBufWriteCursor) = RXEndAddr;
SetIRQ(0);
if (TXCurSlot == -1)
{
ComStatus = 0;
RXCounter = 0;
}
if ((RXBuffer[0] & 0x0F) == 0x0C)
{
u16 clientmask = *(u16*)&RXBuffer[0xC + 26];
@ -914,6 +971,10 @@ u16 Read(u32 addr)
}
}
break;
case W_TXBusy:
return IOPORT(W_TXBusy) & 0x001F; // no bit for MP replies. odd
//case 0x214: NDS::debug(0); break;
//case 0x040: NDS::debug(0); break;
//case 0x54: printf("wifi: read WRCSR -> %04X\n", IOPORT(0x54)); break;
@ -1198,6 +1259,11 @@ void Write(u32 addr, u16 val)
addr, val, IOPORT(W_TXReqRead), (u32)(USCounter-mpreplywindow));
break;
case 0x228:
case 0x244:
printf("wifi: write port%03X %04X\n", addr, val);
break;
// read-only ports
case 0x000:
case 0x044: