wifi improvements:

* implement channels
* rework power-down support, fixing bugs
* fix bug when W_BeaconInterval is zero
* fix potential missing IRQs when writing to W_IE
This commit is contained in:
Arisotura 2024-04-12 17:28:51 +02:00
parent 0b87dd5fa6
commit 111dc7a563
6 changed files with 344 additions and 134 deletions

View File

@ -1845,7 +1845,7 @@ void NDS::debug(u32 param)
//for (int i = 0; i < 9; i++) //for (int i = 0; i < 9; i++)
// printf("VRAM %c: %02X\n", 'A'+i, GPU->VRAMCNT[i]); // printf("VRAM %c: %02X\n", 'A'+i, GPU->VRAMCNT[i]);
Platform::FileHandle* shit = Platform::OpenFile("debug/DSfirmware.bin", FileMode::Write); Platform::FileHandle* shit = Platform::OpenFile("debug/pokeplat.bin", FileMode::Write);
Platform::FileWrite(ARM9.ITCM, 0x8000, 1, shit); Platform::FileWrite(ARM9.ITCM, 0x8000, 1, shit);
for (u32 i = 0x02000000; i < 0x02400000; i+=4) for (u32 i = 0x02000000; i < 0x02400000; i+=4)
{ {

View File

@ -159,11 +159,45 @@ void Wifi::Reset()
#undef BBREG_FIXED #undef BBREG_FIXED
const Firmware& fw = NDS.SPI.GetFirmware(); const Firmware& fw = NDS.SPI.GetFirmware();
const auto& fwheader = fw.GetHeader();
RFVersion = fw.GetHeader().RFChipType; RFVersion = fwheader.RFChipType;
memset(RFRegs, 0, 4*0x40); memset(RFRegs, 0, 4*0x40);
Firmware::FirmwareConsoleType console = fw.GetHeader().ConsoleType; // load channel index/data from the firmware
// the current channel will be determined by RF settings
// so we compare the two 'most important' RF registers to these values to figure out which channel is selected
if (RFVersion == 3)
{
RFChannelIndex[0] = fwheader.Type3Config.RFIndex1;
RFChannelIndex[1] = fwheader.Type3Config.RFIndex2;
for (int i = 0; i < 14; i++)
{
RFChannelData[i][0] = fwheader.Type3Config.RFData1[i];
RFChannelData[i][1] = fwheader.Type3Config.RFData2[i];
}
}
else
{
RFChannelIndex[0] = fwheader.Type2Config.InitialRF56Values[2] >> 2;
RFChannelIndex[1] = fwheader.Type2Config.InitialRF56Values[5] >> 2;
for (int i = 0; i < 14; i++)
{
RFChannelData[i][0] = fwheader.Type2Config.InitialRF56Values[i*6 + 0] |
(fwheader.Type2Config.InitialRF56Values[i*6 + 1] << 8) |
((fwheader.Type2Config.InitialRF56Values[i*6 + 2] & 0x03) << 16);
RFChannelData[i][1] = fwheader.Type2Config.InitialRF56Values[i*6 + 3] |
(fwheader.Type2Config.InitialRF56Values[i*6 + 4] << 8) |
((fwheader.Type2Config.InitialRF56Values[i*6 + 5] & 0x03) << 16);
}
}
CurChannel = 0;
Firmware::FirmwareConsoleType console = fwheader.ConsoleType;
if (console == Firmware::FirmwareConsoleType::DS) if (console == Firmware::FirmwareConsoleType::DS)
IOPORT(0x000) = 0x1440; IOPORT(0x000) = 0x1440;
else if (console == Firmware::FirmwareConsoleType::DSLite) else if (console == Firmware::FirmwareConsoleType::DSLite)
@ -182,6 +216,8 @@ void Wifi::Reset()
// TODO: find out what the initial values are // TODO: find out what the initial values are
IOPORT(W_PowerUS) = 0x0001; IOPORT(W_PowerUS) = 0x0001;
//IOPORT(W_BeaconInterval) = 100;
USTimestamp = 0; USTimestamp = 0;
USCounter = 0; USCounter = 0;
@ -209,7 +245,6 @@ void Wifi::Reset()
CmdCounter = 0; CmdCounter = 0;
USUntilPowerOn = 0; USUntilPowerOn = 0;
ForcePowerOn = false;
IsMP = false; IsMP = false;
IsMPClient = false; IsMPClient = false;
@ -244,6 +279,8 @@ void Wifi::DoSavestate(Savestate* file)
file->Var8(&RFVersion); file->Var8(&RFVersion);
file->VarArray(RFRegs, 4*0x40); file->VarArray(RFRegs, 4*0x40);
file->Var32((u32*)&CurChannel);
file->Var64(&USCounter); file->Var64(&USCounter);
file->Var64(&USCompare); file->Var64(&USCompare);
file->Bool32(&BlockBeaconIRQ14); file->Bool32(&BlockBeaconIRQ14);
@ -285,7 +322,6 @@ void Wifi::DoSavestate(Savestate* file)
file->Var16(&MPLastSeqno); file->Var16(&MPLastSeqno);
file->Var32((u32*)&USUntilPowerOn); file->Var32((u32*)&USUntilPowerOn);
file->Bool32(&ForcePowerOn);
file->Bool32(&IsMP); file->Bool32(&IsMP);
file->Bool32(&IsMPClient); file->Bool32(&IsMPClient);
@ -351,33 +387,38 @@ void Wifi::SetPowerCnt(u32 val)
} }
void Wifi::SetIRQ(u32 irq) void Wifi::CheckIRQ(u16 oldflags)
{ {
u32 oldflags = IOPORT(W_IF) & IOPORT(W_IE); u16 newflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IF) |= (1<<irq);
u32 newflags = IOPORT(W_IF) & IOPORT(W_IE);
if ((oldflags == 0) && (newflags != 0)) if ((oldflags == 0) && (newflags != 0))
NDS.SetIRQ(1, IRQ_Wifi); NDS.SetIRQ(1, IRQ_Wifi);
} }
void Wifi::SetIRQ(u32 irq)
{
u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IF) |= (1<<irq);
CheckIRQ(oldflags);
}
void Wifi::SetIRQ13() void Wifi::SetIRQ13()
{ {
SetIRQ(13); SetIRQ(13);
if (!(IOPORT(W_PowerTX) & 0x0002)) if ((IOPORT(W_ModeWEP) & 0x7) != 3)
{ {
IOPORT(0x034) = 0x0002; if (!(IOPORT(W_PowerTX) & (1<<1)))
//PowerDown(); {
// FIXME!! UpdatePowerStatus(-1);
IOPORT(W_RFPins) = 0x0046; }
IOPORT(W_RFStatus) = 9;
} }
} }
void Wifi::SetIRQ14(int source) // 0=USCOMPARE 1=BEACONCOUNT 2=forced void Wifi::SetIRQ14(int source) // 0=USCOMPARE 1=BEACONCOUNT 2=forced
{ {
// CHECKME: is this also done for USCOMPARE IRQ?
if (source != 2) if (source != 2)
IOPORT(W_BeaconCount1) = IOPORT(W_BeaconInterval); IOPORT(W_BeaconCount1) = IOPORT(W_BeaconInterval);
@ -409,10 +450,10 @@ void Wifi::SetIRQ15()
{ {
SetIRQ(15); SetIRQ(15);
if (IOPORT(W_PowerTX) & 0x0001) // unlike auto sleep, auto wakeup works under all power management modes
if (IOPORT(W_PowerTX) & (1<<0))
{ {
IOPORT(W_RFPins) |= 0x0080; UpdatePowerStatus(1);
IOPORT(W_RFStatus) = 1;
} }
} }
@ -426,16 +467,110 @@ void Wifi::SetStatus(u32 status)
} }
void Wifi::PowerDown() void Wifi::UpdatePowerStatus(int power) // 1=on 0=no change -1=off
{ {
IOPORT(W_TXReqRead) &= ~0x000F; // TRANSCEIVER POWER MANAGEMENT
IOPORT(W_PowerState) |= 0x0200; //
// * W_PowerForce overrides all else
// * W_ModeReset bit0 forcibly turns off the transceiver when cleared
// * power is normally turned on or off either by IRQ15/IRQ13 or by W_PowerState
// depending on the power management mode selected in W_ModeWEP
// * W_PowerDownCtrl controls how deep a regular power-down is
// if the RF hardware is powered down while still sending or receiving, int curflags = 0;
// the current frame is completed before going idle if (IOPORT(W_TRXPower) == 1) curflags |= 1;
if (!ComStatus) if (!(IOPORT(W_PowerState) & (1<<9))) curflags |= 2;
int reqflags = curflags;
if (IOPORT(W_PowerForce) & (1<<15))
{ {
SetStatus(9); reqflags = (IOPORT(W_PowerForce) & (1<<0)) ? 0 : 3;
}
else if (!(IOPORT(W_ModeReset) & (1<<0)))
{
reqflags = 0;
}
else
{
if (power == 0)
{
if ((IOPORT(W_PowerState) & 0x0202) == 0x0202)
power = 1;
else if ((IOPORT(W_PowerState) & 0x0201) == 0x0001)
power = -1;
}
// W_PowerDownCtrl:
// * bit 0 inhibits a regular power-down
// * bit 1 forces a wakeup, atleast partial
if ((power == -1) && (IOPORT(W_PowerDownCtrl) & (1<<0)))
power = 0;
/*if (power == 1)
reqflags = 3;
else if (power == -1)
reqflags = IOPORT(W_PowerDownCtrl);
else if (IOPORT(W_PowerDownCtrl) & (1<<1))
reqflags = (curflags == 3) ? 3 : IOPORT(W_PowerDownCtrl);*/
// TODO: support partial power statuses (W_PowerDownCtrl=1 or 2)
if (power == 1)
reqflags = 3;
else if (power == -1)
reqflags = IOPORT(W_PowerDownCtrl) ? 3 : 0;
else if (IOPORT(W_PowerDownCtrl) & (1<<1))
reqflags = 3;
}
if (reqflags == curflags)
return;
if (reqflags & 1)
{
if (!(curflags & 1))
{
IOPORT(W_TRXPower) = 1;
SetStatus(1);
}
}
else
{
// signal the transceiver is going to turn off (checkme)
IOPORT(W_TRXPower) = 2;
if (!ComStatus)
{
IOPORT(W_TRXPower) = 0;
SetStatus(9);
}
}
if (reqflags & 2)
{
// power on
IOPORT(W_PowerState) |= (1<<8);
if ((!(curflags & 2)) && (USUntilPowerOn == 0))
{
Log(LogLevel::Debug, "wifi: TRX power ON\n");
USUntilPowerOn = -2048;
SetIRQ(11);
}
}
else
{
// power off
if (curflags & 2)
Log(LogLevel::Debug, "wifi: TRX power OFF\n");
IOPORT(W_PowerState) &= ~(1<<0);
IOPORT(W_PowerState) &= ~(1<<8);
IOPORT(W_PowerState) |= (1<<9);
USUntilPowerOn = 0;
} }
} }
@ -521,6 +656,9 @@ void Wifi::TXSendFrame(const TXSlot* slot, int num)
if (noseqno == 2) if (noseqno == 2)
*(u16*)&TXBuffer[0xC] |= (1<<11); *(u16*)&TXBuffer[0xC] |= (1<<11);
if (CurChannel == 0) return;
TXBuffer[9] = CurChannel;
switch (num) switch (num)
{ {
case 0: case 0:
@ -600,6 +738,9 @@ void Wifi::StartTX_Cmd()
slot->CurPhase = 13; slot->CurPhase = 13;
slot->CurPhaseTime = CmdCounter - 100; slot->CurPhaseTime = CmdCounter - 100;
} }
// starting a CMD transfer wakes up the transceiver automatically
UpdatePowerStatus(1);
} }
void Wifi::StartTX_Beacon() void Wifi::StartTX_Beacon()
@ -678,6 +819,9 @@ void Wifi::SendMPDefaultReply()
// TODO // TODO
reply[0x8] = 0x14; reply[0x8] = 0x14;
if (CurChannel == 0) return;
reply[0x9] = CurChannel;
*(u16*)&reply[0xC + 0x00] = 0x0158; *(u16*)&reply[0xC + 0x00] = 0x0158;
*(u16*)&reply[0xC + 0x02] = 0x00F0;//0; // TODO?? *(u16*)&reply[0xC + 0x02] = 0x00F0;//0; // TODO??
*(u16*)&reply[0xC + 0x04] = IOPORT(W_BSSID0); *(u16*)&reply[0xC + 0x04] = IOPORT(W_BSSID0);
@ -767,6 +911,9 @@ void Wifi::SendMPAck(u16 cmdcount, u16 clientfail)
if (TXSlots[1].Rate == 2) ack[0x8] = 0x14; if (TXSlots[1].Rate == 2) ack[0x8] = 0x14;
else ack[0x8] = 0xA; else ack[0x8] = 0xA;
if (CurChannel == 0) return;
ack[0x9] = CurChannel;
*(u16*)&ack[0xC + 0x00] = 0x0218; *(u16*)&ack[0xC + 0x00] = 0x0218;
*(u16*)&ack[0xC + 0x02] = 0; *(u16*)&ack[0xC + 0x02] = 0;
*(u16*)&ack[0xC + 0x04] = 0x0903; *(u16*)&ack[0xC + 0x04] = 0x0903;
@ -1110,8 +1257,11 @@ void Wifi::FinishRX()
if (!ComStatus) if (!ComStatus)
{ {
if (IOPORT(W_PowerState) & 0x0300) if (IOPORT(W_PowerState) & (1<<9))
{
IOPORT(W_TRXPower) = 0;
SetStatus(9); SetStatus(9);
}
else else
SetStatus(1); SetStatus(1);
} }
@ -1380,7 +1530,7 @@ void Wifi::FinishRX()
void Wifi::MPClientReplyRX(int client) void Wifi::MPClientReplyRX(int client)
{ {
if (IOPORT(W_PowerState) & 0x0300) if (IOPORT(W_PowerState) & (1<<9))
return; return;
if (!(IOPORT(W_RXCnt) & 0x8000)) if (!(IOPORT(W_RXCnt) & 0x8000))
@ -1421,7 +1571,7 @@ void Wifi::MPClientReplyRX(int client)
bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
{ {
if (IOPORT(W_PowerState) & 0x0300) if (IOPORT(W_PowerState) & (1<<9))
return false; return false;
if (!(IOPORT(W_RXCnt) & 0x8000)) if (!(IOPORT(W_RXCnt) & 0x8000))
@ -1433,7 +1583,7 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
int rxlen; int rxlen;
int framelen; int framelen;
u16 framectl; u16 framectl;
u8 txrate; u8 txrate, chan;
u64 timestamp; u64 timestamp;
for (;;) for (;;)
@ -1468,6 +1618,13 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
continue; continue;
} }
chan = RXBuffer[9];
if (chan != CurChannel || CurChannel == 0)
{
Log(LogLevel::Debug, "received frame but bad channel %d (expected %d)\n", chan, CurChannel);
continue;
}
framectl = *(u16*)&RXBuffer[12+0]; framectl = *(u16*)&RXBuffer[12+0];
txrate = RXBuffer[8]; txrate = RXBuffer[8];
@ -1528,7 +1685,6 @@ bool Wifi::CheckRX(int type) // 0=regular 1=MP replies 2=MP host frames
// we also need to determine how far we can run after having received this frame // we also need to determine how far we can run after having received this frame
RXTimestamp = timestamp; RXTimestamp = timestamp;
//if (RXTimestamp < USTimestamp) printf("CRAP!! %04X %016llX %016llX\n", framectl, RXTimestamp, USTimestamp);
if (RXTimestamp < USTimestamp) RXTimestamp = USTimestamp; if (RXTimestamp < USTimestamp) RXTimestamp = USTimestamp;
NextSync = RXTimestamp + (framelen * (txrate==0x14 ? 4:8)); NextSync = RXTimestamp + (framelen * (txrate==0x14 ? 4:8));
@ -1570,11 +1726,13 @@ void Wifi::MSTimer()
} }
} }
IOPORT(W_BeaconCount1)--; if (IOPORT(W_BeaconCount1) != 0)
if (IOPORT(W_BeaconCount1) == 0)
{ {
SetIRQ14(1); IOPORT(W_BeaconCount1)--;
if (IOPORT(W_BeaconCount1) == 0) SetIRQ14(1);
} }
if (IOPORT(W_BeaconCount1) == 0)
IOPORT(W_BeaconCount1) = IOPORT(W_BeaconInterval);
if (IOPORT(W_BeaconCount2) != 0) if (IOPORT(W_BeaconCount2) != 0)
{ {
@ -1605,19 +1763,19 @@ void Wifi::USTimer(u32 param)
if (!(USTimestamp & 0x3FF & kTimeCheckMask)) if (!(USTimestamp & 0x3FF & kTimeCheckMask))
WifiAP->MSTimer(); WifiAP->MSTimer();
bool switchOffPowerSaving = false;
if (USUntilPowerOn < 0) if (USUntilPowerOn < 0)
{ {
USUntilPowerOn += kTimerInterval; USUntilPowerOn += kTimerInterval;
switchOffPowerSaving = (USUntilPowerOn >= 0) && (IOPORT(W_PowerUnk) & 0x0001 || ForcePowerOn); if (USUntilPowerOn >= 0)
} {
if ((USUntilPowerOn >= 0) && (IOPORT(W_PowerState) & 0x0002 || switchOffPowerSaving)) USUntilPowerOn = 0;
{
IOPORT(W_PowerState) = 0; IOPORT(W_PowerState) = 0;
IOPORT(W_RFPins) = 1; SetStatus(1);
IOPORT(W_RFPins) = 0x0084;
SetIRQ(11); UpdatePowerStatus(0);
}
} }
if (IOPORT(W_USCountCnt)) if (IOPORT(W_USCountCnt))
@ -1660,7 +1818,7 @@ void Wifi::USTimer(u32 param)
u16 txbusy = IOPORT(W_TXBusy); u16 txbusy = IOPORT(W_TXBusy);
if (txbusy) if (txbusy)
{ {
if (IOPORT(W_PowerState) & 0x0300) if (IOPORT(W_PowerState) & (1<<9))
{ {
ComStatus = 0; ComStatus = 0;
TXCurSlot = -1; TXCurSlot = -1;
@ -1695,9 +1853,10 @@ void Wifi::USTimer(u32 param)
bool finished = ProcessTX(&TXSlots[TXCurSlot], TXCurSlot); bool finished = ProcessTX(&TXSlots[TXCurSlot], TXCurSlot);
if (finished) if (finished)
{ {
if (IOPORT(W_PowerState) & 0x0300) if (IOPORT(W_PowerState) & (1<<9))
{ {
IOPORT(W_TXBusy) = 0; IOPORT(W_TXBusy) = 0;
IOPORT(W_TRXPower) = 0;
SetStatus(9); SetStatus(9);
} }
@ -1754,8 +1913,9 @@ void Wifi::USTimer(u32 param)
RXCounter = 0; RXCounter = 0;
} }
// TODO: proper error management // TODO: proper error management
if ((!ComStatus) && (IOPORT(W_PowerState) & 0x0300)) if ((!ComStatus) && (IOPORT(W_PowerState) & (1<<9)))
{ {
IOPORT(W_TRXPower) = 0;
SetStatus(9); SetStatus(9);
} }
} }
@ -1766,6 +1926,28 @@ void Wifi::USTimer(u32 param)
} }
void Wifi::ChangeChannel()
{
u32 val1 = RFRegs[RFChannelIndex[0]];
u32 val2 = RFRegs[RFChannelIndex[1]];
CurChannel = 0;
for (int i = 0; i < 14; i++)
{
if (val1 == RFChannelData[i][0] && val2 == RFChannelData[i][1])
{
CurChannel = i+1;
break;
}
}
if (CurChannel > 0)
Log(LogLevel::Debug, "wifi: switching to channel %d\n", CurChannel);
else
Log(LogLevel::Debug, "wifi: invalid channel values %05X:%05X\n", val1, val2);
}
void Wifi::RFTransfer_Type2() void Wifi::RFTransfer_Type2()
{ {
u32 id = (IOPORT(W_RFData2) >> 2) & 0x1F; u32 id = (IOPORT(W_RFData2) >> 2) & 0x1F;
@ -1780,6 +1962,9 @@ void Wifi::RFTransfer_Type2()
{ {
u32 data = IOPORT(W_RFData1) | ((IOPORT(W_RFData2) & 0x0003) << 16); u32 data = IOPORT(W_RFData1) | ((IOPORT(W_RFData2) & 0x0003) << 16);
RFRegs[id] = data; RFRegs[id] = data;
if (id == RFChannelIndex[0] || id == RFChannelIndex[1])
ChangeChannel();
} }
} }
@ -1796,6 +1981,9 @@ void Wifi::RFTransfer_Type3()
{ {
u32 data = IOPORT(W_RFData1) & 0xFF; u32 data = IOPORT(W_RFData1) & 0xFF;
RFRegs[id] = data; RFRegs[id] = data;
if (id == RFChannelIndex[0] || id == RFChannelIndex[1])
ChangeChannel();
} }
} }
@ -1819,6 +2007,7 @@ u16 Wifi::Read(u32 addr)
switch (addr) switch (addr)
{ {
case W_Random: // random generator. not accurate case W_Random: // random generator. not accurate
// TODO: rotate the sequence based on the ARM7 cycle counter (if this is important)
Random = (Random & 0x1) ^ (((Random & 0x3FF) << 1) | (Random >> 10)); Random = (Random & 0x1) ^ (((Random & 0x3FF) << 1) | (Random >> 10));
return Random; return Random;
@ -1899,7 +2088,6 @@ u16 Wifi::Read(u32 addr)
} }
} }
//printf("WIFI: read %08X\n", addr);
return IOPORT(addr&0xFFF); return IOPORT(addr&0xFFF);
} }
@ -1923,28 +2111,20 @@ void Wifi::Write(u32 addr, u16 val)
case W_ModeReset: case W_ModeReset:
{ {
u16 oldval = IOPORT(W_ModeReset); u16 oldval = IOPORT(W_ModeReset);
IOPORT(W_ModeReset) = val & 0x0001;
if (!(oldval & 0x0001) && (val & 0x0001)) if (!(oldval & 0x0001) && (val & 0x0001))
{ {
if (!(USUntilPowerOn < 0 && ForcePowerOn)) IOPORT(0x27C) = 0x0005;
{ // TODO: 02A2??
//printf("mode reset power on %08x\n", NDS::ARM7->R[15]);
IOPORT(0x034) = 0x0002;
IOPORT(0x27C) = 0x0005;
// TODO: 02A2??
if (IOPORT(W_PowerUnk) & 0x0002) UpdatePowerStatus(0);
{
USUntilPowerOn = -2048;
IOPORT(W_PowerState) |= 0x100;
}
}
} }
else if ((oldval & 0x0001) && !(val & 0x0001)) else if ((oldval & 0x0001) && !(val & 0x0001))
{ {
//printf("mode reset shutdown %08x\n", NDS::ARM7->R[15]);
IOPORT(0x27C) = 0x000A; IOPORT(0x27C) = 0x000A;
PowerDown();
UpdatePowerStatus(0);
} }
if (val & 0x2000) if (val & 0x2000)
@ -1986,23 +2166,43 @@ void Wifi::Write(u32 addr, u16 val)
IOPORT(0x230) = 0x0047; IOPORT(0x230) = 0x0047;
} }
} }
break; return;
case W_ModeWEP: case W_ModeWEP:
val &= 0x007F; val &= 0x007F;
//printf("writing mode web %x\n", val); IOPORT(W_ModeWEP) = val;
if ((val & 0x7) == 1)
IOPORT(W_PowerUnk) |= 0x0002;
if ((val & 0x7) == 2)
IOPORT(W_PowerUnk) = 0x0003;
break;
if (IOPORT(W_PowerTX) & (1<<1))
{
if ((val & 0x7) == 1)
IOPORT(W_PowerDownCtrl) |= (1<<1);
else if ((val & 0x7) == 2)
IOPORT(W_PowerDownCtrl) = 3;
if ((val & 0x7) != 3)
IOPORT(W_PowerState) &= 0x0300;
UpdatePowerStatus(0);
}
return;
case W_IE:
{
u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IE) = val;
CheckIRQ(oldflags);
}
return;
case W_IF: case W_IF:
IOPORT(W_IF) &= ~val; IOPORT(W_IF) &= ~val;
return; return;
case W_IFSet: case W_IFSet:
IOPORT(W_IF) |= (val & 0xFBFF); {
Log(LogLevel::Debug, "wifi: force-setting IF %04X\n", val); u16 oldflags = IOPORT(W_IF) & IOPORT(W_IE);
IOPORT(W_IF) |= (val & 0xFBFF);
CheckIRQ(oldflags);
Log(LogLevel::Debug, "wifi: force-setting IF %04X\n", val);
}
return; return;
case W_AIDLow: case W_AIDLow:
@ -2012,67 +2212,63 @@ void Wifi::Write(u32 addr, u16 val)
IOPORT(W_AIDFull) = val & 0x07FF; IOPORT(W_AIDFull) = val & 0x07FF;
return; return;
case W_PowerState:
//printf("writing power state %x %08x\n", val, NDS::ARM7->R[15]);
IOPORT(W_PowerState) |= val & 0x0002;
if (IOPORT(W_ModeReset) & 0x0001 && IOPORT(W_PowerState) & 0x0002)
{
/*if (IOPORT(W_PowerState) & 0x100)
{
AlwaysPowerOn = true;
USUntilPowerOn = -1;
}
else */
if (IOPORT(W_PowerForce) == 1)
{
//printf("power on\n");
IOPORT(W_PowerState) |= 0x100;
USUntilPowerOn = -2048;
ForcePowerOn = false;
}
}
return;
case W_PowerForce:
//if ((val&0x8001)==0x8000) printf("WIFI: forcing power %04X\n", val);
val &= 0x8001;
//printf("writing power force %x %08x\n", val, NDS::ARM7->R[15]);
if (val == 0x8001)
{
//printf("force power off\n");
IOPORT(0x034) = 0x0002;
IOPORT(W_PowerState) = 0x0200;
IOPORT(W_TXReqRead) = 0;
PowerDown();
}
if (val == 1 && IOPORT(W_PowerState) & 0x0002)
{
//printf("power on\n");
IOPORT(W_PowerState) |= 0x100;
USUntilPowerOn = -2048;
ForcePowerOn = false;
}
if (val == 0x8000)
{
//printf("force power on\n");
IOPORT(W_PowerState) |= 0x100;
USUntilPowerOn = -2048;
ForcePowerOn = true;
}
break;
case W_PowerUS: case W_PowerUS:
IOPORT(W_PowerUS) = val & 0x0003; IOPORT(W_PowerUS) = val & 0x0003;
UpdatePowerOn(); UpdatePowerOn();
return; return;
case W_PowerUnk:
val &= 0x0003; case W_PowerTX:
//printf("writing power unk %x\n", val); IOPORT(W_PowerTX) = val & 0x0003;
if ((IOPORT(W_ModeWEP) & 0x7) == 1) if (val & (1<<1))
val |= 2; {
else if ((IOPORT(W_ModeWEP) & 0x7) == 2) if ((IOPORT(W_ModeWEP) & 0x7) == 1)
val = 3; IOPORT(W_PowerDownCtrl) |= (1<<1);
break; else if ((IOPORT(W_ModeWEP) & 0x7) == 2)
IOPORT(W_PowerDownCtrl) = 3;
UpdatePowerStatus(0);
}
return;
case W_PowerState:
if ((IOPORT(W_ModeWEP) & 0x7) != 3)
return;
val = (IOPORT(W_PowerState) & 0x0300) | (val & 0x0003);
if ((val & 0x0300) == 0x0200)
val &= ~(1<<0);
else
val &= ~(1<<1);
if (!(val & (1<<9)))
val &= ~(1<<8);
IOPORT(W_PowerState) = val;
UpdatePowerStatus(0);
return;
case W_PowerForce:
val &= 0x8001;
IOPORT(W_PowerForce) = val;
UpdatePowerStatus(0);
return;
case W_PowerDownCtrl:
IOPORT(W_PowerDownCtrl) = val & 0x0003;
if (IOPORT(W_PowerTX) & (1<<1))
{
if ((IOPORT(W_ModeWEP) & 0x7) == 1)
IOPORT(W_PowerDownCtrl) |= (1<<1);
else if ((IOPORT(W_ModeWEP) & 0x7) == 2)
IOPORT(W_PowerDownCtrl) = 3;
}
if (val != 0 && val != 3)
Log(LogLevel::Warn, "wifi: unusual W_PowerDownCtrl value %04X\n", val);
UpdatePowerStatus(0);
return;
case W_USCountCnt: val &= 0x0001; break; case W_USCountCnt: val &= 0x0001; break;
case W_USCompareCnt: case W_USCompareCnt:
@ -2231,6 +2427,7 @@ void Wifi::Write(u32 addr, u16 val)
// read-only ports // read-only ports
case 0x000: case 0x000:
case 0x034:
case 0x044: case 0x044:
case 0x054: case 0x054:
case 0x098: case 0x098:

