diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index c8457f45b..2c80e0ee3 100755 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -1733,7 +1733,7 @@ void Sequencer::execHardware() { if (wifi.isTriggered()) { - WIFI_usTrigger(); + wifiHandler->CommTrigger(); wifi.timestamp += kWifiCycles; } } diff --git a/desmume/src/wifi.cpp b/desmume/src/wifi.cpp index c56023308..d3dcbcce9 100755 --- a/desmume/src/wifi.cpp +++ b/desmume/src/wifi.cpp @@ -754,19 +754,21 @@ static void WIFI_TXStart(const WifiTXLocIndex txSlotIndex, IOREG_W_TXBUF_LOCATIO if (txLocation.TransferRequest != 0) /* is slot enabled? */ { //printf("send packet at %08X, lr=%08X\n", NDS_ARM7.instruct_adr, NDS_ARM7.R[14]); - u16 address = txLocation.HalfwordAddress; - TXPacketHeader &txHeader = (TXPacketHeader &)wifi.RAM[address]; + u32 byteAddress = txLocation.HalfwordAddress << 1; // is there even enough space for the header (6 hwords) in the tx buffer? - if (address > 0x1000-6) + if (byteAddress > (0x2000 - sizeof(TXPacketHeader) - sizeof(WifiFrameControl))) { WIFI_LOG(1, "TX slot %i trying to send a packet overflowing from the TX buffer (address %04X). Attempt ignored.\n", - (int)txSlotIndex, (address << 1)); + (int)txSlotIndex, (int)byteAddress); return; } + + TXPacketHeader &txHeader = (TXPacketHeader &)wifi.RAM[byteAddress]; + const WifiFrameControl &fc = (WifiFrameControl &)wifi.RAM[byteAddress + sizeof(TXPacketHeader)]; //printf("---------- SENDING A PACKET ON SLOT %i, FrameCtl = %04X ----------\n", - // slot, wifiMac.RAM[address+6]); + // slot, wifi.RAM[byteAddress + sizeof(TXPacketHeader)]); // 12 byte header TX Header: http://www.akkit.org/info/dswifi.htm#FmtTx @@ -788,14 +790,26 @@ static void WIFI_TXStart(const WifiTXLocIndex txSlotIndex, IOREG_W_TXBUF_LOCATIO // Set sequence number if required if ( (txSlotIndex == WifiTXLocIndex_BEACON) || (txLocation.IEEESeqCtrl == 0) ) { - // u16 seqctl = wifiMac.RAM[address + 6 + 22]; - // wifiMac.RAM[address + 6 + 11] = (seqctl & 0x000F) | (wifiMac.TXSeqNo << 4); - wifi.RAM[address + 6 + 11] = io.TX_SEQNO.Number << 4; + if (fc.Type == WifiFrameType_Management) + { + WifiMgmtFrameHeader &mgmtHeader = (WifiMgmtFrameHeader &)wifi.RAM[byteAddress + sizeof(TXPacketHeader)]; + mgmtHeader.seqCtl.SequenceNumber = io.TX_SEQNO.Number; + mgmtHeader.seqCtl.FragmentNumber = 0; + } + else if (fc.Type == WifiFrameType_Data) + { + // The frame header may not necessarily be a STA-to-STA header, but all of the data frame headers + // place the sequence number value at the same location in memory, so we can just use the + // STA-to-STA header to represent all of the data frame headers. + WifiDataFrameHeaderSTA2STA &dataHeader = (WifiDataFrameHeaderSTA2STA &)wifi.RAM[byteAddress + sizeof(TXPacketHeader)]; + dataHeader.seqCtl.SequenceNumber = io.TX_SEQNO.Number; + dataHeader.seqCtl.FragmentNumber = 0; + } } - + // Calculate and set FCS - u32 crc32 = WIFI_calcCRC32((u8 *)&wifi.RAM[address + 6], txHeader.length - 4); - *(u32*)&wifi.RAM[address + 6 + ((txHeader.length - 4) >> 1)] = crc32; + u32 crc32 = WIFI_calcCRC32(&wifi.RAM[byteAddress + sizeof(TXPacketHeader)], txHeader.length - 4); + *(u32 *)&wifi.RAM[byteAddress + sizeof(TXPacketHeader) + txHeader.length - 4] = crc32; WIFI_triggerIRQ(WifiIRQ07_TXStart); @@ -826,7 +840,7 @@ static void WIFI_TXStart(const WifiTXLocIndex txSlotIndex, IOREG_W_TXBUF_LOCATIO wifi.txCurrentSlot = WifiTXLocIndex_LOC2; } - io.RXTX_ADDR.HalfwordAddress = address; + io.RXTX_ADDR.HalfwordAddress = byteAddress >> 1; io.RF_STATUS.RFStatus = 0x03; io.RF_PINS.CarrierSense = 0; @@ -835,16 +849,16 @@ static void WIFI_TXStart(const WifiTXLocIndex txSlotIndex, IOREG_W_TXBUF_LOCATIO io.RF_PINS.TX_On = 1; io.RF_PINS.RX_On = 0; #if 0 - WIFI_SoftAP_RecvPacketFromDS((u8 *)&wifi.RAM[address + 6], txHeader.length); + WIFI_SoftAP_RecvPacketFromDS(&wifi.RAM[address + sizeof(TXPacketHeader)], txHeader.length); WIFI_triggerIRQ(WifiIRQ01_TXComplete); - wifi.RAM[address] = 0x0001; - wifi.RAM[address+4] &= 0x00FF; + txHeader.txStatus = 0x0001; + txHeader.UNKNOWN3 = 0; #endif } else if (txSlotIndex == WifiTXLocIndex_CMD) { - wifiHandler->CommSendPacket(txHeader, (u8 *)&wifi.RAM[address + 6]); + wifiHandler->CommSendPacket(txHeader, &wifi.RAM[byteAddress + sizeof(TXPacketHeader)]); WIFI_triggerIRQ(WifiIRQ12_UNKNOWN); // If bit 13 is set, then it has priority over bit 14 @@ -861,15 +875,15 @@ static void WIFI_TXStart(const WifiTXLocIndex txSlotIndex, IOREG_W_TXBUF_LOCATIO txLocation.TransferRequest = 0; - wifi.RAM[address] = 0x0001; - wifi.RAM[address+4] &= 0x00FF; + txHeader.txStatus = 0x0001; + txHeader.UNKNOWN3 = 0; } else if (txSlotIndex == WifiTXLocIndex_BEACON) { // Set timestamp - *(u64*)&wifi.RAM[address + 6 + 12] = io.US_COUNT; + *(u64 *)&wifi.RAM[byteAddress + sizeof(TXPacketHeader) + sizeof(WifiMgmtFrameHeader)] = io.US_COUNT; - wifiHandler->CommSendPacket(txHeader, (u8 *)&wifi.RAM[address + 6]); + wifiHandler->CommSendPacket(txHeader, &wifi.RAM[byteAddress + sizeof(TXPacketHeader)]); if (io.TXSTATCNT.UpdateTXStatBeacon != 0) { @@ -877,8 +891,8 @@ static void WIFI_TXStart(const WifiTXLocIndex txSlotIndex, IOREG_W_TXBUF_LOCATIO io.TXSTAT.value = 0x0301; } - wifi.RAM[address] = 0x0001; - wifi.RAM[address+4] &= 0x00FF; + txHeader.txStatus = 0x0001; + txHeader.UNKNOWN3 = 0; } } } @@ -904,8 +918,7 @@ void WIFI_write16(u32 address, u16 val) if ((page >= 0x4000) && (page < 0x6000)) { /* access to the circular buffer */ - address &= 0x1FFF; - wifi.RAM[address >> 1] = val; + *(u16 *)&wifi.RAM[address & 0x1FFE] = val; return; } @@ -1263,7 +1276,7 @@ void WIFI_write16(u32 address, u16 val) { /* set value into the circ buffer, and move cursor to the next hword on action */ //printf("wifi: circbuf fifo write at %04X, %04X (action=%i)\n", (wifiMac.CircBufWriteAddress & 0x1FFF), val, action); - wifi.RAM[io.TXBUF_WR_ADDR.HalfwordAddress] = val; + *(u16 *)&wifi.RAM[io.TXBUF_WR_ADDR.HalfwordAddress << 1] = val; if (action) { /* move to next hword */ @@ -2296,7 +2309,7 @@ u16 WIFI_read16(u32 address) // 0x4000 - 0x5FFF: wifi RAM if ((page >= 0x4000) && (page < 0x6000)) { - return wifi.RAM[(address & 0x1FFF) >> 1]; + return *(u16 *)&wifi.RAM[address & 0x1FFE]; } // anything else: I/O ports @@ -2430,7 +2443,7 @@ u16 WIFI_read16(u32 address) } } - io.RXBUF_RD_DATA = wifi.RAM[io.RXBUF_RD_ADDR.HalfwordAddress]; + io.RXBUF_RD_DATA = *(u16 *)&wifi.RAM[io.RXBUF_RD_ADDR.HalfwordAddress << 1]; if (io.RXBUF_COUNT.Count > 0) { @@ -2976,195 +2989,6 @@ u16 WIFI_read16(u32 address) return 0xFFFF; } -void WIFI_usTrigger() -{ - WifiData &wifi = wifiHandler->GetWifiData(); - WIFI_IOREG_MAP &io = wifi.io; - - if (io.POWER_US.Disable != 0) - { - // Don't do anything if WiFi isn't powered up. - return; - } - - // a usec has passed - if (io.US_COUNTCNT.EnableCounter != 0) - { - io.US_COUNT++; - } - - // Note: the extra counter is decremented every 10 microseconds. - // To avoid a modulo every microsecond, we multiply the counter - // value by 10 and decrement it every microsecond :) - if (io.CMD_COUNTCNT.EnableCounter != 0) - { - if (wifi.cmdCount_u32 > 0) - { - wifi.cmdCount_u32--; - - if (wifi.cmdCount_u32 == 0) - { - WIFI_TXStart(WifiTXLocIndex_CMD, io.TXBUF_CMD); - } - } - } - - // The beacon counters are in milliseconds - // GBATek says they're decremented every 1024 usecs - if ( !(io.US_COUNT & 1023) ) - { - io.BEACONCOUNT1--; - if ( io.BEACONCOUNT1 == (io.PRE_BEACON >> 10) ) - { - WIFI_triggerIRQ(WifiIRQ15_TimeslotPreBeacon); - } - else if (io.BEACONCOUNT1 == 0) - { - WIFI_triggerIRQ(WifiIRQ14_TimeslotBeacon); - } - - if (io.BEACONCOUNT2 > 0) - { - io.BEACONCOUNT2--; - if (io.BEACONCOUNT2 == 0) - { - WIFI_triggerIRQ(WifiIRQ13_TimeslotPostBeacon); - } - } - } - - if ( (io.US_COMPARECNT.EnableCompare != 0) && (io.US_COMPARE == io.US_COUNT) ) - { - //printf("ucmp irq14\n"); - WIFI_triggerIRQ(WifiIRQ14_TimeslotBeacon); - } - - if (io.CONTENTFREE > 0) - { - io.CONTENTFREE--; - } - - if ((io.US_COUNT & 3) == 0) - { - const WifiTXLocIndex txSlotIndex = wifi.txCurrentSlot; - bool isTXSlotBusy = false; - - switch (txSlotIndex) - { - case WifiTXLocIndex_LOC1: isTXSlotBusy = (io.TXBUSY.Loc1 != 0); break; - //case WifiTXLocIndex_CMD: isTXSlotBusy = (io.TXBUSY.Cmd != 0); break; - case WifiTXLocIndex_LOC2: isTXSlotBusy = (io.TXBUSY.Loc2 != 0); break; - case WifiTXLocIndex_LOC3: isTXSlotBusy = (io.TXBUSY.Loc3 != 0); break; - //case WifiTXLocIndex_BEACON: isTXSlotBusy = (io.TXBUSY.Beacon != 0); break; - - default: - break; - } - - if (isTXSlotBusy) - { - IOREG_W_TXBUF_LOCATION *txBufLocation = NULL; - TXPacketInfo &txPacketInfo = wifiHandler->GetPacketInfoAtSlot(txSlotIndex); - - switch (txSlotIndex) - { - case WifiTXLocIndex_LOC1: txBufLocation = &io.TXBUF_LOC1; break; - //case WifiTXLocIndex_CMD: txBufLocation = &io.TXBUF_CMD; break; - case WifiTXLocIndex_LOC2: txBufLocation = &io.TXBUF_LOC2; break; - case WifiTXLocIndex_LOC3: txBufLocation = &io.TXBUF_LOC3; break; - //case WifiTXLocIndex_BEACON: txBufLocation = &io.TXBUF_BEACON; break; - - default: - break; - } - - txPacketInfo.remainingBytes--; - io.RXTX_ADDR.HalfwordAddress++; - - if (txPacketInfo.remainingBytes == 0) - { - isTXSlotBusy = false; - - switch (txSlotIndex) - { - case WifiTXLocIndex_LOC1: io.TXBUSY.Loc1 = 0; break; - //case WifiTXLocIndex_CMD: io.TXBUSY.Cmd = 0; break; - case WifiTXLocIndex_LOC2: io.TXBUSY.Loc2 = 0; break; - case WifiTXLocIndex_LOC3: io.TXBUSY.Loc3 = 0; break; - //case WifiTXLocIndex_BEACON: io.TXBUSY.Beacon = 0; break; - - default: - break; - } - - txBufLocation->TransferRequest = 0; - - const TXPacketHeader &txHeader = (TXPacketHeader &)wifi.RAM[txBufLocation->HalfwordAddress]; - wifiHandler->CommSendPacket(txHeader, (u8 *)&wifi.RAM[txBufLocation->HalfwordAddress+6]); - - wifi.RAM[txBufLocation->HalfwordAddress] = 0x0001; - wifi.RAM[txBufLocation->HalfwordAddress+4] &= 0x00FF; - - switch (txSlotIndex) - { - //case WifiTXLocIndex_CMD: - //case WifiTXLocIndex_BEACON: - case WifiTXLocIndex_LOC1: io.TXSTAT.PacketUpdate = 0; break; - case WifiTXLocIndex_LOC2: io.TXSTAT.PacketUpdate = 1; break; - case WifiTXLocIndex_LOC3: io.TXSTAT.PacketUpdate = 2; break; - - default: - break; - } - - io.TXSTAT.PacketCompleted = 1; - - WIFI_triggerIRQ(WifiIRQ01_TXComplete); - - //io.RF_STATUS.RFStatus = 0x01; - //io.RF_PINS.RX_On = 1; - - io.RF_STATUS.RFStatus = 0x09; - io.RF_PINS.CarrierSense = 0; - io.RF_PINS.TXMain = 0; - io.RF_PINS.UNKNOWN1 = 1; - io.RF_PINS.TX_On = 0; - io.RF_PINS.RX_On = 0; - - // Switch to the next TX slot. - while (!isTXSlotBusy && (wifi.txCurrentSlot != WifiTXLocIndex_LOC1)) - { - /*if (wifi.txCurrentSlot == WifiTXLocIndex_BEACON) - { - wifi.txCurrentSlot = WifiTXLocIndex_CMD; - isTXSlotBusy = (io.TXBUSY.Cmd != 0); - } - else if (wifi.txCurrentSlot == WifiTXLocIndex_CMD) - { - wifi.txCurrentSlot = WifiTXLocIndex_LOC3; - isTXSlotBusy = (io.TXBUSY.Loc3 != 0); - } - else */if (wifi.txCurrentSlot == WifiTXLocIndex_LOC3) - { - wifi.txCurrentSlot = WifiTXLocIndex_LOC2; - isTXSlotBusy = (io.TXBUSY.Loc2 != 0); - } - else if (wifi.txCurrentSlot == WifiTXLocIndex_LOC2) - { - wifi.txCurrentSlot = WifiTXLocIndex_LOC1; - isTXSlotBusy = (io.TXBUSY.Loc1 != 0); - } - } - - WIFI_LOG(3, "TX slot %i finished sending its packet. Next is slot %i. TXStat = %04X\n", - (int)txSlotIndex, (int)wifi.txCurrentSlot, io.TXSTAT.value); - } - } - } - - wifiHandler->CommTrigger(); -} - /******************************************************************************* SoftAP (fake wifi access point) @@ -3775,11 +3599,6 @@ size_t SoftAPCommInterface::TXPacketSend(u8 *txTargetBuffer, size_t txLength) return txPacketSize; } -#if WIFI_SAVE_PCAP_TO_FILE - // Store the packet in the PCAP file. - this->_PacketCaptureFileWrite(txTargetBuffer, txLength, false); -#endif - int result = this->_pcap->sendpacket(this->_bridgeDevice, txTargetBuffer, txLength); if (result == 0) { @@ -3798,7 +3617,7 @@ size_t SoftAPCommInterface::RXPacketGet(u8 *rxTargetBuffer, u16 sequenceNumber) return rxPacketSize; } - int result = this->_pcap->dispatch(this->_bridgeDevice, 16, (void *)&SoftAP_RXPacketGet_Callback, rxTargetBuffer); + int result = this->_pcap->dispatch(this->_bridgeDevice, 1, (void *)&SoftAP_RXPacketGet_Callback, rxTargetBuffer); if (result <= 0) { return rxPacketSize; @@ -3834,8 +3653,6 @@ WifiHandler::WifiHandler() _selectedBridgeDeviceIndex = 0; _firmwareMACMode = FirmwareMACMode_Automatic; - _usecCounter = 0; - _workingTXBuffer = NULL; _workingRXAdhocBuffer = NULL; _workingRXSoftAPBuffer = NULL; @@ -3902,7 +3719,7 @@ void WifiHandler::_RXWriteOneHalfword(u16 val) WifiData &wifi = this->_wifi; WIFI_IOREG_MAP &io = wifi.io; - wifi.RAM[io.RXBUF_WRCSR.HalfwordAddress] = val; + *(u16 *)&wifi.RAM[io.RXBUF_WRCSR.HalfwordAddress << 1] = val; io.RXBUF_WRCSR.HalfwordAddress++; // wrap around @@ -4088,7 +3905,7 @@ const u8* WifiHandler::_RXPacketFilter(const u8 *rxBuffer, const size_t rxBytes, #if WIFI_SAVE_PCAP_TO_FILE if ( !WIFI_isBroadcastMAC(&packetIEEE80211HeaderPtr[destMACOffset]) ) { - this->_PacketCaptureFileWrite(packetIEEE80211HeaderPtr, rxPacketSize, true); + this->_PacketCaptureFileWrite(packetIEEE80211HeaderPtr, rxPacketSize, true, wifi.usecCounter); } #endif @@ -4155,7 +3972,7 @@ void WifiHandler::_PacketCaptureFileClose() } // Save an Ethernet packet into the PCAP file of the current connection. -void WifiHandler::_PacketCaptureFileWrite(const u8 *packet, u32 len, bool isReceived) +void WifiHandler::_PacketCaptureFileWrite(const u8 *packet, u32 len, bool isReceived, u64 timeStamp) { if (this->_packetCaptureFile == NULL) { @@ -4163,8 +3980,8 @@ void WifiHandler::_PacketCaptureFileWrite(const u8 *packet, u32 len, bool isRece return; } - const u32 seconds = this->_usecCounter / 1000000; - const u32 millis = this->_usecCounter % 1000000; + const u32 seconds = timeStamp / 1000000; + const u32 millis = timeStamp % 1000000; // Add the packet // more info: http://www.kroosec.com/2012/10/a-look-at-pcap-file-format.html @@ -4206,7 +4023,7 @@ RXQueuedPacket WifiHandler::_GenerateSoftAPDeauthenticationFrame(u16 sequenceNum return newRXPacket; } -RXQueuedPacket WifiHandler::_GenerateSoftAPBeaconFrame(u16 sequenceNumber) +RXQueuedPacket WifiHandler::_GenerateSoftAPBeaconFrame(u16 sequenceNumber, u64 timeStamp) { RXQueuedPacket newRXPacket; @@ -4217,14 +4034,14 @@ RXQueuedPacket WifiHandler::_GenerateSoftAPBeaconFrame(u16 sequenceNumber) memcpy(IEEE80211FrameHeaderPtr, SoftAP_Beacon, sizeof(SoftAP_Beacon)); mgmtFrameHeader.seqCtl.SequenceNumber = sequenceNumber; - *(u64 *)mgmtFrameBody = this->_usecCounter; // Timestamp + *(u64 *)mgmtFrameBody = timeStamp; newRXPacket.rxHeader = WIFI_GenerateRXHeader(IEEE80211FrameHeaderPtr, 1, true, sizeof(SoftAP_Beacon)); return newRXPacket; } -RXQueuedPacket WifiHandler::_GenerateSoftAPMgmtResponseFrame(WifiFrameManagementSubtype mgmtFrameSubtype, u16 sequenceNumber) +RXQueuedPacket WifiHandler::_GenerateSoftAPMgmtResponseFrame(WifiFrameManagementSubtype mgmtFrameSubtype, u16 sequenceNumber, u64 timeStamp) { RXQueuedPacket newRXPacket; @@ -4240,9 +4057,7 @@ RXQueuedPacket WifiHandler::_GenerateSoftAPMgmtResponseFrame(WifiFrameManagement packetLen = sizeof(SoftAP_ProbeResponse); memcpy(IEEE80211FrameHeaderPtr, SoftAP_ProbeResponse, packetLen); - // Add the timestamp - u64 timestamp = this->_usecCounter; - *(u64 *)mgmtFrameBody = timestamp; + *(u64 *)mgmtFrameBody = timeStamp; break; } @@ -4349,7 +4164,7 @@ bool WifiHandler::_SoftAPTrySendPacket(const TXPacketHeader &txHeader, const u8 bool isPacketHandled = false; const WifiFrameControl &fc = (WifiFrameControl &)IEEE80211PacketData[0]; - switch((WifiFrameType)fc.Type) + switch ((WifiFrameType)fc.Type) { case WifiFrameType_Management: { @@ -4358,7 +4173,7 @@ bool WifiHandler::_SoftAPTrySendPacket(const TXPacketHeader &txHeader, const u8 if ( WIFI_compareMAC(mgmtFrameHeader.BSSID, SoftAP_MACAddr) || (WIFI_isBroadcastMAC(mgmtFrameHeader.BSSID) && (fc.Subtype == WifiFrameManagementSubtype_ProbeRequest)) ) { - RXQueuedPacket newRXPacket = this->_GenerateSoftAPMgmtResponseFrame((WifiFrameManagementSubtype)fc.Subtype, this->_softAPSequenceNumber); + RXQueuedPacket newRXPacket = this->_GenerateSoftAPMgmtResponseFrame((WifiFrameManagementSubtype)fc.Subtype, this->_softAPSequenceNumber, this->_wifi.usecCounter); if (newRXPacket.rxHeader.length > 0) { newRXPacket.latencyCount = 0; @@ -4449,6 +4264,11 @@ bool WifiHandler::_SoftAPTrySendPacket(const TXPacketHeader &txHeader, const u8 this->_rxPacketQueue.push_back(newRXPacket); slock_unlock(this->_mutexRXPacketQueue); this->_softAPSequenceNumber++; + +#if WIFI_SAVE_PCAP_TO_FILE + // Store the packet in the PCAP file. + this->_PacketCaptureFileWrite(this->_workingTXBuffer, sendPacketSize, false, this->_wifi.usecCounter); +#endif } } @@ -4622,7 +4442,7 @@ bool WifiHandler::CommStart() this->_softAPCommInterface->Stop(); // Reset internal values. - this->_usecCounter = 0; + this->_wifi.usecCounter = 0; this->_RXEmptyQueue(); // Allocate 16KB worth of memory per buffer for sending packets. Hopefully, this should be plenty. @@ -4750,15 +4570,204 @@ void WifiHandler::CommSendPacket(const TXPacketHeader &txHeader, const u8 *IEEE8 void WifiHandler::CommTrigger() { - WIFI_IOREG_MAP &io = this->_wifi.io; + WifiData &wifi = this->_wifi; + WIFI_IOREG_MAP &io = wifi.io; - this->_usecCounter++; + if (io.POWER_US.Disable != 0) + { + return; // Don't do anything if WiFi isn't powered up. + } - if ( ((this->_usecCounter & 131071) == 0) && (io.RXCNT.EnableRXFIFOQueuing != 0) ) + wifi.usecCounter++; + + // a usec has passed + if (io.US_COUNTCNT.EnableCounter != 0) + { + io.US_COUNT++; + } + + // Note: the extra counter is decremented every 10 microseconds. + // To avoid a modulo every microsecond, we multiply the counter + // value by 10 and decrement it every microsecond :) + if (io.CMD_COUNTCNT.EnableCounter != 0) + { + if (wifi.cmdCount_u32 > 0) + { + wifi.cmdCount_u32--; + + if (wifi.cmdCount_u32 == 0) + { + WIFI_TXStart(WifiTXLocIndex_CMD, io.TXBUF_CMD); + } + } + } + + // The beacon counters are in milliseconds + // GBATek says they're decremented every 1024 usecs + if ((io.US_COUNT & 1023) == 0) + { + io.BEACONCOUNT1--; + if (io.BEACONCOUNT1 == (io.PRE_BEACON >> 10)) + { + WIFI_triggerIRQ(WifiIRQ15_TimeslotPreBeacon); + } + else if (io.BEACONCOUNT1 == 0) + { + WIFI_triggerIRQ(WifiIRQ14_TimeslotBeacon); + } + + if (io.BEACONCOUNT2 > 0) + { + io.BEACONCOUNT2--; + if (io.BEACONCOUNT2 == 0) + { + WIFI_triggerIRQ(WifiIRQ13_TimeslotPostBeacon); + } + } + } + + if ( (io.US_COMPARECNT.EnableCompare != 0) && (io.US_COMPARE == io.US_COUNT) ) + { + //printf("ucmp irq14\n"); + WIFI_triggerIRQ(WifiIRQ14_TimeslotBeacon); + } + + if (io.CONTENTFREE > 0) + { + io.CONTENTFREE--; + } + + if ((io.US_COUNT & 3) == 0) + { + const WifiTXLocIndex txSlotIndex = wifi.txCurrentSlot; + bool isTXSlotBusy = false; + + switch (txSlotIndex) + { + case WifiTXLocIndex_LOC1: isTXSlotBusy = (io.TXBUSY.Loc1 != 0); break; + //case WifiTXLocIndex_CMD: isTXSlotBusy = (io.TXBUSY.Cmd != 0); break; + case WifiTXLocIndex_LOC2: isTXSlotBusy = (io.TXBUSY.Loc2 != 0); break; + case WifiTXLocIndex_LOC3: isTXSlotBusy = (io.TXBUSY.Loc3 != 0); break; + //case WifiTXLocIndex_BEACON: isTXSlotBusy = (io.TXBUSY.Beacon != 0); break; + + default: + break; + } + + if (isTXSlotBusy) + { + IOREG_W_TXBUF_LOCATION *txBufLocation = NULL; + TXPacketInfo &txPacketInfo = wifiHandler->GetPacketInfoAtSlot(txSlotIndex); + + switch (txSlotIndex) + { + case WifiTXLocIndex_LOC1: txBufLocation = &io.TXBUF_LOC1; break; + //case WifiTXLocIndex_CMD: txBufLocation = &io.TXBUF_CMD; break; + case WifiTXLocIndex_LOC2: txBufLocation = &io.TXBUF_LOC2; break; + case WifiTXLocIndex_LOC3: txBufLocation = &io.TXBUF_LOC3; break; + //case WifiTXLocIndex_BEACON: txBufLocation = &io.TXBUF_BEACON; break; + + default: + break; + } + + txPacketInfo.remainingBytes--; + io.RXTX_ADDR.HalfwordAddress++; + + if (txPacketInfo.remainingBytes == 0) + { + isTXSlotBusy = false; + + switch (txSlotIndex) + { + case WifiTXLocIndex_LOC1: io.TXBUSY.Loc1 = 0; break; + //case WifiTXLocIndex_CMD: io.TXBUSY.Cmd = 0; break; + case WifiTXLocIndex_LOC2: io.TXBUSY.Loc2 = 0; break; + case WifiTXLocIndex_LOC3: io.TXBUSY.Loc3 = 0; break; + //case WifiTXLocIndex_BEACON: io.TXBUSY.Beacon = 0; break; + + default: + break; + } + + txBufLocation->TransferRequest = 0; + + TXPacketHeader &txHeader = (TXPacketHeader &)wifi.RAM[txBufLocation->HalfwordAddress << 1]; + wifiHandler->CommSendPacket(txHeader, &wifi.RAM[(txBufLocation->HalfwordAddress << 1) + sizeof(TXPacketHeader)]); + txHeader.txStatus = 0x0001; + txHeader.UNKNOWN3 = 0; + + switch (txSlotIndex) + { + //case WifiTXLocIndex_CMD: + //case WifiTXLocIndex_BEACON: + case WifiTXLocIndex_LOC1: io.TXSTAT.PacketUpdate = 0; break; + case WifiTXLocIndex_LOC2: io.TXSTAT.PacketUpdate = 1; break; + case WifiTXLocIndex_LOC3: io.TXSTAT.PacketUpdate = 2; break; + + default: + break; + } + + io.TXSTAT.PacketCompleted = 1; + + WIFI_triggerIRQ(WifiIRQ01_TXComplete); + + //io.RF_STATUS.RFStatus = 0x01; + //io.RF_PINS.RX_On = 1; + + io.RF_STATUS.RFStatus = 0x09; + io.RF_PINS.CarrierSense = 0; + io.RF_PINS.TXMain = 0; + io.RF_PINS.UNKNOWN1 = 1; + io.RF_PINS.TX_On = 0; + io.RF_PINS.RX_On = 0; + + // Switch to the next TX slot. + while (!isTXSlotBusy && (wifi.txCurrentSlot != WifiTXLocIndex_LOC1)) + { + /*if (wifi.txCurrentSlot == WifiTXLocIndex_BEACON) + { + wifi.txCurrentSlot = WifiTXLocIndex_CMD; + isTXSlotBusy = (io.TXBUSY.Cmd != 0); + } + else if (wifi.txCurrentSlot == WifiTXLocIndex_CMD) + { + wifi.txCurrentSlot = WifiTXLocIndex_LOC3; + isTXSlotBusy = (io.TXBUSY.Loc3 != 0); + } + else */if (wifi.txCurrentSlot == WifiTXLocIndex_LOC3) + { + wifi.txCurrentSlot = WifiTXLocIndex_LOC2; + isTXSlotBusy = (io.TXBUSY.Loc2 != 0); + } + else if (wifi.txCurrentSlot == WifiTXLocIndex_LOC2) + { + wifi.txCurrentSlot = WifiTXLocIndex_LOC1; + isTXSlotBusy = (io.TXBUSY.Loc1 != 0); + } + } + + WIFI_LOG(3, "TX slot %i finished sending its packet. Next is slot %i. TXStat = %04X\n", + (int)txSlotIndex, (int)wifi.txCurrentSlot, io.TXSTAT.value); + } + } + } + + if (io.RXCNT.EnableRXFIFOQueuing != 0) + { + this->_AddPeriodicPacketsToRXQueue(wifi.usecCounter); + this->_CopyFromRXQueue(); + } +} + +void WifiHandler::_AddPeriodicPacketsToRXQueue(const u64 usecCounter) +{ + if ((usecCounter & 131071) == 0) { //zero sez: every 1/10 second? does it have to be precise? this is so costly.. // Okay for 128 ms then - RXQueuedPacket newRXPacket = this->_GenerateSoftAPBeaconFrame(this->_softAPSequenceNumber); + RXQueuedPacket newRXPacket = this->_GenerateSoftAPBeaconFrame(this->_softAPSequenceNumber, this->_wifi.usecCounter); newRXPacket.latencyCount = 0; slock_lock(this->_mutexRXPacketQueue); @@ -4767,75 +4776,10 @@ void WifiHandler::CommTrigger() this->_softAPSequenceNumber++; } - slock_lock(this->_mutexRXPacketQueue); - - if (!this->_rxPacketQueue.empty() && (io.RXCNT.EnableRXFIFOQueuing != 0)) - { - RXQueuedPacket ¤tRXPacket = this->_rxPacketQueue.front(); - currentRXPacket.latencyCount++; - - const RXQueuedPacket newRXPacket = currentRXPacket; - slock_unlock(this->_mutexRXPacketQueue); - - const size_t totalPacketLength = (sizeof(RXPacketHeader) + newRXPacket.rxHeader.length > sizeof(RXQueuedPacket)) ? sizeof(RXQueuedPacket) : sizeof(RXPacketHeader) + newRXPacket.rxHeader.length; - - if (this->_rxCurrentQueuedPacketPosition == 0) - { - WIFI_triggerIRQ(WifiIRQ06_RXStart); - } - - // If the user selects compatibility mode, then we will emulate the transfer delays - // involved with copying RX packet data into WiFi RAM. Otherwise, just copy all of - // the RX packet data into WiFi RAM immediately. - if (this->_currentEmulationLevel == WifiEmulationLevel_Compatibility) - { - // Copy the RX packet data into WiFi RAM over time. - if ( (this->_rxCurrentQueuedPacketPosition == 0) || (newRXPacket.latencyCount >= RX_LATENCY_LIMIT) ) - { - this->_RXWriteOneHalfword(*(u16 *)&newRXPacket.rawFrameData[this->_rxCurrentQueuedPacketPosition]); - this->_rxCurrentQueuedPacketPosition += 2; - } - } - else - { - // Copy the entire RX packet data into WiFi RAM immediately. - while (this->_rxCurrentQueuedPacketPosition < totalPacketLength) - { - this->_RXWriteOneHalfword(*(u16 *)&newRXPacket.rawFrameData[this->_rxCurrentQueuedPacketPosition]); - this->_rxCurrentQueuedPacketPosition += 2; - } - } - - if (this->_rxCurrentQueuedPacketPosition >= totalPacketLength) - { - slock_lock(this->_mutexRXPacketQueue); - this->_rxPacketQueue.pop_front(); - slock_unlock(this->_mutexRXPacketQueue); - - this->_rxCurrentQueuedPacketPosition = 0; - - // Adjust the RX cursor address so that it is 4-byte aligned. - io.RXBUF_WRCSR.HalfwordAddress = ((io.RXBUF_WRCSR.HalfwordAddress + 1) & 0x0FFE); - if (io.RXBUF_WRCSR.HalfwordAddress >= ((io.RXBUF_END & 0x1FFE) >> 1)) - { - io.RXBUF_WRCSR.HalfwordAddress = ((io.RXBUF_BEGIN & 0x1FFE) >> 1); - } - - io.RX_COUNT.OkayCount++; - WIFI_triggerIRQ(WifiIRQ00_RXComplete); - io.RF_STATUS.RFStatus = WifiRFStatus1_TXComplete; - io.RF_PINS.value = RFPinsLUT[WifiRFStatus1_TXComplete]; - } - } - else - { - slock_unlock(this->_mutexRXPacketQueue); - } - // EXTREMELY EXPERIMENTAL packet receiving code // Can now receive 64 packets per millisecond. Completely arbitrary limit. Todo: tweak if needed. // But due to using non-blocking mode, this shouldn't be as slow as it used to be. - if ((this->_usecCounter & 255) == 0) + if ((usecCounter & 15) == 0) { size_t rxBytes = this->_softAPCommInterface->RXPacketGet(this->_workingRXSoftAPBuffer, this->_softAPSequenceNumber); if (rxBytes > 0) @@ -4857,6 +4801,75 @@ void WifiHandler::CommTrigger() } } +void WifiHandler::_CopyFromRXQueue() +{ + WIFI_IOREG_MAP &io = this->_wifi.io; + + slock_lock(this->_mutexRXPacketQueue); + + if (this->_rxPacketQueue.empty()) + { + slock_unlock(this->_mutexRXPacketQueue); + return; + } + + RXQueuedPacket ¤tRXPacket = this->_rxPacketQueue.front(); + currentRXPacket.latencyCount++; + + const RXQueuedPacket newRXPacket = currentRXPacket; + slock_unlock(this->_mutexRXPacketQueue); + + const size_t totalPacketLength = (sizeof(RXPacketHeader) + newRXPacket.rxHeader.length > sizeof(RXQueuedPacket)) ? sizeof(RXQueuedPacket) : sizeof(RXPacketHeader) + newRXPacket.rxHeader.length; + + if (this->_rxCurrentQueuedPacketPosition == 0) + { + WIFI_triggerIRQ(WifiIRQ06_RXStart); + } + + // If the user selects compatibility mode, then we will emulate the transfer delays + // involved with copying RX packet data into WiFi RAM. Otherwise, just copy all of + // the RX packet data into WiFi RAM immediately. + if (this->_currentEmulationLevel == WifiEmulationLevel_Compatibility) + { + // Copy the RX packet data into WiFi RAM over time. + if ( (this->_rxCurrentQueuedPacketPosition == 0) || (newRXPacket.latencyCount >= RX_LATENCY_LIMIT) ) + { + this->_RXWriteOneHalfword(*(u16 *)&newRXPacket.rawFrameData[this->_rxCurrentQueuedPacketPosition]); + this->_rxCurrentQueuedPacketPosition += 2; + } + } + else + { + // Copy the entire RX packet data into WiFi RAM immediately. + while (this->_rxCurrentQueuedPacketPosition < totalPacketLength) + { + this->_RXWriteOneHalfword(*(u16 *)&newRXPacket.rawFrameData[this->_rxCurrentQueuedPacketPosition]); + this->_rxCurrentQueuedPacketPosition += 2; + } + } + + if (this->_rxCurrentQueuedPacketPosition >= totalPacketLength) + { + slock_lock(this->_mutexRXPacketQueue); + this->_rxPacketQueue.pop_front(); + slock_unlock(this->_mutexRXPacketQueue); + + this->_rxCurrentQueuedPacketPosition = 0; + + // Adjust the RX cursor address so that it is 4-byte aligned. + io.RXBUF_WRCSR.HalfwordAddress = ((io.RXBUF_WRCSR.HalfwordAddress + 1) & 0x0FFE); + if (io.RXBUF_WRCSR.HalfwordAddress >= ((io.RXBUF_END & 0x1FFE) >> 1)) + { + io.RXBUF_WRCSR.HalfwordAddress = ((io.RXBUF_BEGIN & 0x1FFE) >> 1); + } + + io.RX_COUNT.OkayCount++; + WIFI_triggerIRQ(WifiIRQ00_RXComplete); + io.RF_STATUS.RFStatus = WifiRFStatus1_TXComplete; + io.RF_PINS.value = RFPinsLUT[WifiRFStatus1_TXComplete]; + } +} + void WifiHandler::CommEmptyRXQueue() { this->_RXEmptyQueue(); diff --git a/desmume/src/wifi.h b/desmume/src/wifi.h index d6d936f84..e7ead22c5 100755 --- a/desmume/src/wifi.h +++ b/desmume/src/wifi.h @@ -2788,11 +2788,12 @@ typedef struct WIFI_IOREG_MAP io; RF2958_IOREG_MAP rf; bb_t bb; - u16 RAM[0x1000]; + u8 RAM[0x2000]; WifiTXLocIndex txCurrentSlot; TXPacketInfo txPacketInfo[6]; u32 cmdCount_u32; + u64 usecCounter; } WifiData; // Emulator frame headers @@ -3173,10 +3174,6 @@ extern LegacyWifiSFormat legacyWifiSF; void WIFI_write16(u32 address, u16 val); u16 WIFI_read16(u32 address); -/* wifimac timing */ -void WIFI_usTrigger(); - - /* DS WFC profile data documented here : */ /* http://dsdev.bigredpimp.com/2006/07/31/aoss-wfc-profile-data/ */ /* Note : we use bytes to avoid endianness issues */ @@ -3323,8 +3320,6 @@ protected: FirmwareMACMode _firmwareMACMode; u8 _userMAC[3]; - u64 _usecCounter; - u8 *_workingTXBuffer; u8 *_workingRXAdhocBuffer; u8 *_workingRXSoftAPBuffer; @@ -3342,17 +3337,20 @@ protected: FILE *_packetCaptureFile; // PCAP file to store the Ethernet packets. + void _AddPeriodicPacketsToRXQueue(const u64 usecCounter); + void _CopyFromRXQueue(); + void _RXEmptyQueue(); void _RXWriteOneHalfword(u16 val); const u8* _RXPacketFilter(const u8 *rxBuffer, const size_t rxBytes, RXPacketHeader &outRXHeader); void _PacketCaptureFileOpen(); void _PacketCaptureFileClose(); - void _PacketCaptureFileWrite(const u8 *packet, u32 len, bool isReceived); + void _PacketCaptureFileWrite(const u8 *packet, u32 len, bool isReceived, u64 timeStamp); RXQueuedPacket _GenerateSoftAPDeauthenticationFrame(u16 sequenceNumber); - RXQueuedPacket _GenerateSoftAPBeaconFrame(u16 sequenceNumber); - RXQueuedPacket _GenerateSoftAPMgmtResponseFrame(WifiFrameManagementSubtype mgmtFrameSubtype, u16 sequenceNumber); + RXQueuedPacket _GenerateSoftAPBeaconFrame(u16 sequenceNumber, u64 timeStamp); + RXQueuedPacket _GenerateSoftAPMgmtResponseFrame(WifiFrameManagementSubtype mgmtFrameSubtype, u16 sequenceNumber, u64 timeStamp); RXQueuedPacket _GenerateSoftAPCtlACKFrame(const WifiDataFrameHeaderSTA2DS &inIEEE80211FrameHeader, const size_t sendPacketLength); bool _SoftAPTrySendPacket(const TXPacketHeader &txHeader, const u8 *IEEE80211PacketData);