From d383d0f5aa4450ea7159eb0fc0b58a896d4d2555 Mon Sep 17 00:00:00 2001 From: luigi__ Date: Thu, 16 Jun 2011 15:36:08 +0000 Subject: [PATCH] Wifi: proper queuing of received packets, emulate TX/RX delays, and misc extra accuracy. Also removed a bunch of redundant code. NSMB gets one step further. When Luigi receives Mario's data frames, he tries to use port 094 (REPLY1) to respond, but only writes zero there for whatever reason. --- desmume/src/NDSSystem.cpp | 2 +- desmume/src/saves.cpp | 18 +- desmume/src/wifi.cpp | 800 +++++++++++++++----------------------- desmume/src/wifi.h | 77 ++-- 4 files changed, 358 insertions(+), 539 deletions(-) diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index 9569c9f6f..62f1f14ce 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -1375,7 +1375,7 @@ static void initSchedule() // ARM7_CLOCK = 33.51 mhz // = 33513982 cycles per second // = 33.513982 cycles per microsecond -const u64 kWifiCycles = 34*2; +const u64 kWifiCycles = 67;//34*2; //(this isn't very precise. I don't think it needs to be) void Sequencer::init() diff --git a/desmume/src/saves.cpp b/desmume/src/saves.cpp index ebfa6306b..4c6977c75 100644 --- a/desmume/src/saves.cpp +++ b/desmume/src/saves.cpp @@ -292,6 +292,7 @@ static void mmu_savestate(EMUFILE* os) MMU_new.dsi_tsc.save_state(os); } +// TODO: integrate the new wifi state variables once everything is settled SFORMAT SF_WIFI[]={ { "W000", 4, 1, &wifiMac.powerOn}, { "W010", 4, 1, &wifiMac.powerOnPending}, @@ -306,17 +307,8 @@ SFORMAT SF_WIFI[]={ { "W070", 2, 1, &wifiMac.wepMode}, { "W080", 4, 1, &wifiMac.WEP_enable}, - { "W090", 2, 3, &wifiMac.TXSlot[0]}, { "W100", 2, 1, &wifiMac.TXCnt}, - { "W110", 2, 1, &wifiMac.TXOpt}, { "W120", 2, 1, &wifiMac.TXStat}, - { "W130", 2, 1, &wifiMac.BeaconAddr}, - { "W140", 4, 1, &wifiMac.BeaconEnable}, - { "W150", 1, 1, &wifiMac.txCurSlot}, - { "W160", 1, 3, &wifiMac.txSlotBusy[0]}, - { "W170", 4, 3, &wifiMac.txSlotAddr[0]}, - { "W180", 4, 3, &wifiMac.txSlotLen[0]}, - { "W190", 4, 3, &wifiMac.txSlotRemainingBytes[0]}, { "W200", 2, 1, &wifiMac.RXCnt}, { "W210", 2, 1, &wifiMac.RXCheckCounter}, @@ -371,18 +363,10 @@ SFORMAT SF_WIFI[]={ { "W530", 2, 1, &wifiMac.CircBufWrEnd}, { "W540", 2, 1, &wifiMac.CircBufWrSkip}, - { "W550", 4, 1, &wifiMac.curPacketSize[0]}, - { "W560", 4, 1, &wifiMac.curPacketPos[0]}, - { "W570", 4, 1, &wifiMac.curPacketSending[0]}, - { "W580", 2, 0x800, &wifiMac.IOPorts[0]}, { "W590", 2, 1, &wifiMac.randomSeed}, { "WX00", 8, 1, &SoftAP.usecCounter}, - { "WX10", 1, 4096, &SoftAP.curPacket[0]}, - { "WX20", 4, 1, &SoftAP.curPacketSize}, - { "WX30", 4, 1, &SoftAP.curPacketPos}, - { "WX40", 4, 1, &SoftAP.curPacketSending}, { 0 } }; diff --git a/desmume/src/wifi.cpp b/desmume/src/wifi.cpp index 52955573e..806849110 100644 --- a/desmume/src/wifi.cpp +++ b/desmume/src/wifi.cpp @@ -71,6 +71,7 @@ pcap_t *wifi_bridge = NULL; wifimac_t wifiMac; Adhoc_t Adhoc; SoftAP_t SoftAP; +int wifi_lastmode; /******************************************************************************* @@ -302,7 +303,7 @@ WifiComInterface* wifiCom; // 3: medium logging, for debugging, shows lots of stuff // 4: high logging, for debugging, shows almost everything, may slow down // 5: highest logging, for debugging, shows everything, may slow down a lot -#define WIFI_LOGGING_LEVEL 1 +#define WIFI_LOGGING_LEVEL 2 #define WIFI_LOG_USE_LOGC 0 @@ -574,7 +575,7 @@ u8 WIFI_getBB_DATA() *******************************************************************************/ -static void WIFI_BeaconTXStart(); +static void WIFI_TXStart(u32 slot); static void WIFI_triggerIRQMask(u16 mask) { @@ -594,13 +595,12 @@ static void WIFI_triggerIRQ(u8 irq) switch (irq) { case WIFI_IRQ_TXSTART: - wifiMac.TXSeqNo++; break; case WIFI_IRQ_TIMEPREBEACON: if (wifiMac.TXPower & 0x0001) { - wifiMac.rfStatus = 1; - wifiMac.rfPins = 0x0084; + //wifiMac.rfStatus = 1; + //wifiMac.rfPins = 0x0084; } break; case WIFI_IRQ_TIMEBEACON: @@ -611,7 +611,7 @@ static void WIFI_triggerIRQ(u8 irq) wifiMac.BeaconCount2 = 0xFFFF; wifiMac.TXCnt &= 0xFFF2; - WIFI_BeaconTXStart(); + WIFI_TXStart(WIFI_TXSLOT_BEACON); if (wifiMac.ListenCount == 0) wifiMac.ListenCount = wifiMac.ListenInterval; wifiMac.ListenCount--; @@ -620,13 +620,12 @@ static void WIFI_triggerIRQ(u8 irq) case WIFI_IRQ_TIMEPOSTBEACON: if (wifiMac.TXPower & 0x0002) { - wifiMac.rfStatus = 9; - wifiMac.rfPins = 0x0004; + //wifiMac.rfStatus = 9; + //wifiMac.rfPins = 0x0004; } break; case WIFI_IRQ_UNK: - WIFI_LOG(2, "IRQ 12 triggered.\n"); - wifiMac.TXSeqNo++; + WIFI_LOG(3, "IRQ 12 triggered.\n"); break; } @@ -636,52 +635,52 @@ static void WIFI_triggerIRQ(u8 irq) bool WIFI_Init() { - memset(&wifiMac, 0, sizeof(wifimac_t)); - WIFI_initCRC32Table(); - - WIFI_resetRF(&wifiMac.RF); - - wifiMac.powerOn = FALSE; - wifiMac.powerOnPending = FALSE; - - wifiMac.rfStatus = 0x0000; - wifiMac.rfPins = 0x0004; - - if((u32)CommonSettings.wifi.mode >= ARRAY_SIZE(wifiComs)) - CommonSettings.wifi.mode = 0; - wifiCom = wifiComs[CommonSettings.wifi.mode]; - if(wifiCom) - wifiCom->Init(); - - bWFCUserWarned = false; - + wifi_lastmode = -999; + WIFI_Reset(); return true; } void WIFI_DeInit() { - if(wifiCom) - wifiCom->DeInit(); + if (wifiCom) wifiCom->DeInit(); } void WIFI_Reset() { - memset(&wifiMac, 0, sizeof(wifimac_t)); + //memset(&wifiMac, 0, sizeof(wifimac_t)); WIFI_resetRF(&wifiMac.RF); + memset(wifiMac.IOPorts, 0, sizeof(wifiMac.IOPorts)); + + wifiMac.crystalEnabled = FALSE; wifiMac.powerOn = FALSE; wifiMac.powerOnPending = FALSE; + + wifiMac.usec = wifiMac.ucmp = 0ULL; - wifiMac.rfStatus = 0x0000; - wifiMac.rfPins = 0x0004; + //wifiMac.rfStatus = 0x0000; + //wifiMac.rfPins = 0x0004; + wifiMac.rfStatus = 0x0009; + wifiMac.rfPins = 0x00C6; + + memset(wifiMac.TXSlots, 0, sizeof(wifiMac.TXSlots)); + wifiMac.TXCurSlot = -1; + wifiMac.TXCnt = wifiMac.TXStat = wifiMac.TXSeqNo = wifiMac.TXBusy = 0; + while (!wifiMac.RXPacketQueue.empty()) + wifiMac.RXPacketQueue.pop(); if((u32)CommonSettings.wifi.mode >= ARRAY_SIZE(wifiComs)) CommonSettings.wifi.mode = 0; + if (wifiCom && (wifi_lastmode != CommonSettings.wifi.mode)) + wifiCom->DeInit(); wifiCom = wifiComs[CommonSettings.wifi.mode]; - if(wifiCom) + if (wifiCom && (wifi_lastmode != CommonSettings.wifi.mode)) + wifiCom->Init(); + else wifiCom->Reset(); + wifi_lastmode = CommonSettings.wifi.mode; bWFCUserWarned = false; } @@ -704,8 +703,10 @@ INLINE u16 WIFI_GetRXFlags(u8* packet) break; case 0x0008: // Data frame - if (frameCtl == 0x0228) + if ((frameCtl & 0xE7FF) == 0x0228) ret |= 0x000C; + else if ((frameCtl & 0xE7FF) == 0x0218) + ret |= 0x000D; else ret |= 0x0008; break; @@ -717,8 +718,6 @@ INLINE u16 WIFI_GetRXFlags(u8* packet) if (!memcmp(&packet[10], &wifiMac.bss.bytes[0], 6)) ret |= 0x8000; - //printf("----- Computing RX flags for received frame: FrameCtl = %04X, Flags = %04X -----\n", frameCtl, ret); - return ret; } @@ -726,20 +725,19 @@ INLINE void WIFI_MakeRXHeader(u8* buf, u16 flags, u16 xferRate, u16 len, u8 maxR { *(u16*)&buf[0] = flags; - // Unknown (usually 0x0040) - buf[2] = 0x40; - buf[3] = 0x00; + // Unknown, seems to always be 0x0040 + // except with from-DS-to-STA data+cfpoll frames (0228) + *(u16*)&buf[2] = ((flags & 0xF) == 0xC) ? 0x0000 : 0x0040; - // Time since last packet??? Random??? Left unchanged??? - buf[4] = 0x01; - buf[5] = 0x00; + // seems to always be zero (or just left unchanged) + *(u16*)&buf[4] = 0x0000; *(u16*)&buf[6] = xferRate; - *(u16*)&buf[8] = len; - buf[10] = 253;//maxRSSI; - buf[11] = 255;//minRSSI; + // idk about those, really + buf[10] = 0x20;//maxRSSI; + buf[11] = 0xA0;//minRSSI; } #ifdef EXPERIMENTAL_WIFI_COMM @@ -747,40 +745,42 @@ static void WIFI_RXPutWord(u16 val) { /* abort when RX data queuing is not enabled */ if (!(wifiMac.RXCnt & 0x8000)) return; - /* abort when ringbuffer is full */ - //if (wifiMac.RXReadCursor == wifiMac.RXWriteCursor) return; - /*if(wifiMac.RXWriteCursor >= wifiMac.RXReadCursor) - { - printf("WIFI: write cursor (%04X) above READCSR (%04X). Cannot write received packet.\n", - wifiMac.RXWriteCursor, wifiMac.RXReadCursor); - return; - }*/ /* write the data to cursor position */ wifiMac.RAM[wifiMac.RXWriteCursor & 0xFFF] = val; -// printf("wifi: written word %04X to circbuf addr %04X\n", val, (wifiMac.RXWriteCursor << 1)); + //printf("wifi: written word %04X to circbuf addr %04X\n", val, (wifiMac.RXWriteCursor << 1)); /* move cursor by one */ //printf("written one word to %04X (start %04X, end %04X), ", wifiMac.RXWriteCursor, wifiMac.RXRangeBegin, wifiMac.RXRangeEnd); wifiMac.RXWriteCursor++; + /* wrap around */ -// wifiMac.RXWriteCursor %= (wifiMac.RXRangeEnd - wifiMac.RXRangeBegin) >> 1; -// printf("new addr=%04X\n", wifiMac.RXWriteCursor); - if(wifiMac.RXWriteCursor >= ((wifiMac.RXRangeEnd & 0x1FFE) >> 1)) - wifiMac.RXWriteCursor = ((wifiMac.RXRangeBegin & 0x1FFE) >> 1); + if(wifiMac.RXWriteCursor >= (wifiMac.RXRangeEnd >> 1)) + wifiMac.RXWriteCursor = (wifiMac.RXRangeBegin >> 1); + + wifiMac.RXTXAddr = wifiMac.RXWriteCursor; +} + +static void WIFI_RXQueuePacket(u8* packet, u32 len) +{ + if (!(wifiMac.RXCnt & 0x8000)) return; + + Wifi_RXPacket pkt; + pkt.Data = packet; + pkt.RemHWords = (len - 11) >> 1; + pkt.CurOffset = 12; + pkt.NotStarted = true; + wifiMac.RXPacketQueue.push(pkt); } #endif -static void WIFI_TXStart(u8 slot) +static void WIFI_TXStart(u32 slot) { WIFI_LOG(3, "TX slot %i trying to send a packet: TXCnt = %04X, TXBufLoc = %04X\n", - slot, wifiMac.TXCnt, wifiMac.TXSlot[slot]); + slot, wifiMac.TXCnt, wifiMac.TXSlots[slot].RegVal); - if (BIT15(wifiMac.TXSlot[slot])) /* is slot enabled? */ + u16 reg = wifiMac.TXSlots[slot].RegVal; + if (BIT15(reg)) { - //printf("send packet at %08X, lr=%08X\n", NDS_ARM7.instruct_adr, NDS_ARM7.R[14]); - u16 txLen; - // the address has to be somewhere in the circular buffer, so drop the other bits - u16 address = (wifiMac.TXSlot[slot] & 0x0FFF); - // is there even enough space for the header (6 hwords) in the tx buffer? + u16 address = reg & 0x0FFF; if (address > 0x1000-6) { WIFI_LOG(1, "TX slot %i trying to send a packet overflowing from the TX buffer (address %04X). Attempt ignored.\n", @@ -788,200 +788,44 @@ static void WIFI_TXStart(u8 slot) return; } - //printf("---------- SENDING A PACKET ON SLOT %i, FrameCtl = %04X ----------\n", - // slot, wifiMac.RAM[address+6]); - - // 12 byte header TX Header: http://www.akkit.org/info/dswifi.htm#FmtTx - txLen = wifiMac.RAM[address+5]; - // zero length - if (txLen == 0) + u16 txLen = wifiMac.RAM[address+5] & 0x3FFF; + if (txLen == 0) // zero length { WIFI_LOG(1, "TX slot %i trying to send a packet with length field set to zero. Attempt ignored.\n", slot); return; } - // Align packet length - txLen = WIFI_alignedLen(txLen); - - // unsupported txRate - switch (wifiMac.RAM[address+4] & 0xFF) - { - case 10: // 1 mbit - case 20: // 2 mbit - break; - default: // other rates - WIFI_LOG(1, "TX slot %i trying to send a packet with transfer rate field set to an invalid value of %i. Attempt ignored.\n", - slot, wifiMac.RAM[address+4] & 0xFF); - return; - } + u32 timemask = ((wifiMac.RAM[address+4] & 0xFF) == 20) ? 7 : 15; // Set sequence number if required - if (!BIT13(wifiMac.TXSlot[slot])) + if ((!BIT13(reg)) || (slot == WIFI_TXSLOT_BEACON)) { - // u16 seqctl = wifiMac.RAM[address + 6 + 22]; - // wifiMac.RAM[address + 6 + 11] = (seqctl & 0x000F) | (wifiMac.TXSeqNo << 4); wifiMac.RAM[address + 6 + 11] = wifiMac.TXSeqNo << 4; + wifiMac.TXSeqNo++; + if (slot == WIFI_TXSLOT_MPCMD) wifiMac.TXSeqNo++; } + // Set timestamp (for beacons only) + if (slot == WIFI_TXSLOT_BEACON) + *(u64*)&wifiMac.RAM[address + 6 + 12] = wifiMac.usec; + // Calculate and set FCS u32 crc32 = WIFI_calcCRC32((u8*)&wifiMac.RAM[address + 6], txLen - 4); *(u32*)&wifiMac.RAM[address + 6 + ((txLen-4) >> 1)] = crc32; + + wifiMac.TXSlots[slot].CurAddr = address + 6; + wifiMac.TXSlots[slot].RemHWords = (txLen + 1) >> 1; + wifiMac.TXSlots[slot].RemPreamble = (BIT2(WIFI_IOREG(REG_WIFI_PREAMBLE)) && (timemask == 7)) ? 96 : 192; + wifiMac.TXSlots[slot].TimeMask = timemask; + wifiMac.TXSlots[slot].NotStarted = true; - WIFI_triggerIRQ(WIFI_IRQ_TXSTART); + if (wifiMac.TXCurSlot < 0) + wifiMac.TXCurSlot = slot; + wifiMac.TXBusy |= (1 << slot); - if(slot > wifiMac.txCurSlot) - wifiMac.txCurSlot = slot; - - wifiMac.txSlotBusy[slot] = 1; - wifiMac.txSlotAddr[slot] = address; - wifiMac.txSlotLen[slot] = txLen; - wifiMac.txSlotRemainingBytes[slot] = (txLen + 12); - - wifiMac.RXTXAddr = address; - - wifiMac.rfStatus = 0x0003; - wifiMac.rfPins = 0x0046; - -#if 0 - WIFI_SoftAP_RecvPacketFromDS((u8*)&wifiMac.RAM[address+6], txLen); - WIFI_triggerIRQ(WIFI_IRQ_TXEND); - - wifiMac.RAM[address] = 0x0001; - wifiMac.RAM[address+4] &= 0x00FF; -#endif - } -} - -static void WIFI_ExtraTXStart() -{ - if (BIT15(wifiMac.TXSlotExtra)) - { - u16 txLen; - u16 address = wifiMac.TXSlotExtra & 0x0FFF; - // is there even enough space for the header (6 hwords) in the tx buffer? - if (address > 0x1000-6) - { - return; - } - - //printf("---------- SENDING A PACKET ON EXTRA SLOT, FrameCtl = %04X ----------\n", - // wifiMac.RAM[address+6]); - - // 12 byte header TX Header: http://www.akkit.org/info/dswifi.htm#FmtTx - txLen = wifiMac.RAM[address+5]; - // zero length - if (txLen == 0) - { - return; - } - - // Align packet length - txLen = WIFI_alignedLen(txLen); - - // unsupported txRate - switch (wifiMac.RAM[address+4] & 0xFF) - { - case 10: // 1 mbit - case 20: // 2 mbit - break; - default: // other rates - return; - } - - // Set sequence number if required - if (!BIT13(wifiMac.TXSlotExtra)) - { - //u16 seqctl = wifiMac.RAM[address + 6 + 22]; - //wifiMac.RAM[address + 6 + 11] = (seqctl & 0x000F) | (wifiMac.TXSeqNo << 4); - wifiMac.RAM[address + 6 + 11] = wifiMac.TXSeqNo << 4; - } - - // Calculate and set FCS - u32 crc32 = WIFI_calcCRC32((u8*)&wifiMac.RAM[address + 6], txLen - 4); - *(u32*)&wifiMac.RAM[address + 6 + ((txLen-4) >> 1)] = crc32; - - // Note: Extra transfers trigger two TX start interrupts according to GBATek - WIFI_triggerIRQ(WIFI_IRQ_TXSTART); - if(wifiCom) - wifiCom->SendPacket((u8*)&wifiMac.RAM[address+6], txLen); - WIFI_triggerIRQ(WIFI_IRQ_UNK); - - if (BIT13(wifiMac.TXStatCnt)) - { - WIFI_triggerIRQ(WIFI_IRQ_TXEND); - wifiMac.TXStat = 0x0B01; - } - else if (BIT14(wifiMac.TXStatCnt)) - { - WIFI_triggerIRQ(WIFI_IRQ_TXEND); - wifiMac.TXStat = 0x0801; - } - - wifiMac.TXSlotExtra &= 0x7FFF; - - wifiMac.RAM[address] = 0x0001; - wifiMac.RAM[address+4] &= 0x00FF; - } -} - -static void WIFI_BeaconTXStart() -{ - if (wifiMac.BeaconEnable) - { - u16 txLen; - u16 address = wifiMac.BeaconAddr; - // is there even enough space for the header (6 hwords) in the tx buffer? - if (address > 0x1000-6) - { - return; - } - - // 12 byte header TX Header: http://www.akkit.org/info/dswifi.htm#FmtTx - txLen = wifiMac.RAM[address+5]; - // zero length - if (txLen == 0) - { - return; - } - - // Align packet length - txLen = WIFI_alignedLen(txLen); - - // unsupported txRate - switch (wifiMac.RAM[address+4] & 0xFF) - { - case 10: // 1 mbit - case 20: // 2 mbit - break; - default: // other rates - return; - } - - // Set sequence number - //u16 seqctl = wifiMac.RAM[address + 6 + 22]; - //wifiMac.RAM[address + 6 + 11] = (seqctl & 0x000F) | (wifiMac.TXSeqNo << 4); - wifiMac.RAM[address + 6 + 11] = wifiMac.TXSeqNo << 4; - - // Set timestamp - *(u64*)&wifiMac.RAM[address + 6 + 12] = wifiMac.usec; - - // Calculate and set FCS - u32 crc32 = WIFI_calcCRC32((u8*)&wifiMac.RAM[address + 6], txLen - 4); - *(u32*)&wifiMac.RAM[address + 6 + ((txLen-4) >> 1)] = crc32; - - WIFI_triggerIRQ(WIFI_IRQ_TXSTART); - if(wifiCom) - wifiCom->SendPacket((u8*)&wifiMac.RAM[address+6], txLen); - - if (BIT15(wifiMac.TXStatCnt)) - { - WIFI_triggerIRQ(WIFI_IRQ_TXEND); - wifiMac.TXStat = 0x0301; - } - - wifiMac.RAM[address] = 0x0001; - wifiMac.RAM[address+4] &= 0x00FF; + //wifiMac.rfStatus = 3; + //wifiMac.rfPins = 0x0046; } } @@ -997,7 +841,11 @@ void WIFI_write16(u32 address, u16 val) return; WIFI_LOG(5, "Write at address %08X, %04X\n", address, val); - //printf("WIFI: Write at address %08X, %04X, pc=%08X\n", address, val, NDS_ARM7.instruct_adr); + if (address == 0x04804008 && val == 0x0200) + { + printf("WIFI: Write at address %08X, %04X, pc=%08X\n", address, val, NDS_ARM7.instruct_adr); + emu_halt(); + } // 0x4000 - 0x5FFF: wifi RAM if ((page >= 0x4000) && (page < 0x6000)) @@ -1058,8 +906,10 @@ void WIFI_write16(u32 address, u16 val) wifiMac.aid = 0x0000; WIFI_IOREG(REG_WIFI_RETRYLIMIT) = 0x0707; WIFI_IOREG(0x02E) = 0x0000; - wifiMac.RXRangeBegin = 0x4000; - wifiMac.RXRangeEnd = 0x4800; + WIFI_IOREG(REG_WIFI_RXRANGEBEGIN) = 0x4000; + WIFI_IOREG(REG_WIFI_RXRANGEEND) = 0x4800; + wifiMac.RXRangeBegin = 0x0000; // 0x4000 + wifiMac.RXRangeEnd = 0x0800; // 0x4800 WIFI_IOREG(0x084) = 0x0000; WIFI_IOREG(REG_WIFI_PREAMBLE) = 0x0001; WIFI_IOREG(REG_WIFI_RXFILTER) = 0x0401; @@ -1136,21 +986,27 @@ void WIFI_write16(u32 address, u16 val) break; case REG_WIFI_RXCNT: wifiMac.RXCnt = val & 0xFF0E; - if(BIT0(val)) + if (BIT0(val)) { wifiMac.RXWriteCursor = WIFI_IOREG(REG_WIFI_WRITECSRLATCH); WIFI_IOREG(REG_WIFI_RXHWWRITECSR) = wifiMac.RXWriteCursor; } + if (BIT7(val)) + { + WIFI_LOG(2, "TXBUF_REPLY=%04X\n", WIFI_IOREG(REG_WIFI_TXBUF_REPLY1)); + wifiMac.TXSlots[WIFI_TXSLOT_MPREPLY].RegVal = WIFI_IOREG(REG_WIFI_TXBUF_REPLY1); + WIFI_IOREG(REG_WIFI_TXBUF_REPLY1) = 0x0000; + } break; case REG_WIFI_RXRANGEBEGIN: - wifiMac.RXRangeBegin = val; - if(wifiMac.RXWriteCursor < ((val & 0x1FFE) >> 1)) - wifiMac.RXWriteCursor = ((val & 0x1FFE) >> 1); + wifiMac.RXRangeBegin = val & 0x1FFE; + if(wifiMac.RXWriteCursor < (wifiMac.RXRangeBegin >> 1)) + wifiMac.RXWriteCursor = (wifiMac.RXRangeBegin >> 1); break; case REG_WIFI_RXRANGEEND: - wifiMac.RXRangeEnd = val; - if(wifiMac.RXWriteCursor >= ((val & 0x1FFE) >> 1)) - wifiMac.RXWriteCursor = ((wifiMac.RXRangeBegin & 0x1FFE) >> 1); + wifiMac.RXRangeEnd = val & 0x1FFE; + if(wifiMac.RXWriteCursor >= (wifiMac.RXRangeEnd >> 1)) + wifiMac.RXWriteCursor = (wifiMac.RXRangeBegin >> 1); break; case REG_WIFI_CIRCBUFRADR: @@ -1180,55 +1036,37 @@ void WIFI_write16(u32 address, u16 val) case REG_WIFI_CIRCBUFWR_SKIP: wifiMac.CircBufWrSkip = val; break; - case REG_WIFI_TXLOCBEACON: - wifiMac.BeaconAddr = val & 0x0FFF; - wifiMac.BeaconEnable = BIT15(val); - if (wifiMac.BeaconEnable) + case REG_WIFI_TXBUF_BEACON: + wifiMac.TXSlots[WIFI_TXSLOT_BEACON].RegVal = val; + if (BIT15(val)) WIFI_LOG(3, "Beacon transmission enabled to send the packet at %08X every %i milliseconds.\n", - 0x04804000 + (wifiMac.BeaconAddr << 1), wifiMac.BeaconInterval); + 0x04804000 + ((val & 0x0FFF) << 1), wifiMac.BeaconInterval); break; - case REG_WIFI_TXLOCEXTRA: - wifiMac.TXSlotExtra = val; - WIFI_LOG(2, "Write to port %03X: %04X\n", address, val); + case REG_WIFI_TXBUF_CMD: + wifiMac.TXSlots[WIFI_TXSLOT_MPCMD].RegVal = val; break; - case 0x094: - // printf("write to 094 port\n"); + case REG_WIFI_TXBUF_LOC1: + wifiMac.TXSlots[WIFI_TXSLOT_LOC1].RegVal = val; break; - case 0x098: - case 0x0C0: - case 0x0C4: - case 0x0C8: - case 0x244: - case 0x228: - case 0x290: - case 0x1A0: - case 0x1A2: - case 0x1A4: - case 0x194: - WIFI_LOG(2, "Write to port %03X: %04X\n", address, val); + case REG_WIFI_TXBUF_LOC2: + wifiMac.TXSlots[WIFI_TXSLOT_LOC2].RegVal = val; break; - case REG_WIFI_TXLOC1: - case REG_WIFI_TXLOC2: - case REG_WIFI_TXLOC3: - wifiMac.TXSlot[(address - REG_WIFI_TXLOC1) >> 2] = val; - WIFI_LOG(2, "Write to port %03X: %04X\n", address, val); + case REG_WIFI_TXBUF_LOC3: + wifiMac.TXSlots[WIFI_TXSLOT_LOC3].RegVal = val; break; case REG_WIFI_TXRESET: WIFI_LOG(3, "Write to TXRESET: %04X\n", val); - //if (val & 0x0001) wifiMac.TXSlot[0] &= 0x7FFF; - //if (val & 0x0004) wifiMac.TXSlot[1] &= 0x7FFF; - //if (val & 0x0008) wifiMac.TXSlot[2] &= 0x7FFF; break; case REG_WIFI_TXREQ_RESET: wifiMac.TXCnt &= ~val; break; case REG_WIFI_TXREQ_SET: wifiMac.TXCnt |= val; - if (BIT0(val)) WIFI_TXStart(0); - if (BIT1(val)) WIFI_ExtraTXStart(); - if (BIT2(val)) WIFI_TXStart(1); - if (BIT3(val)) WIFI_TXStart(2); - //if (val) printf("TXReq: %04X\n", val); + if (BIT0(val)) WIFI_TXStart(WIFI_TXSLOT_LOC1); + if (BIT1(val)) WIFI_TXStart(WIFI_TXSLOT_MPCMD); + if (BIT2(val)) WIFI_TXStart(WIFI_TXSLOT_LOC2); + if (BIT3(val)) WIFI_TXStart(WIFI_TXSLOT_LOC3); + if (val & 0xFFF0) WIFI_LOG(2, "Unknown TXREQ bits set: %04X\n", val); break; case REG_WIFI_RFCNT: WIFI_setRF_CNT(val); @@ -1262,9 +1100,15 @@ void WIFI_write16(u32 address, u16 val) break; case REG_WIFI_USCOMPARE0: wifiMac.ucmp = (wifiMac.ucmp & 0xFFFFFFFFFFFF0000ULL) | (u64)(val & 0xFFFE); - //if (BIT0(val)) - // WIFI_triggerIRQ(14); - // wifiMac.usec = wifiMac.ucmp; + // in NSMB multiplayer, Luigi sets USCOMPARE to the USCOUNTER of Mario, and sets bit0 + // possibly bit0 writes USCOMPARE into USCOUNTER? + // it seems to also trigger IRQ14 + // in NSMB, Luigi sends packets on the first attempt only if we trigger IRQ14 here + if (BIT0(val)) + { + wifiMac.usec = wifiMac.ucmp; + WIFI_triggerIRQ(WIFI_IRQ_TIMEBEACON); + } break; case REG_WIFI_USCOMPARE1: wifiMac.ucmp = (wifiMac.ucmp & 0xFFFFFFFF0000FFFFULL) | (u64)val << 16; @@ -1294,6 +1138,7 @@ void WIFI_write16(u32 address, u16 val) wifiMac.eCountEnable = BIT0(val); break; case REG_WIFI_EXTRACOUNT: + WIFI_LOG(3, "EXTRACOUNT=%i (%i µs)\n", val, val*10); wifiMac.eCount = (u32)val * 10; break; case REG_WIFI_LISTENINT: @@ -1394,17 +1239,13 @@ u16 WIFI_read16(u32 address) case REG_WIFI_MAC0: case REG_WIFI_MAC1: case REG_WIFI_MAC2: - //printf("read mac addr: word %i = %02X\n", (address - REG_WIFI_MAC0) >> 1, wifiMac.mac.words[(address - REG_WIFI_MAC0) >> 1]); return wifiMac.mac.words[(address - REG_WIFI_MAC0) >> 1]; case REG_WIFI_BSS0: case REG_WIFI_BSS1: case REG_WIFI_BSS2: - //printf("read bssid addr: word %i = %02X\n", (address - REG_WIFI_BSS0) >> 1, wifiMac.bss.words[(address - REG_WIFI_BSS0) >> 1]); return wifiMac.bss.words[(address - REG_WIFI_BSS0) >> 1]; case REG_WIFI_RXCNT: return wifiMac.RXCnt; - case REG_WIFI_RXRANGEBEGIN: - return wifiMac.RXRangeBegin; case REG_WIFI_CIRCBUFREAD: { u16 val = wifiMac.RAM[wifiMac.CircBufReadAddress >> 1]; @@ -1443,25 +1284,23 @@ u16 WIFI_read16(u32 address) case REG_WIFI_RXBUF_COUNT: return wifiMac.RXBufCount; case REG_WIFI_TXREQ_READ: - //printf("read TX reg %04X\n", address); return wifiMac.TXCnt | 0x10; case REG_WIFI_TXBUSY: - //printf("read TX reg %04X\n", address); - return ((wifiMac.txSlotBusy[0] ? 0x01 : 0x00) | (wifiMac.txSlotBusy[1] ? 0x04 : 0x00) | (wifiMac.txSlotBusy[2] ? 0x08 : 0x00)); + return wifiMac.TXBusy; case REG_WIFI_TXSTAT: - //printf("read TX reg %04X\n", address); return wifiMac.TXStat; - case REG_WIFI_TXLOCEXTRA: - //printf("read TX reg %04X\n", address); - return wifiMac.TXSlotExtra; - case REG_WIFI_TXLOC1: - case REG_WIFI_TXLOC2: - case REG_WIFI_TXLOC3: - //printf("read TX reg %04X\n", address); - return wifiMac.TXSlot[(address - REG_WIFI_TXLOC1) >> 2]; - case REG_WIFI_TXLOCBEACON: - //printf("read TX reg %04X\n", address); - break; + case REG_WIFI_TXBUF_CMD: + return wifiMac.TXSlots[WIFI_TXSLOT_MPCMD].RegVal; + case REG_WIFI_TXBUF_REPLY2: + return wifiMac.TXSlots[WIFI_TXSLOT_MPREPLY].RegVal; + case REG_WIFI_TXBUF_LOC1: + return wifiMac.TXSlots[WIFI_TXSLOT_LOC1].RegVal; + case REG_WIFI_TXBUF_LOC2: + return wifiMac.TXSlots[WIFI_TXSLOT_LOC2].RegVal; + case REG_WIFI_TXBUF_LOC3: + return wifiMac.TXSlots[WIFI_TXSLOT_LOC3].RegVal; + case REG_WIFI_TXBUF_BEACON: + return wifiMac.TXSlots[WIFI_TXSLOT_BEACON].RegVal; case REG_WIFI_EXTRACOUNTCNT: return wifiMac.eCountEnable?1:0; case REG_WIFI_EXTRACOUNT: @@ -1503,13 +1342,18 @@ u16 WIFI_read16(u32 address) // TODO: figure out how to emulate those correctly // without breaking Nintendo's games case REG_WIFI_RFSTATUS: - return 0x0009; + return wifiMac.rfStatus; + //return 9; case REG_WIFI_RFPINS: - return 0x00C6; - - case 0x268: + return wifiMac.rfPins; + //return 0x00C6; + case REG_WIFI_RXTXADDR: return wifiMac.RXTXAddr; + case 0x84: + WIFI_LOG(2, "Read to TXBUF_TIM\n"); + break; + default: // printf("wifi: read unhandled reg %03X\n", address); break; @@ -1536,7 +1380,7 @@ void WIFI_usTrigger() { wifiMac.eCount--; if (wifiMac.eCount == 0) - WIFI_ExtraTXStart(); + WIFI_TXStart(WIFI_TXSLOT_MPCMD); } } @@ -1561,44 +1405,132 @@ void WIFI_usTrigger() } if ((wifiMac.ucmpEnable) && (wifiMac.ucmp == wifiMac.usec)) - { - //printf("ucmp irq14\n"); WIFI_triggerIRQ(WIFI_IRQ_TIMEBEACON); - } - if((wifiMac.usec & 3) == 0) + if (wifiMac.TXCurSlot >= 0) { - int slot = wifiMac.txCurSlot; - - if(wifiMac.txSlotBusy[slot]) + Wifi_TXSlot& slot = wifiMac.TXSlots[wifiMac.TXCurSlot]; + if (slot.RemPreamble > 0) + slot.RemPreamble--; + else if ((wifiMac.usec & slot.TimeMask) == 0) { - wifiMac.txSlotRemainingBytes[slot]--; - wifiMac.RXTXAddr++; - if(wifiMac.txSlotRemainingBytes[slot] == 0) + if (slot.NotStarted) { - wifiMac.txSlotBusy[slot] = 0; - wifiMac.TXSlot[slot] &= 0x7FFF; + WIFI_triggerIRQ(WIFI_IRQ_TXSTART); + if (wifiCom) wifiCom->SendPacket((u8*)&wifiMac.RAM[slot.CurAddr], slot.RemHWords << 1); + slot.NotStarted = false; + } - if(wifiCom) - wifiCom->SendPacket((u8*)&wifiMac.RAM[wifiMac.txSlotAddr[slot]+6], wifiMac.txSlotLen[slot]); + slot.RemHWords--; + slot.CurAddr++; + wifiMac.RXTXAddr = slot.CurAddr; - while((wifiMac.txSlotBusy[wifiMac.txCurSlot] == 0) && (wifiMac.txCurSlot > 0)) - wifiMac.txCurSlot--; + if (slot.RemHWords == 0) + { + if (wifiMac.TXCurSlot == WIFI_TXSLOT_MPCMD) + { + WIFI_triggerIRQ(WIFI_IRQ_UNK); + if (BIT13(wifiMac.TXStatCnt)) + { + WIFI_triggerIRQ(WIFI_IRQ_TXEND); + wifiMac.TXStat = 0x0B01; + } + else if (BIT14(wifiMac.TXStatCnt)) + { + WIFI_triggerIRQ(WIFI_IRQ_TXEND); + wifiMac.TXStat = 0x0801; + } - wifiMac.RAM[wifiMac.txSlotAddr[slot]] = 0x0001; - wifiMac.RAM[wifiMac.txSlotAddr[slot]+4] &= 0x00FF; + slot.RegVal &= 0x7FFF; + } + else if (wifiMac.TXCurSlot == WIFI_TXSLOT_BEACON) + { + if (BIT15(wifiMac.TXStatCnt)) + { + WIFI_triggerIRQ(WIFI_IRQ_TXEND); + wifiMac.TXStat = 0x0301; + } + } + else + { + WIFI_triggerIRQ(WIFI_IRQ_TXEND); + wifiMac.TXStat = 0x0001 | (wifiMac.TXCurSlot == 0 ? 0 : ((wifiMac.TXCurSlot - 1) << 12)); + if (BIT12(slot.RegVal)) wifiMac.TXStat |= 0x0700; - wifiMac.TXStat = (0x0001 | (slot << 12)); - - WIFI_triggerIRQ(WIFI_IRQ_TXEND); + slot.RegVal &= 0x7FFF; + } - //wifiMac.rfStatus = 0x0001; - //wifiMac.rfPins = 0x0084; - wifiMac.rfStatus = 0x0009; - wifiMac.rfPins = 0x0004; + u16 addr = slot.RegVal & 0x0FFF; + wifiMac.RAM[addr] = 0x0001; + wifiMac.RAM[addr+4] &= 0x00FF; - WIFI_LOG(3, "TX slot %i finished sending its packet. Next is slot %i. TXStat = %04X\n", - slot, wifiMac.txCurSlot, wifiMac.TXStat); + wifiMac.TXBusy &= ~(1 << wifiMac.TXCurSlot); + int nextslot = -1; + for (int i = WIFI_TXSLOT_NUM-1; i >= 0; i--) + { + if (BIT_N(wifiMac.TXBusy, i)) + { + nextslot = i; + break; + } + } + + if (nextslot < 0) + { + //wifiMac.rfStatus = 9; + //wifiMac.rfPins = 0x00C6; + wifiMac.TXCurSlot = -1; + } + else + { + wifiMac.TXCurSlot = nextslot; + } + } + } + } + else if (!wifiMac.RXPacketQueue.empty()) + { + if ((wifiMac.usec & 7) == 0) + { + Wifi_RXPacket& pkt = wifiMac.RXPacketQueue.front(); + if (pkt.NotStarted) + { + WIFI_RXPutWord(*(u16*)&pkt.Data[0]); + WIFI_RXPutWord(*(u16*)&pkt.Data[2]); + WIFI_RXPutWord(*(u16*)&pkt.Data[4]); + WIFI_RXPutWord(*(u16*)&pkt.Data[6]); + WIFI_RXPutWord(*(u16*)&pkt.Data[8]); + WIFI_RXPutWord(*(u16*)&pkt.Data[10]); + + WIFI_triggerIRQ(WIFI_IRQ_RXSTART); + pkt.NotStarted = false; + + //wifiMac.rfStatus = 1; + wifiMac.rfPins = 0x00C7; + } + + WIFI_RXPutWord(*(u16*)&pkt.Data[pkt.CurOffset]); + pkt.CurOffset += 2; + pkt.RemHWords--; + + if (pkt.RemHWords == 0) + { + wifiMac.RXWriteCursor = ((wifiMac.RXWriteCursor + 1) & (~1)); + if (wifiMac.RXWriteCursor >= (wifiMac.RXRangeEnd >> 1)) + wifiMac.RXWriteCursor = (wifiMac.RXRangeBegin >> 1); + WIFI_IOREG(REG_WIFI_RXHWWRITECSR) = wifiMac.RXWriteCursor; + + wifiMac.RXNum++; + WIFI_triggerIRQ(WIFI_IRQ_RXEND); + + //if (((*(u16*)&pkt.Data[12]) & 0xE7FF) == 0x0228) + // WIFI_triggerIRQ(WIFI_IRQ_UNK); + + delete[] pkt.Data; + wifiMac.RXPacketQueue.pop(); + + wifiMac.rfStatus = 9; + wifiMac.rfPins = 0x00C6; } } } @@ -1707,7 +1639,7 @@ void Adhoc_SendPacket(u8* packet, u32 len) if (wifi_socket < 0) return; - WIFI_LOG(2, "Ad-hoc: sending a packet of %i bytes, frame control: %04X\n", len, *(u16*)&packet[0]); + WIFI_LOG(3, "Ad-hoc: sending a packet of %i bytes, frame control: %04X\n", len, *(u16*)&packet[0]); u32 frameLen = sizeof(Adhoc_FrameHeader) + len; @@ -1773,7 +1705,7 @@ void Adhoc_usTrigger() if (header.version != ADHOC_PROTOCOL_VERSION) return; - packetLen = header.packetLen; + packetLen = header.packetLen - 4; ptr += sizeof(Adhoc_FrameHeader); // If the packet is for us, send it to the wifi core @@ -1783,44 +1715,19 @@ void Adhoc_usTrigger() WIFI_compareMAC(&ptr[16], &wifiMac.bss.bytes[0]) || WIFI_isBroadcastMAC(&wifiMac.bss.bytes[0])) { - /* printf("packet was for us: mac=%02X:%02X.%02X.%02X.%02X.%02X, bssid=%02X:%02X.%02X.%02X.%02X.%02X\n", - wifiMac.mac.bytes[0], wifiMac.mac.bytes[1], wifiMac.mac.bytes[2], wifiMac.mac.bytes[3], wifiMac.mac.bytes[4], wifiMac.mac.bytes[5], - wifiMac.bss.bytes[0], wifiMac.bss.bytes[1], wifiMac.bss.bytes[2], wifiMac.bss.bytes[3], wifiMac.bss.bytes[4], wifiMac.bss.bytes[5]); - printf("da=%02X:%02X.%02X.%02X.%02X.%02X, sa=%02X:%02X.%02X.%02X.%02X.%02X, bssid=%02X:%02X.%02X.%02X.%02X.%02X\n", - ptr[4], ptr[5], ptr[6], ptr[7], ptr[8], ptr[9], - ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], - ptr[16], ptr[17], ptr[18], ptr[19], ptr[20], ptr[21]);*/ /* WIFI_LOG(3, "Ad-hoc: received a packet of %i bytes from %i.%i.%i.%i (port %i).\n", nbytes, (u8)fromAddr.sa_data[2], (u8)fromAddr.sa_data[3], (u8)fromAddr.sa_data[4], (u8)fromAddr.sa_data[5], ntohs(*(u16*)&fromAddr.sa_data[0]));*/ - WIFI_LOG(2, "Ad-hoc: received a packet of %i bytes, frame control: %04X\n", packetLen, *(u16*)&ptr[0]); + WIFI_LOG(3, "Ad-hoc: received a packet of %i bytes, frame control: %04X\n", packetLen, *(u16*)&ptr[0]); //WIFI_LOG(2, "Storing packet at %08X.\n", 0x04804000 + (wifiMac.RXWriteCursor<<1)); - //if (((*(u16*)&ptr[0]) != 0x0080) && ((*(u16*)&ptr[0]) != 0x0228)) - // printf("received packet, framectl=%04X\n", (*(u16*)&ptr[0])); - - //if ((*(u16*)&ptr[0]) == 0x0228) - // printf("wifi: received fucking packet!\n"); - - WIFI_triggerIRQ(WIFI_IRQ_RXSTART); - u8* packet = new u8[12 + packetLen]; WIFI_MakeRXHeader(packet, WIFI_GetRXFlags(ptr), 20, packetLen, 0, 0); memcpy(&packet[12], ptr, packetLen); - - for (int i = 0; i < (12 + packetLen); i += 2) - { - u16 word = *(u16*)&packet[i]; - WIFI_RXPutWord(word); - } - - wifiMac.RXWriteCursor = ((wifiMac.RXWriteCursor + 1) & (~1)); - WIFI_IOREG(REG_WIFI_RXHWWRITECSR) = wifiMac.RXWriteCursor; - wifiMac.RXNum++; - WIFI_triggerIRQ(WIFI_IRQ_RXEND); + WIFI_RXQueuePacket(packet, 12+packetLen); } } } @@ -1943,15 +1850,6 @@ static pcap_if_t * WIFI_index_device(pcap_if_t *alldevs, int index) bool SoftAP_Init() { - SoftAP.usecCounter = 0; - - SoftAP.curPacketSize = 0; - SoftAP.curPacketPos = 0; - SoftAP.curPacketSending = FALSE; - - SoftAP.status = APStatus_Disconnected; - SoftAP.seqNum = 0; - if (!driver->WIFI_PCapAvailable()) { WIFI_LOG(1, "SoftAP: PCap library not available on your system.\n"); @@ -1988,6 +1886,8 @@ bool SoftAP_Init() return false; } + SoftAP_Reset(); + return true; } @@ -2001,10 +1901,6 @@ void SoftAP_Reset() { SoftAP.usecCounter = 0; - SoftAP.curPacketSize = 0; - SoftAP.curPacketPos = 0; - SoftAP.curPacketSending = FALSE; - SoftAP.status = APStatus_Disconnected; SoftAP.seqNum = 0; } @@ -2052,24 +1948,21 @@ static bool SoftAP_IsDNSRequestToWFC(u16 ethertype, u8* body) static void SoftAP_Deauthenticate() { u32 packetLen = sizeof(SoftAP_DeauthFrame); + u8* packet = new u8[12 + packetLen]; - memcpy(&SoftAP.curPacket[12], SoftAP_DeauthFrame, packetLen); + memcpy(&packet[12], SoftAP_DeauthFrame, packetLen); - memcpy(&SoftAP.curPacket[12 + 4], FW_Mac, 6); // Receiver MAC + memcpy(&packet[12 + 4], FW_Mac, 6); // Receiver MAC - *(u16*)&SoftAP.curPacket[12 + 22] = SoftAP.seqNum << 4; // Sequence number + *(u16*)&packet[12 + 22] = SoftAP.seqNum << 4; // Sequence number SoftAP.seqNum++; u16 rxflags = 0x0010; - if (WIFI_compareMAC(wifiMac.bss.bytes, &SoftAP.curPacket[12 + 16])) + if (WIFI_compareMAC(wifiMac.bss.bytes, &packet[12 + 16])) rxflags |= 0x8000; - WIFI_MakeRXHeader(SoftAP.curPacket, rxflags, 20, packetLen, 0, 0); - - // Let's prepare to send - SoftAP.curPacketSize = packetLen + 12; - SoftAP.curPacketPos = 0; - SoftAP.curPacketSending = TRUE; + WIFI_MakeRXHeader(packet, rxflags, 20, packetLen, 0, 0); + WIFI_RXQueuePacket(packet, 12 + packetLen); SoftAP.status = APStatus_Disconnected; } @@ -2095,24 +1988,27 @@ void SoftAP_SendPacket(u8 *packet, u32 len) case 0x0: // Management frame { u32 packetLen; + u8* rpacket; switch((frameCtl >> 4) & 0xF) { - case 0x4: // Probe request (WFC) + case 0x4: // Probe request { packetLen = sizeof(SoftAP_ProbeResponse); - memcpy(&SoftAP.curPacket[12], SoftAP_ProbeResponse, packetLen); + rpacket = new u8[12 + packetLen]; + memcpy(&rpacket[12], SoftAP_ProbeResponse, packetLen); // Add the timestamp u64 timestamp = SoftAP.usecCounter; - *(u64*)&SoftAP.curPacket[12 + 24] = timestamp; + *(u64*)&rpacket[12 + 24] = timestamp; } break; case 0xB: // Authentication { packetLen = sizeof(SoftAP_AuthFrame); - memcpy(&SoftAP.curPacket[12], SoftAP_AuthFrame, packetLen); + rpacket = new u8[12 + packetLen]; + memcpy(&rpacket[12], SoftAP_AuthFrame, packetLen); SoftAP.status = APStatus_Authenticated; } @@ -2124,7 +2020,8 @@ void SoftAP_SendPacket(u8 *packet, u32 len) return; packetLen = sizeof(SoftAP_AssocResponse); - memcpy(&SoftAP.curPacket[12], SoftAP_AssocResponse, packetLen); + rpacket = new u8[12 + packetLen]; + memcpy(&rpacket[12], SoftAP_AssocResponse, packetLen); SoftAP.status = APStatus_Associated; WIFI_LOG(1, "SoftAP connected!\n"); @@ -2145,21 +2042,17 @@ void SoftAP_SendPacket(u8 *packet, u32 len) return; } - memcpy(&SoftAP.curPacket[12 + 4], FW_Mac, 6); // Receiver MAC + memcpy(&rpacket[12 + 4], FW_Mac, 6); // Receiver MAC - *(u16*)&SoftAP.curPacket[12 + 22] = SoftAP.seqNum << 4; // Sequence number + *(u16*)&rpacket[12 + 22] = SoftAP.seqNum << 4; // Sequence number SoftAP.seqNum++; u16 rxflags = 0x0010; - if (WIFI_compareMAC(wifiMac.bss.bytes, &SoftAP.curPacket[12 + 16])) + if (WIFI_compareMAC(wifiMac.bss.bytes, &rpacket[12 + 16])) rxflags |= 0x8000; - WIFI_MakeRXHeader(SoftAP.curPacket, rxflags, 20, packetLen, 0, 0); // make the RX header - - // Let's prepare to send - SoftAP.curPacketSize = packetLen + 12; - SoftAP.curPacketPos = 0; - SoftAP.curPacketSending = TRUE; + WIFI_MakeRXHeader(rpacket, rxflags, 20, packetLen, 0, 0); // make the RX header + WIFI_RXQueuePacket(rpacket, 12 + packetLen); } break; @@ -2203,25 +2096,22 @@ void SoftAP_SendPacket(u8 *packet, u32 len) INLINE void SoftAP_SendBeacon() { u32 packetLen = sizeof(SoftAP_Beacon); + u8* packet = new u8[12 + packetLen]; - memcpy(&SoftAP.curPacket[12], SoftAP_Beacon, packetLen); // Copy the beacon template + memcpy(&packet[12], SoftAP_Beacon, packetLen); // Copy the beacon template - *(u16*)&SoftAP.curPacket[12 + 22] = SoftAP.seqNum << 4; // Sequence number + *(u16*)&packet[12 + 22] = SoftAP.seqNum << 4; // Sequence number SoftAP.seqNum++; u64 timestamp = SoftAP.usecCounter; - *(u64*)&SoftAP.curPacket[12 + 24] = timestamp; // Timestamp + *(u64*)&packet[12 + 24] = timestamp; // Timestamp u16 rxflags = 0x0011; - if (WIFI_compareMAC(wifiMac.bss.bytes, &SoftAP.curPacket[12 + 16])) + if (WIFI_compareMAC(wifiMac.bss.bytes, &packet[12 + 16])) rxflags |= 0x8000; - WIFI_MakeRXHeader(SoftAP.curPacket, rxflags, 20, packetLen, 0, 0); - - // Let's prepare to send - SoftAP.curPacketSize = packetLen + 12; - SoftAP.curPacketPos = 0; - SoftAP.curPacketSending = TRUE; + WIFI_MakeRXHeader(packet, rxflags, 20, packetLen, 0, 0); + WIFI_RXQueuePacket(packet, 12 + packetLen); } static void SoftAP_RXHandler(u_char* user, const struct pcap_pkthdr* h, const u_char* _data) @@ -2240,20 +2130,9 @@ static void SoftAP_RXHandler(u_char* user, const struct pcap_pkthdr* h, const u_ if (WIFI_compareMAC(&data[6], wifiMac.mac.bytes)) return; - if (SoftAP.curPacketSending) - { - printf("crap we're gonna nuke a packet at %i/%i (%04X) (%04X)\n", SoftAP.curPacketPos, SoftAP.curPacketSize, *(u16*)&SoftAP.curPacket[12], wifiMac.RXWriteCursor<<1); - } - // The packet was for us. Let's process it then. - WIFI_triggerIRQ(WIFI_IRQ_RXSTART); - int wpacketLen = WIFI_alignedLen(26 + 6 + (h->len-14)); - u8 wpacket[2048]; - - //printf("RECEIVED DATA FRAME: len=%i/%i, src=%02X:%02X:%02X:%02X:%02X:%02X, dst=%02X:%02X:%02X:%02X:%02X:%02X, ethertype=%04X\n", - // 24+ (h->caplen-12), 24 + (h->len-12), data[6], data[7], data[8], data[9], data[10], data[11], - // data[0], data[1], data[2], data[3], data[4], data[5], *(u16*)&data[12]); + u8* wpacket = new u8[12 + wpacketLen]; u16 rxflags = 0x0018; if (WIFI_compareMAC(wifiMac.bss.bytes, (u8*)SoftAP_MACAddr)) @@ -2275,64 +2154,17 @@ static void SoftAP_RXHandler(u_char* user, const struct pcap_pkthdr* h, const u_ SoftAP.seqNum++; - // put it in the RX buffer - for (int i = 0; i < (12 + wpacketLen); i += 2) - { - u16 word = *(u16*)&wpacket[i]; - WIFI_RXPutWord(word); - } - - // Done! - wifiMac.RXWriteCursor = ((wifiMac.RXWriteCursor + 1) & (~1)); - WIFI_IOREG(REG_WIFI_RXHWWRITECSR) = wifiMac.RXWriteCursor; - - WIFI_triggerIRQ(WIFI_IRQ_RXEND); + WIFI_RXQueuePacket(wpacket, 12 + wpacketLen); } void SoftAP_usTrigger() { SoftAP.usecCounter++; - // other packets will have priority over beacons - // 'cause they might be only once of them - // whereas there will be sooo much beacons - if(!SoftAP.curPacketSending) // && SoftAP.status != APStatus_Associated) - { - //if(wifiMac.ioMem[0xD0 >> 1] & 0x0400) - { - //zero sez: every 1/10 second? does it have to be precise? this is so costly.. - // Okay for 128 ms then - if((SoftAP.usecCounter & 131071) == 0) - { - SoftAP_SendBeacon(); - } - } - } - - /* Given a connection of 2 megabits per second, */ - /* we take ~4 microseconds to transfer a byte, */ - /* ie ~8 microseconds to transfer a word. */ - if((SoftAP.curPacketSending) && !(SoftAP.usecCounter & 7)) - { - if(SoftAP.curPacketPos == 0) - WIFI_triggerIRQ(WIFI_IRQ_RXSTART); - - u16 word = *(u16*)&SoftAP.curPacket[SoftAP.curPacketPos]; - WIFI_RXPutWord(word); - - SoftAP.curPacketPos += 2; - if(SoftAP.curPacketPos >= SoftAP.curPacketSize) - { - SoftAP.curPacketSize = 0; - SoftAP.curPacketPos = 0; - SoftAP.curPacketSending = FALSE; - - wifiMac.RXWriteCursor = ((wifiMac.RXWriteCursor + 1) & (~1)); - WIFI_IOREG(REG_WIFI_RXHWWRITECSR) = wifiMac.RXWriteCursor; - - WIFI_triggerIRQ(WIFI_IRQ_RXEND); - } - } + //zero sez: every 1/10 second? does it have to be precise? this is so costly.. + // Okay for 128 ms then + if((SoftAP.usecCounter & 131071) == 0) + SoftAP_SendBeacon(); // EXTREMELY EXPERIMENTAL packet receiving code // Can now receive 64 packets per millisecond. Completely arbitrary limit. Todo: tweak if needed. diff --git a/desmume/src/wifi.h b/desmume/src/wifi.h index e5d1a94d7..18c7d3802 100644 --- a/desmume/src/wifi.h +++ b/desmume/src/wifi.h @@ -23,6 +23,8 @@ #include #include "types.h" +#include + #ifdef EXPERIMENTAL_WIFI_COMM #define HAVE_REMOTE @@ -78,17 +80,17 @@ #define REG_WIFI_CIRCBUFWR_SKIP 0x076 // 078 - internal -#define REG_WIFI_TXLOCBEACON 0x080 +#define REG_WIFI_TXBUF_BEACON 0x080 #define REG_WIFI_LISTENCOUNT 0x088 #define REG_WIFI_BEACONPERIOD 0x08C #define REG_WIFI_LISTENINT 0x08E -#define REG_WIFI_TXLOCEXTRA 0x090 -// 094 - ? -// 098 - ? +#define REG_WIFI_TXBUF_CMD 0x090 +#define REG_WIFI_TXBUF_REPLY1 0x094 +#define REG_WIFI_TXBUF_REPLY2 0x098 // 09C - internal -#define REG_WIFI_TXLOC1 0x0A0 -#define REG_WIFI_TXLOC2 0x0A4 -#define REG_WIFI_TXLOC3 0x0A8 +#define REG_WIFI_TXBUF_LOC1 0x0A0 +#define REG_WIFI_TXBUF_LOC2 0x0A4 +#define REG_WIFI_TXBUF_LOC3 0x0A8 #define REG_WIFI_TXREQ_RESET 0x0AC #define REG_WIFI_TXREQ_SET 0x0AE #define REG_WIFI_TXREQ_READ 0x0B0 @@ -165,6 +167,7 @@ #define REG_WIFI_RFSTATUS 0x214 #define REG_WIFI_IF_SET 0x21C #define REG_WIFI_TXSEQNO 0x210 +#define REG_WIFI_RXTXADDR 0x268 #define REG_WIFI_POWERACK 0x2D0 @@ -408,14 +411,34 @@ typedef union #define WIFI_IRQ_TIMEBEACON 14 #define WIFI_IRQ_TIMEPREBEACON 15 -typedef struct +struct Wifi_TXSlot { - bool enabled; - u16 address; + u16 RegVal; - bool sending; - u16 remtime; -} Wifi_TXLoc; + u16 CurAddr; + int RemPreamble; // preamble time in µs + int RemHWords; + u32 TimeMask; // 3 = 2mbps, 7 = 1mbps + bool NotStarted; +}; + +#define WIFI_TXSLOT_LOC1 0 +#define WIFI_TXSLOT_MPCMD 1 +#define WIFI_TXSLOT_LOC2 2 +#define WIFI_TXSLOT_LOC3 3 +#define WIFI_TXSLOT_BEACON 4 +#define WIFI_TXSLOT_MPREPLY 5 +#define WIFI_TXSLOT_NUM 6 + +struct Wifi_RXPacket +{ + u8* Data; + int CurOffset; + int RemHWords; + bool NotStarted; +}; + +typedef std::queue Wifi_RXPacketQueue; enum EAPStatus { @@ -449,28 +472,18 @@ typedef struct /* sending */ u16 TXStatCnt; u16 TXPower; - u16 TXSlot[3]; u16 TXCnt; - u16 TXOpt; u16 TXStat; - u16 BeaconAddr; - BOOL BeaconEnable; - u16 TXSlotExtra; u16 TXSeqNo; - u8 txCurSlot; - u8 txSlotBusy[3]; - u32 txSlotAddr[3]; - u32 txSlotLen[3]; - u32 txSlotRemainingBytes[3]; - bool ExtraSlotBusy; - u16 ExtraSlotAddr; - u16 ExtraSlotLen; - u16 ExtraSlotRemBytes; + Wifi_TXSlot TXSlots[WIFI_TXSLOT_NUM]; + int TXCurSlot; + u16 TXBusy; /* receiving */ u16 RXCnt; u16 RXCheckCounter; u8 RXNum; + Wifi_RXPacketQueue RXPacketQueue; u16 RXTXAddr; @@ -529,11 +542,6 @@ typedef struct u16 CircBufWrEnd; u16 CircBufWrSkip; - /* tx packets */ - s32 curPacketSize[3]; - s32 curPacketPos[3]; - BOOL curPacketSending[3]; - /* I/O ports */ u16 IOPorts[0x800]; @@ -553,11 +561,6 @@ typedef struct { u64 usecCounter; - u8 curPacket[4096]; - s32 curPacketSize; - s32 curPacketPos; - BOOL curPacketSending; - EAPStatus status; u16 seqNum;