View File

@ -52,11 +52,12 @@ public:
W_RXCnt = 0x030, W_RXCnt = 0x030,
W_WEPCnt = 0x032, W_WEPCnt = 0x032,
W_TRXPower = 0x034,
W_PowerUS = 0x036, W_PowerUS = 0x036,
W_PowerTX = 0x038, W_PowerTX = 0x038,
W_PowerState = 0x03C, W_PowerState = 0x03C,
W_PowerForce = 0x040, W_PowerForce = 0x040,
W_PowerUnk = 0x48, W_PowerDownCtrl = 0x48,
W_Random = 0x044, W_Random = 0x044,
@ -206,6 +207,10 @@ private:
u8 RFVersion; u8 RFVersion;
u32 RFRegs[0x40]; u32 RFRegs[0x40];
u32 RFChannelIndex[2];
u32 RFChannelData[14][2];
int CurChannel;
struct TXSlot struct TXSlot
{ {
bool Valid; bool Valid;
@ -240,7 +245,6 @@ private:
bool LANInited; bool LANInited;
int USUntilPowerOn; int USUntilPowerOn;
bool ForcePowerOn;
// MULTIPLAYER SYNC APPARATUS // MULTIPLAYER SYNC APPARATUS
bool IsMP; bool IsMP;
@ -253,13 +257,15 @@ private:
void ScheduleTimer(bool first); void ScheduleTimer(bool first);
void UpdatePowerOn(); void UpdatePowerOn();
void CheckIRQ(u16 oldflags);
void SetIRQ(u32 irq); void SetIRQ(u32 irq);
void SetIRQ13(); void SetIRQ13();
void SetIRQ14(int source); void SetIRQ14(int source);
void SetIRQ15(); void SetIRQ15();
void SetStatus(u32 status); void SetStatus(u32 status);
void PowerDown();
void UpdatePowerStatus(int power);
int PreambleLen(int rate) const; int PreambleLen(int rate) const;
u32 NumClients(u16 bitmask) const; u32 NumClients(u16 bitmask) const;
@ -284,6 +290,8 @@ private:
void MSTimer(); void MSTimer();
void ChangeChannel();
void RFTransfer_Type2(); void RFTransfer_Type2();
void RFTransfer_Type3(); void RFTransfer_Type3();
}; };

