diff --git a/desmume/src/NDSSystem.cpp b/desmume/src/NDSSystem.cpp index 7702f5b6c..1149b2fe4 100644 --- a/desmume/src/NDSSystem.cpp +++ b/desmume/src/NDSSystem.cpp @@ -197,6 +197,7 @@ int NDS_Init( void) { #ifdef EXPERIMENTAL_WIFI WIFI_Init(&wifiMac) ; + WIFI_SoftAP_Init(&wifiMac); #endif return 0; @@ -1086,14 +1087,17 @@ u32 NDS_exec(s32 nb) #endif } -#ifdef EXPERIMENTAL_WIFI +/*#ifdef EXPERIMENTAL_WIFI if((nds.ARM7Cycle % 0x3F03) == 0) { - /* 3F03 arm7 cyles = ~1usec */ + /* 3F03 arm7 cycles = ~1usec *-/ WIFI_usTrigger(&wifiMac) ; } -#endif +#endif*/ + + int nds7old = nds.ARM7Cycle; + if(nds.ARM7Cycle<=nds.cycles) { #ifdef LOG_ARM7 @@ -1126,6 +1130,22 @@ u32 NDS_exec(s32 nb) DisassemblerTools_Refresh(ARMCPU_ARM7); #endif } + +#ifdef EXPERIMENTAL_WIFI + /* TODO: the wifi stuff isn't actually clocked by the ARM7 clock, */ + /* but by a 22 mhz oscillator. */ + if(nds7old < nds.ARM7Cycle) + { + nds7old %= 67; + int nds7new = (nds.ARM7Cycle % 67); + + if(nds7old > nds7new) + { + WIFI_usTrigger(&wifiMac); + WIFI_SoftAP_usTrigger(&wifiMac); + } + } +#endif } if(!nds.sleeping) diff --git a/desmume/src/wifi.cpp b/desmume/src/wifi.cpp index cf6ff3d7a..897c3c7d2 100644 --- a/desmume/src/wifi.cpp +++ b/desmume/src/wifi.cpp @@ -127,7 +127,7 @@ const u8 FW_BBChannel[14] = { 0xb3, 0xb3, 0xb3, 0xb3, 0xb3, /* channel 1- 6 */ /* Note : the values are inspired from what I found in a firmware image from my DS */ -FW_WFCProfile FW_WFCProfile1 = {"DeSmuME Soft AP", +FW_WFCProfile FW_WFCProfile1 = {"SoftAP", "", "", "", @@ -413,6 +413,18 @@ static void WIFI_triggerIRQ(wifimac_t *wifi, u8 irq) WIFI_triggerIRQMask(wifi,1<RF) ; @@ -422,14 +434,27 @@ void WIFI_Init(wifimac_t *wifi) wifi->powerOnPending = FALSE; } +/*void WIFI_Thread(wifimac_t *wifi) +{ + for(;;) + { + WIFI_usTrigger(wifi); + WIFI_SoftAP_usTrigger(wifi); + WIFI_uSleep(wifi->udpSocket, 1); + } +}*/ + static void WIFI_RXPutWord(wifimac_t *wifi,u16 val) { +// printf("wifi: rx circbuf write attempt: rxcnt=%04X, rxread=%04X, rxwrite=%04X\n", +// wifi->RXCnt, wifi->RXReadCursor, wifi->RXHWWriteCursor); /* abort when RX data queuing is not enabled */ if (!(wifi->RXCnt & 0x8000)) return ; /* abort when ringbuffer is full */ if (wifi->RXReadCursor == wifi->RXHWWriteCursor) return ; /* write the data to cursor position */ - wifi->circularBuffer[wifi->RXHWWriteCursor & 0xFFF] ; + wifi->circularBuffer[wifi->RXHWWriteCursor & 0xFFF] = val; +// printf("wifi: written word %04X to circbuf addr %04X\n", val, (wifi->RXHWWriteCursor << 1)); /* move cursor by one */ wifi->RXHWWriteCursor++ ; /* wrap around */ @@ -447,11 +472,11 @@ static void WIFI_TXStart(wifimac_t *wifi,u8 slot) if (address > 0x1000-6) return ; /* 12 byte header TX Header: http://www.akkit.org/info/dswifi.htm#FmtTx */ - txLen = ntohs(wifi->circularBuffer[address+5]) ; + txLen = /*ntohs*/(wifi->circularBuffer[address+5]) ; /* zero length */ if (txLen==0) return ; /* unsupported txRate */ - switch (ntohs(wifi->circularBuffer[address+4])) + switch (/*ntohs*/(wifi->circularBuffer[address+4])) { case 10: /* 1 mbit */ case 20: /* 2 mbit */ @@ -464,6 +489,7 @@ static void WIFI_TXStart(wifimac_t *wifi,u8 slot) WIFI_triggerIRQ(wifi,/*WIFI_IRQ_SENDSTART*/7) ; WIFI_Host_SendData(wifi->udpSocket,wifi->channel,(u8 *)&wifi->circularBuffer[address],txLen) ; + WIFI_SoftAP_RecvPacketFromDS(wifi, (u8*)&wifi->circularBuffer[address+6], txLen); WIFI_triggerIRQ(wifi,/*WIFI_IRQ_SENDCOMPLETE*/1) ; } } @@ -554,15 +580,21 @@ void WIFI_write16(wifimac_t *wifi,u32 address, u16 val) wifi->powerOnPending = FALSE; } break; + case REG_WIFI_RXCNT: + wifi->RXCnt = val; + break; case REG_WIFI_RXRANGEBEGIN: wifi->RXRangeBegin = val ; + // printf("wifi: rx range begin=%04X\n", val); break ; case REG_WIFI_RXRANGEEND: wifi->RXRangeEnd = val ; + //printf("wifi: rx range end=%04X\n", val); break ; case REG_WIFI_WRITECSRLATCH: if ((action) && (wifi->RXCnt & 1)) /* only when action register and CSR change enabled */ { + // printf("wifi: rx write cursor=%04X\n", (val << 1)); wifi->RXHWWriteCursor = val ; } break ; @@ -595,6 +627,7 @@ void WIFI_write16(wifimac_t *wifi,u32 address, u16 val) case REG_WIFI_BEACONTRANS: wifi->BEACONSlot = val & 0x7FFF ; wifi->BEACON_enable = (val & 0x8000) != 0 ; + //printf("wifi beacon: enable=%s, addr=%04X\n", (wifi->BEACON_enable?"yes":"no"), (wifi->BEACONSlot<<1)); break ; case REG_WIFI_TXLOC1: case REG_WIFI_TXLOC2: @@ -606,7 +639,7 @@ void WIFI_write16(wifimac_t *wifi,u32 address, u16 val) { /* reset TX logic */ /* CHECKME */ - wifi->TXSlot[0] = 0 ; wifi->TXSlot[1] = 0 ; wifi->TXSlot[2] = 0 ; + // wifi->TXSlot[0] = 0 ; wifi->TXSlot[1] = 0 ; wifi->TXSlot[2] = 0 ; wifi->TXOpt = 0 ; wifi->TXCnt = 0 ; } else @@ -700,10 +733,11 @@ u16 WIFI_read16(wifimac_t *wifi,u32 address) if (((address & 0x00007000) >= 0x00004000) && ((address & 0x00007000) < 0x00006000)) { /* access to the circular buffer */ + //printf("wifi: circbuf read at %04X\n", (address & 0x1FFF)); return wifi->circularBuffer[(address & 0x1FFF) >> 1] ; } if (!(address & 0x00007000)) action = TRUE ; -// if((address != 0x04808214) && (address != 0x0480803C)) + //if((address != 0x04808214) && (address != 0x0480803C) && (address != 0x048080F8) && (address != 0x048080FA) && (address != 0x0480819C)) // printf("wifi read at %08X\n", address); /* mirrors => register address */ address &= 0x00000FFF ; @@ -742,6 +776,8 @@ u16 WIFI_read16(wifimac_t *wifi,u32 address) case REG_WIFI_BSS1: case REG_WIFI_BSS2: return wifi->bss.words[(address - REG_WIFI_BSS0) >> 1] ; + case REG_WIFI_RXCNT: + return wifi->RXCnt; case REG_WIFI_RXRANGEBEGIN: return wifi->RXRangeBegin ; case REG_WIFI_CIRCBUFREAD: @@ -775,12 +811,22 @@ u16 WIFI_read16(wifimac_t *wifi,u32 address) return temp; case REG_WIFI_CIRCBUFRADR: return wifi->CircBufReadAddress ; + case REG_WIFI_RXREADCSR: + return wifi->RXReadCursor; case REG_WIFI_RXBUF_COUNT: return wifi->RXBufCount ; case REG_WIFI_EXTRACOUNTCNT: return wifi->eCountEnable?1:0 ; case REG_WIFI_EXTRACOUNT: return wifi->eCount ; + case REG_WIFI_USCOMPARE0: + return (wifi->usec & 0xFFFF); + case REG_WIFI_USCOMPARE1: + return ((wifi->usec >> 16) & 0xFFFF); + case REG_WIFI_USCOMPARE2: + return ((wifi->usec >> 32) & 0xFFFF); + case REG_WIFI_USCOMPARE3: + return ((wifi->usec >> 48) & 0xFFFF); case REG_WIFI_POWER_US: return wifi->crystalEnabled?0:1 ; case REG_WIFI_CIRCBUFRD_END: @@ -840,6 +886,262 @@ void WIFI_usTrigger(wifimac_t *wifi) } } +/******************************************************************************* + + SoftAP (fake wifi access point) + + *******************************************************************************/ + +u32 SoftAP_CRC32Table[256]; + +u8 SoftAP_MACAddr[6] = {0x00, 0xF0, 0x1A, 0x2B, 0x3C, 0x4D}; + +u8 SoftAP_Beacon[58] = { + /* 802.11 header */ + 0x80, 0x00, // Frame control + 0x00, 0x00, // Duration ID + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Receiver + 0x00, 0xF0, 0x1A, 0x2B, 0x3C, 0x4D, // Sender + 0x00, 0xF0, 0x1A, 0x2B, 0x3C, 0x4D, // BSSID + 0x00, 0x00, // Sequence control + + /* Frame body */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x64, 0x00, // Beacon interval + 0xFF, 0xFF, // Capablilty information + 0x00, 0x06, 'S', 'o', 'f', 't', 'A', 'P', // SSID + 0x01, 0x02, 0x82, 0x84, // Supported rates + 0x05, 0x04, 0x00, 0x00, 0x00, 0x00, // TIM + + /* CRC32 */ + 0x00, 0x00, 0x00, 0x00 +}; + +u8 SoftAP_ProbeResponse[52] = { + /* 802.11 header */ + 0x50, 0x00, // Frame control + 0x00, 0x00, // Duration ID + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Receiver + 0x00, 0xF0, 0x1A, 0x2B, 0x3C, 0x4D, // Sender + 0x00, 0xF0, 0x1A, 0x2B, 0x3C, 0x4D, // BSSID + 0x00, 0x00, // Sequence control + + /* Frame body */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Timestamp + 0x64, 0x00, // Beacon interval + 0xFF, 0xFF, // Capablilty information + 0x00, 0x06, 'S', 'o', 'f', 't', 'A', 'P', // SSID + 0x01, 0x02, 0x82, 0x84, // Supported rates + + /* CRC32 */ + 0x00, 0x00, 0x00, 0x00 +}; + +// http://www.codeproject.com/KB/recipes/crc32_large.aspx +u32 reflect(u32 ref, char ch) +{ + u32 value = 0; + + for(int i = 1; i < (ch + 1); i++) + { + if (ref & 1) + value |= 1 << (ch - i); + ref >>= 1; + } + + return value; +} + +// http://www.codeproject.com/KB/recipes/crc32_large.aspx +u32 WIFI_SoftAP_GetCRC32(u8 *data, int len) +{ + u32 crc = 0xFFFFFFFF; + + while(len--) + crc = (crc >> 8) ^ SoftAP_CRC32Table[(crc & 0xFF) ^ *data++]; + + return (crc ^ 0xFFFFFFFF); +} + +int WIFI_SoftAP_Init(wifimac_t *wifi) +{ + sockaddr_t addr; + + wifi->SoftAP.sock = socket(AF_INET, SOCK_RAW, 0); + + memset(&addr, 0, sizeof(addr)); + addr.sa_family = AF_INET; + *(u32*)&addr.sa_data[2] = htonl(INADDR_ANY); + *(u16*)&addr.sa_data[0] = htons(80); + bind(wifi->SoftAP.sock, &addr, sizeof(addr)); + + wifi->SoftAP.usecCounter = 0; + + wifi->SoftAP.curPacket = NULL; + wifi->SoftAP.curPacketSize = 0; + wifi->SoftAP.curPacketPos = 0; + wifi->SoftAP.curPacketSending = FALSE; + + // http://www.codeproject.com/KB/recipes/crc32_large.aspx + u32 polynomial = 0x04C11DB7; + + for(int i = 0; i < 0x100; i++) + { + SoftAP_CRC32Table[i] = reflect(i, 8) << 24; + for(int j = 0; j < 8; j++) + SoftAP_CRC32Table[i] = (SoftAP_CRC32Table[i] << 1) ^ (SoftAP_CRC32Table[i] & (1 << 31) ? polynomial : 0); + SoftAP_CRC32Table[i] = reflect(SoftAP_CRC32Table[i], 32); + } + + return 1; +} + +void WIFI_SoftAP_Shutdown(wifimac_t *wifi) +{ + // +} + +/*void WIFI_SoftAP_SendWordToDS(wifimac_t *wifi, u16 data) +{ + if(wifi->RXCnt & 0x8000) + { + // + } +}*/ + +void WIFI_SoftAP_RecvPacketFromDS(wifimac_t *wifi, u8 *packet, int len) +{ + u16 frameCtl = *(u16*)&packet[0]; + + //printf("wifi: packet arrived, frame ctl = %04X\n", frameCtl); + + switch((frameCtl >> 2) & 0x3) + { + case 0: + { + switch((frameCtl >> 4) & 0xF) + { + case 4: // Probe request + { + u8 proberes[52]; + + memcpy(proberes, SoftAP_ProbeResponse, 52); + u64 timestamp = (wifi->SoftAP.usecCounter / 1000); // FIXME: is it correct? + *(u64*)&proberes[24] = timestamp; + u32 crc32 = WIFI_SoftAP_GetCRC32(proberes, 48); + *(u32*)&proberes[48] = crc32; + + if(wifi->SoftAP.curPacket) + delete wifi->SoftAP.curPacket; + + wifi->SoftAP.curPacket = new u8[52+12]; + + wifi->SoftAP.curPacket[0] = 0x11; + wifi->SoftAP.curPacket[1] = 0x00; + wifi->SoftAP.curPacket[2] = 0x40; + wifi->SoftAP.curPacket[3] = 0x00; + wifi->SoftAP.curPacket[4] = 0x01; + wifi->SoftAP.curPacket[5] = 0x00; + wifi->SoftAP.curPacket[6] = 0x14; + wifi->SoftAP.curPacket[7] = 0x00; + wifi->SoftAP.curPacket[8] = 0x30; + wifi->SoftAP.curPacket[9] = 0x00; + wifi->SoftAP.curPacket[10] = 0x00; + wifi->SoftAP.curPacket[11] = 0x00; + + memcpy((wifi->SoftAP.curPacket+12), proberes, 52); + wifi->SoftAP.curPacketSize = 52+12; + wifi->SoftAP.curPacketPos = 0; + wifi->SoftAP.curPacketSending = TRUE; + } + break; + } + } + break; + } +} + +void WIFI_SoftAP_SendToNetwork(wifimac_t *wifi) +{ + // +} + +void WIFI_SoftAP_RecvFromNetwork(wifimac_t *wifi) +{ + // +} + +void WIFI_SoftAP_SendBeacon(wifimac_t *wifi) +{ + u8 beacon[58]; + + memcpy(beacon, SoftAP_Beacon, 58); + u64 timestamp = (wifi->SoftAP.usecCounter / 1000); // FIXME: is it correct? + *(u64*)&beacon[24] = timestamp; + u32 crc32 = WIFI_SoftAP_GetCRC32(beacon, 54); + *(u32*)&beacon[54] = crc32; + + if(wifi->SoftAP.curPacket) + delete wifi->SoftAP.curPacket; + + wifi->SoftAP.curPacket = new u8[58+12]; + + wifi->SoftAP.curPacket[0] = 0x11; + wifi->SoftAP.curPacket[1] = 0x00; + wifi->SoftAP.curPacket[2] = 0x40; + wifi->SoftAP.curPacket[3] = 0x00; + wifi->SoftAP.curPacket[4] = 0x64; + wifi->SoftAP.curPacket[5] = 0x00; + wifi->SoftAP.curPacket[6] = 0x14; + wifi->SoftAP.curPacket[7] = 0x00; + wifi->SoftAP.curPacket[8] = 0x36; + wifi->SoftAP.curPacket[9] = 0x00; + wifi->SoftAP.curPacket[10] = 0x00; + wifi->SoftAP.curPacket[11] = 0x00; + + memcpy((wifi->SoftAP.curPacket+12), beacon, 58); + + wifi->SoftAP.curPacketSize = 58+12; + wifi->SoftAP.curPacketPos = 0; + wifi->SoftAP.curPacketSending = TRUE; +} + +void WIFI_SoftAP_usTrigger(wifimac_t *wifi) +{ + wifi->SoftAP.usecCounter++; + + if(!wifi->SoftAP.curPacketSending) + { + if((wifi->SoftAP.usecCounter % 100000) == 0) + { + WIFI_SoftAP_SendBeacon(wifi); + } + } + + /* Given a connection of 2 megabits per second, */ + /* we take ~4 microseconds to transfer a byte, */ + /* ie ~8 microseconds to transfer a word. */ + if((wifi->SoftAP.curPacketSending) && !(wifi->SoftAP.usecCounter & 7)) + { + if(wifi->SoftAP.curPacketPos == 0) + WIFI_triggerIRQ(wifi, 6); + + u16 word = wifi->SoftAP.curPacket[wifi->SoftAP.curPacketPos]; + //WIFI_SoftAP_SendWordToDS(wifi, word); + WIFI_RXPutWord(wifi, word); + + wifi->SoftAP.curPacketPos++; + if(wifi->SoftAP.curPacketPos == wifi->SoftAP.curPacketSize) + { + wifi->SoftAP.curPacketSize = 0; + wifi->SoftAP.curPacketPos = 0; + wifi->SoftAP.curPacketSending = FALSE; + + WIFI_triggerIRQ(wifi, 0); + } + } +} + /******************************************************************************* Host system operations @@ -874,6 +1176,7 @@ void WIFI_Host_CloseChannel(socket_t sock) void WIFI_Host_SendData(socket_t sock, u8 channel, u8 *data, u16 length) { + //printf("wifi: sending packet of length %i on channel %i\n", length, channel); sockaddr_t address ; /* create the frame to validate data: "DSWIFI" string and a u16 constant of the payload length */ u8 *frame = (u8 *)malloc(length + 8) ; @@ -904,6 +1207,7 @@ u16 WIFI_Host_RecvData(socket_t sock, u8 *data, u16 maxLength) { /* there is data available */ u32 receivedBytes = recv(sock,(char*)data,maxLength,0) ; + //printf("wifi: received %i bytes\n", receivedBytes); if (receivedBytes < 8) return 0 ; /* this cant be data for us, the header alone is 8 bytes */ if (memcmp(data,"DSWIFI",6)!=0) return 0 ; /* this isnt data for us, as the tag is not our */ if (ntohs(*(u16 *)(data+6))+8 != receivedBytes) return 0 ; /* the datalen+headerlen is not what we received */ diff --git a/desmume/src/wifi.h b/desmume/src/wifi.h index 05a46974e..cce0dcfb7 100644 --- a/desmume/src/wifi.h +++ b/desmume/src/wifi.h @@ -58,6 +58,7 @@ #define REG_WIFI_AID_LOW 0x028 #define REG_WIFI_AID_HIGH 0x02A #define REG_WIFI_RETRYLIMIT 0x02C +#define REG_WIFI_RXCNT 0x030 #define REG_WIFI_WEPCNT 0x032 #define REG_WIFI_POWER_US 0x036 #define REG_WIFI_POWERSTATE 0x03C @@ -452,6 +453,20 @@ typedef struct /* others */ u16 randomSeed ; + /* SoftAP */ + struct _SoftAP + { + socket_t sock; + + u64 usecCounter; + + u8 *curPacket; + int curPacketSize; + int curPacketPos; + BOOL curPacketSending; + + } SoftAP; + /* desmume host communication */ socket_t udpSocket ; u8 channel ; @@ -462,6 +477,8 @@ extern wifimac_t wifiMac ; void WIFI_Init(wifimac_t *wifi); +//void WIFI_Thread(wifimac_t *wifi); + /* subchip communication IO functions */ void WIFI_setRF_CNT(wifimac_t *wifi, u16 val) ; void WIFI_setRF_DATA(wifimac_t *wifi, u16 val, u8 part) ; @@ -479,6 +496,24 @@ u16 WIFI_read16(wifimac_t *wifi,u32 address) ; /* wifimac timing */ void WIFI_usTrigger(wifimac_t *wifi) ; +/* SoftAP */ + +typedef struct _WIFI_FrameHeader +{ + u8 FrameControl[2]; + u8 DurationID[2]; + u8 Receiver[6]; + u8 Sender[6]; + u8 BSSID[6]; + u8 SeqCtl[2]; + +} WIFI_FrameHeader; + +int WIFI_SoftAP_Init(wifimac_t *wifi); +void WIFI_SoftAP_Shutdown(wifimac_t *wifi); +void WIFI_SoftAP_RecvPacketFromDS(wifimac_t *wifi, u8 *packet, int len); +void WIFI_SoftAP_usTrigger(wifimac_t *wifi); + #endif /* DS WFC profile data documented here : */