View File

@ -35,6 +35,7 @@ using Platform::LogLevel;
const char* WifiAP::APName = "melonAP"; const char* WifiAP::APName = "melonAP";
const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77}; const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77};
const u8 WifiAP::APChannel = 6;
#define PWRITE_8(p, v) *p++ = v; #define PWRITE_8(p, v) *p++ = v;
#define PWRITE_16(p, v) *(u16*)p = v; p += 2; #define PWRITE_16(p, v) *(u16*)p = v; p += 2;
@ -55,7 +56,7 @@ const u8 WifiAP::APMac[6] = {0x00, 0xF0, 0x77, 0x77, 0x77, 0x77};
PWRITE_16(p, 0); \ PWRITE_16(p, 0); \
PWRITE_16(p, 0); \ PWRITE_16(p, 0); \
PWRITE_8(p, rate); \ PWRITE_8(p, rate); \
PWRITE_8(p, 0); \ PWRITE_8(p, APChannel); \
PWRITE_16(p, len); PWRITE_16(p, len);
//#define PALIGN_4(p, base) p += ((4 - ((ptrdiff_t)(p-base) & 0x3)) & 0x3); //#define PALIGN_4(p, base) p += ((4 - ((ptrdiff_t)(p-base) & 0x3)) & 0x3);
@ -174,7 +175,7 @@ int WifiAP::HandleManagementFrame(const u8* data, int len)
PWRITE_16(p, 128); // beacon interval PWRITE_16(p, 128); // beacon interval
PWRITE_16(p, 0x0021); // capability PWRITE_16(p, 0x0021); // capability
PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates
PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, 0x06); // current channel PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, APChannel); // current channel
PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName)); PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName));
memcpy(p, APName, strlen(APName)); p += strlen(APName); memcpy(p, APName, strlen(APName)); p += strlen(APName);
@ -260,6 +261,9 @@ int WifiAP::HandleManagementFrame(const u8* data, int len)
int WifiAP::SendPacket(const u8* data, int len) int WifiAP::SendPacket(const u8* data, int len)
{ {
if (data[9] != APChannel)
return 0;
data += 12; data += 12;
u16 framectl = *(u16*)&data[0]; u16 framectl = *(u16*)&data[0];
@ -327,7 +331,7 @@ int WifiAP::RecvPacket(u8* data)
PWRITE_16(p, 128); // beacon interval PWRITE_16(p, 128); // beacon interval
PWRITE_16(p, 0x0021); // capability PWRITE_16(p, 0x0021); // capability
PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates PWRITE_8(p, 0x01); PWRITE_8(p, 0x02); PWRITE_8(p, 0x82); PWRITE_8(p, 0x84); // rates
PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, 0x06); // current channel PWRITE_8(p, 0x03); PWRITE_8(p, 0x01); PWRITE_8(p, APChannel); // current channel
PWRITE_8(p, 0x05); PWRITE_8(p, 0x04); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); // TIM PWRITE_8(p, 0x05); PWRITE_8(p, 0x04); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); PWRITE_8(p, 0); // TIM
PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName)); PWRITE_8(p, 0x00); PWRITE_8(p, strlen(APName));
memcpy(p, APName, strlen(APName)); p += strlen(APName); memcpy(p, APName, strlen(APName)); p += strlen(APName);

View File

@ -34,6 +34,7 @@ public:
static const char* APName; static const char* APName;
static const u8 APMac[6]; static const u8 APMac[6];
static const u8 APChannel;
void MSTimer(); void MSTimer();

View File

@ -805,7 +805,7 @@ void MainWindow::keyPressEvent(QKeyEvent* event)
if (event->isAutoRepeat()) return; if (event->isAutoRepeat()) return;
// TODO!! REMOVE ME IN RELEASE BUILDS!! // TODO!! REMOVE ME IN RELEASE BUILDS!!
//if (event->key() == Qt::Key_F11) NDS::debug(0); //if (event->key() == Qt::Key_F11) emuThread->NDS->debug(0);
Input::KeyPress(event); Input::KeyPress(event);
} }