From 2fdb5e638e023408697be8950e776e8f8ffd2590 Mon Sep 17 00:00:00 2001 From: FIX94 Date: Fri, 8 Apr 2016 23:10:13 +0200 Subject: added experimental save support (only tested with EEPROM) --- gba/source/libSave.c | 677 +++++++++++++++++++++++++++++++++++++++++++++++++++ gba/source/libSave.h | 27 ++ gba/source/main.c | 134 ++++++++-- source/main.c | 231 ++++++++++++++---- 4 files changed, 998 insertions(+), 71 deletions(-) create mode 100644 gba/source/libSave.c create mode 100644 gba/source/libSave.h diff --git a/gba/source/libSave.c b/gba/source/libSave.c new file mode 100644 index 0000000..1ae8162 --- /dev/null +++ b/gba/source/libSave.c @@ -0,0 +1,677 @@ +/* + libSave + Cartridge backup memory save routines. To use, call the required + routine with a pointer to an appropriately sized array of data to + be read from or written to the cartridge. + Data types are from wintermute's gba_types.h libgba library. +*/ + +#include +#include +#include +//--------------------------------------------------------------------------------- +#ifndef _gba_types_h_ +#define _gba_types_h_ +//--------------------------------------------------------------------------------- + +//--------------------------------------------------------------------------------- +// Data types +//--------------------------------------------------------------------------------- +/** Unsigned 8 bit value + +*/ +typedef unsigned char u8; +/** Unsigned 16 bit value + +*/ +typedef unsigned short int u16; +/** Unsigned 32 bit value + +*/ +typedef unsigned int u32; + +/** signed 8 bit value + +*/ +typedef signed char s8; +/** Signed 16 bit value + +*/ +typedef signed short int s16; +/** Signed 32 bit value + +*/ +typedef signed int s32; + +/** Unsigned volatile 8 bit value + +*/ +typedef volatile u8 vu8; +/** Unsigned volatile 16 bit value + +*/ +typedef volatile u16 vu16; +/** Unsigned volatile 32 bit value + +*/ +typedef volatile u32 vu32; + +/** Unsigned volatile 8 bit value + +*/ +typedef volatile s8 vs8; +/** Signed volatile 16 bit value + +*/ +typedef volatile s16 vs16; +/** Signed volatile 32 bit value + +*/ +typedef volatile s32 vs32; + +#ifndef __cplusplus +/** C++ compatible bool for C + +*/ +typedef enum { false, true } bool; +#endif + +//--------------------------------------------------------------------------------- +#endif // data types +//--------------------------------------------------------------------------------- + + +#define EEPROM_ADDRESS (volatile u16*)0xDFFFF00 +#define SRAM_ADDRESS (volatile u16*)0x0E000000 +#define FLASH_1M_ADDRESS (volatile u16*)0x09FE0000 +#define REG_EEPROM (*(volatile u16*)0xDFFFF00) +#define REG_DM3SAD (*(volatile u32*)0x40000D4) +#define REG_DM3DAD (*(volatile u32*)0x40000D8) +#define REG_DM3CNT (*(volatile u32*)0x40000DC) + + +//----------------------------------------------------------------------- +// Common EEPROM Routines +//----------------------------------------------------------------------- + +void EEPROM_SendPacket( u16* packet, int size ) +{ + REG_DM3SAD = (u32)packet; + REG_DM3DAD = (u32)EEPROM_ADDRESS; + REG_DM3CNT = 0x80000000 + size; +} + +void EEPROM_ReceivePacket( u16* packet, int size ) +{ + REG_DM3SAD = (u32)EEPROM_ADDRESS; + REG_DM3DAD = (u32)packet; + REG_DM3CNT = 0x80000000 + size; +} + +//----------------------------------------------------------------------- +// Routines for 512B EEPROM +//----------------------------------------------------------------------- + +void EEPROM_Read_512B( volatile u8 offset, u8* dest ) // dest must point to 8 bytes +{ + u16 packet[68]; + u8* out_pos; + u16* in_pos; + u8 out_byte; + int byte, bit; + + memset( packet, 0, 68*2 ); + + // Read request + packet[0] = 1; + packet[1] = 1; + + // 6 bits eeprom address (MSB first) + packet[2] = (offset>>5)&1; + packet[3] = (offset>>4)&1; + packet[4] = (offset>>3)&1; + packet[5] = (offset>>2)&1; + packet[6] = (offset>>1)&1; + packet[7] = (offset)&1; + + // End of request + packet[8] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 9 ); + memset( packet, 0, 68*2 ); + EEPROM_ReceivePacket( packet, 68 ); + + // Extract data + in_pos = &packet[4]; + out_pos = dest; + for( byte = 7; byte >= 0; --byte ) + { + out_byte = 0; + for( bit = 7; bit >= 0; --bit ) + { +// out_byte += (*in_pos++)<>5)&1; + packet[3] = (offset>>4)&1; + packet[4] = (offset>>3)&1; + packet[5] = (offset>>2)&1; + packet[6] = (offset>>1)&1; + packet[7] = (offset)&1; + + // Extract data + in_pos = source; + out_pos = &packet[8]; + for( byte = 7; byte >= 0; --byte ) + { + in_byte = *in_pos++; + for( bit = 7; bit >= 0; --bit ) + { + *out_pos++ = in_byte>>bit; + } + } + + // End of request + packet[72] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 73 ); + + // Wait for EEPROM to finish (should timeout after 10 ms) + while( (REG_EEPROM & 1) == 0 ); +} + +//--------------------------------------------------------------------------------- +void GetSave_EEPROM_512B(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<64;++x){ + EEPROM_Read_512B(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } +} + +//--------------------------------------------------------------------------------- +void PutSave_EEPROM_512B(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<64;x++){ + EEPROM_Write_512B(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } +} +//----------------------------------------------------------------------- +// Routines for 8KB EEPROM +//----------------------------------------------------------------------- + +void EEPROM_Read_8KB( volatile u16 offset, u8* dest ) // dest must point to 8 bytes +{ + u16 packet[68]; + u8* out_pos; + u16* in_pos; + u8 out_byte; + int byte, bit; + + memset( packet, 0, 68*2 ); + + // Read request + packet[0] = 1; + packet[1] = 1; + + // 14 bits eeprom address (MSB first) + packet[2] = (offset>>13)&1; + packet[3] = (offset>>12)&1; + packet[4] = (offset>>11)&1; + packet[5] = (offset>>10)&1; + packet[6] = (offset>>9)&1; + packet[7] = (offset>>8)&1; + packet[8] = (offset>>7)&1; + packet[9] = (offset>>6)&1; + packet[10] = (offset>>5)&1; + packet[11] = (offset>>4)&1; + packet[12] = (offset>>3)&1; + packet[13] = (offset>>2)&1; + packet[14] = (offset>>1)&1; + packet[15] = (offset)&1; + + // End of request + packet[16] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 17 ); + memset( packet, 0, 68*2 ); + EEPROM_ReceivePacket( packet, 68 ); + + // Extract data + in_pos = &packet[4]; + out_pos = dest; + for( byte = 7; byte >= 0; --byte ) + { + out_byte = 0; + for( bit = 7; bit >= 0; --bit ) + { +// out_byte += (*in_pos++)<>13)&1; + packet[3] = (offset>>12)&1; + packet[4] = (offset>>11)&1; + packet[5] = (offset>>10)&1; + packet[6] = (offset>>9)&1; + packet[7] = (offset>>8)&1; + packet[8] = (offset>>7)&1; + packet[9] = (offset>>6)&1; + packet[10] = (offset>>5)&1; + packet[11] = (offset>>4)&1; + packet[12] = (offset>>3)&1; + packet[13] = (offset>>2)&1; + packet[14] = (offset>>1)&1; + packet[15] = (offset)&1; + + // Extract data + in_pos = source; + out_pos = &packet[16]; + for( byte = 7; byte >= 0; --byte ) + { + in_byte = *in_pos++; + for( bit = 7; bit >= 0; --bit ) + { + *out_pos++ = (in_byte>>bit)&1; + } + } + + // End of request + packet[80] = 0; + + // Do transfers + EEPROM_SendPacket( packet, 81 ); + + // Wait for EEPROM to finish (should timeout after 10 ms) + while( (REG_EEPROM & 1) == 0 ); +} + +//--------------------------------------------------------------------------------- +void GetSave_EEPROM_8KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u16 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<1024;x++){ + EEPROM_Read_8KB(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } + +} + +//--------------------------------------------------------------------------------- +void PutSave_EEPROM_8KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u16 x; + u32 sleep; + + // Set up waitstates for EEPROM access etc. + *(volatile unsigned short *)0x04000204 = 0x4317; + + for (x=0;x<1024;x++){ + EEPROM_Write_8KB(x,&data[x*8]); + for(sleep=0;sleep<512000;sleep++); + } +} + +//--------------------------------------------------------------------------------- +void GetSave_SRAM_32KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 *sram= (u8*) 0x0E000000; + volatile u16 x; + + for (x = 0; x < 0x8000; ++x) + { + data[x] = sram[x]; + } + +} + +//--------------------------------------------------------------------------------- +void PutSave_SRAM_32KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 *sram= (u8*) 0x0E000000; + volatile u16 x; + + for (x = 0; x < 0x8000; ++x) + { + sram[x] = data[x]; + } +} + +//--------------------------------------------------------------------------------- +void GetSave_FLASH_64KB(u8* data) +//--------------------------------------------------------------------------------- +{ + volatile u8 *sram= (u8*) 0x0E000000; + volatile u32 x; + + for (x = 0; x < 0x10000; ++x) + { + data[x] = sram[x]; + } +} + +//--------------------------------------------------------------------------------- +void PutSave_FLASH_64KB(u8* foo) +//--------------------------------------------------------------------------------- +{ + volatile u8 *fctrl0 = (u8*) 0xE005555; + volatile u8 *fctrl1 = (u8*) 0xE002AAA; + volatile u8 *fctrl2 = (u8*) 0xE000000; + + //init flash + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x90; + *fctrl2 = 0xF0; + + //erase chip + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x80; + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x10; + + //wait for erase done + u8 val1; + u8 val2; + val1 = *fctrl2; + val2 = *fctrl2; + while (val1 != val2) { + val1 = *fctrl2; + val2 = *fctrl2; + } + val1 = *fctrl2; + val2 = *fctrl2; + while (val1 != val2) { + val1 = *fctrl2; + val2 = *fctrl2; + } + + volatile u8 *data = fctrl2; + u32 i; + //write data + for (i=0; i<65536; i++) { + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0xA0; + data [i] = foo [ i ]; + val1 = data [ i ]; + val2 = data [ i ]; + + while (val1 != val2) { + val1 = data [ i ]; + val2 = data [ i ]; + } + val1 = data [ i ]; + val2 = data [ i ]; + while (val1 != val2) { + val1 = data [ i ]; + val2 = data [ i ]; + } + val1 = data [ i ]; + val2 = data [ i ]; + while (val1 != val2) { + val1 = data [ i ]; + val2 = data [ i ]; + } + } +} + +//--------------------------------------------------------------------------------- +void GetSave_FLASH_128KB(u8* data) +//--------------------------------------------------------------------------------- +{ + const u32 size = 0x10000; + + volatile u8 *fctrl0 = (u8*) 0xE005555; + volatile u8 *fctrl1 = (u8*) 0xE002AAA; + volatile u8 *fctrl2 = (u8*) 0xE000000; + volatile u32 i; + volatile u8 *sram= (u8*) 0x0E000000; + + //init flash + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0x90; + *fctrl2 = 0xF0; + + // read first bank + *fctrl0 = 0xAA; + *fctrl1 = 0x55; + *fctrl0 = 0xB0; + *fctrl2 = 0x00; + + for (i=0; i=0;x--){ + switch (pak[x]) { + case 0x53414C46: + if (pak[x+1] == 0x5F4D3148){ + return 0x20000; // FLASH_128KB + } else if ((pak[x+1] & 0x0000FFFF) == 0x00005F48){ + return 0x10000; // FLASH_64KB + } else if (pak[x+1] == 0x32313548){ + return 0x10000; // FLASH_64KB + } + break; + case 0x52504545: + if ((pak[x+1] & 0x00FFFFFF) == 0x005F4D4F){ + GetSave_EEPROM_8KB(data); + if (memcmp(data,data+0x200,8) != 0 || + memcmp(data,data+0x400,8) != 0 || + memcmp(data,data+0x600,8) != 0){ + return 0x2000; //EEPROM_8KB + } + return 0x200; // EEPROM_512B + } + break; + case 0x4D415253: + if ((pak[x+1] & 0x000000FF) == 0x0000005F){ + return 0x8000; // SRAM_32KB + } + } + } + return 0; +} + diff --git a/gba/source/libSave.h b/gba/source/libSave.h new file mode 100644 index 0000000..5ecf822 --- /dev/null +++ b/gba/source/libSave.h @@ -0,0 +1,27 @@ + + +//--------------------------------------------------------------------------------- +#ifdef __cplusplus +extern "C" { +#endif +//--------------------------------------------------------------------------------- + +void GetSave_EEPROM_512B(u8* data); +void PutSave_EEPROM_512B(u8* data); +void GetSave_EEPROM_8KB(u8* data); +void PutSave_EEPROM_8KB(u8* data); +void GetSave_SRAM_32KB(u8* data); +void PutSave_SRAM_32KB(u8* data); +void GetSave_FLASH_64KB(u8* data); +void PutSave_FLASH_64KB(u8* foo); +void GetSave_FLASH_128KB(u8* data); +void PutSave_FLASH_128KB(u8* foo); + +u32 SaveSize(u8* data, s32 gamesize); + + +//--------------------------------------------------------------------------------- +#ifdef __cplusplus +} // extern "C" +#endif +//--------------------------------------------------------------------------------- diff --git a/gba/source/main.c b/gba/source/main.c index 9d05189..567165a 100644 --- a/gba/source/main.c +++ b/gba/source/main.c @@ -7,12 +7,15 @@ #include #include #include +#include "libSave.h" -u32 getGameSize(void) +u8 save_data[0x20000] __attribute__ ((section (".sbss"))); + +s32 getGameSize(void) { if(*(vu32*)(0x08000004) != 0x51AEFF24) - return 0; - u32 i; + return -1; + s32 i; for(i = (1<<20); i < (1<<25); i<<=1) { vu16 *rompos = (vu16*)(0x08000000+i); @@ -30,6 +33,8 @@ u32 getGameSize(void) } return i; } +#define JOY_WRITE 2 +#define JOY_READ 4 //--------------------------------------------------------------------------------- // Program entry point //--------------------------------------------------------------------------------- @@ -49,43 +54,132 @@ int main(void) { u32 i; iprintf("\x1b[9;10HROM Dumper\n"); iprintf("\x1b[10;5HPlease look at the TV\n"); - REG_HS_CTRL |= 6; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + u32 prevIrqMask = REG_IME; while (1) { - if((REG_HS_CTRL&4)) + if((REG_HS_CTRL&JOY_READ)) { - REG_HS_CTRL |= 4; - u32 gamesize = getGameSize(); + irqDisable(IRQ_VBLANK); + REG_IME = 0; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + s32 gamesize = getGameSize(); + u32 savesize = SaveSize(save_data,gamesize); REG_JOYTR = gamesize; - while((REG_HS_CTRL&4) == 0) ; - REG_HS_CTRL |= 4; - if(gamesize == 0) + //wait for a cmd receive for safety + while((REG_HS_CTRL&JOY_WRITE) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + REG_JOYTR = savesize; + //wait for a cmd receive for safety + while((REG_HS_CTRL&JOY_WRITE) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + if(gamesize == -1) { REG_JOYTR = 0; + REG_IME = prevIrqMask; + irqEnable(IRQ_VBLANK); continue; //nothing to read } //game in, send header for(i = 0; i < 0xC0; i+=4) { REG_JOYTR = *(vu32*)(0x08000000+i); - while((REG_HS_CTRL&4) == 0) ; - REG_HS_CTRL |= 4; + while((REG_HS_CTRL&JOY_READ) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); } + REG_JOYTR = 0; //wait for other side to choose - while((REG_HS_CTRL&2) == 0) ; - REG_HS_CTRL |= 2; - if(REG_JOYRE == 0) + while((REG_HS_CTRL&JOY_WRITE) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + u32 choseval = REG_JOYRE; + if(choseval == 0) { REG_JOYTR = 0; + REG_IME = prevIrqMask; + irqEnable(IRQ_VBLANK); continue; //nothing to read } - //dump the game - for(i = 0; i < gamesize; i+=4) + else if(choseval == 1) { - REG_JOYTR = *(vu32*)(0x08000000+i); - while((REG_HS_CTRL&4) == 0) ; - REG_HS_CTRL |= 4; + //dump the game + for(i = 0; i < gamesize; i+=4) + { + REG_JOYTR = *(vu32*)(0x08000000+i); + while((REG_HS_CTRL&JOY_READ) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + } + } + else if(choseval == 2) + { + //backup save + switch (savesize){ + case 0x200: + GetSave_EEPROM_512B(save_data); + break; + case 0x2000: + GetSave_EEPROM_8KB(save_data); + break; + case 0x8000: + GetSave_SRAM_32KB(save_data); + break; + case 0x10000: + GetSave_FLASH_64KB(save_data); + break; + case 0x20000: + GetSave_FLASH_128KB(save_data); + break; + default: + break; + } + REG_JOYTR = savesize; + //wait for a cmd receive for safety + while((REG_HS_CTRL&JOY_WRITE) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + //send the save + for(i = 0; i < savesize; i+=4) + { + REG_JOYTR = *(vu32*)(save_data+i); + while((REG_HS_CTRL&JOY_READ) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + } + } + else if(choseval == 3) + { + REG_JOYTR = savesize; + //receive the save + for(i = 0; i < savesize; i+=4) + { + while((REG_HS_CTRL&JOY_WRITE) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); + *(vu32*)(save_data+i) = REG_JOYRE; + } + //write it + switch (savesize){ + case 0x200: + PutSave_EEPROM_512B(save_data); + break; + case 0x2000: + PutSave_EEPROM_8KB(save_data); + break; + case 0x8000: + PutSave_SRAM_32KB(save_data); + break; + case 0x10000: + PutSave_FLASH_64KB(save_data); + break; + case 0x20000: + PutSave_FLASH_128KB(save_data); + break; + default: + break; + } + REG_JOYTR = 0; + //wait for a cmd receive for safety + while((REG_HS_CTRL&JOY_WRITE) == 0) ; + REG_HS_CTRL |= (JOY_WRITE|JOY_READ); } REG_JOYTR = 0; + REG_IME = prevIrqMask; + irqEnable(IRQ_VBLANK); } Halt(); } diff --git a/source/main.c b/source/main.c index afe3423..ee23263 100644 --- a/source/main.c +++ b/source/main.c @@ -23,7 +23,8 @@ void printmain() { printf("\x1b[2J"); printf("\x1b[37m"); - printf("GBA Link Cable Dumper v1.0 by FIX94\n"); + printf("GBA Link Cable Dumper v1.1 by FIX94\n"); + printf("Save Support based on SendSave by Chishm\n"); } u8 *resbuf,*cmdbuf; @@ -299,9 +300,17 @@ int main(int argc, char *argv[]) { if(recvsafe() == 0) //ready { - sleep(1); //gba rom prepare - u32 gbasize = __builtin_bswap32(recvsafe()); - if(gbasize == 0) + printf("Waiting for GBA\n"); + VIDEO_WaitVSync(); + int gbasize = 0; + while(gbasize == 0) + gbasize = __builtin_bswap32(recvsafe()); + sendsafe(0); //got gbasize + usleep(5000); //wait for it to set next val + u32 savesize = __builtin_bswap32(recvsafe()); + sendsafe(0); //got savesize + usleep(5000); //wait for it to set next val + if(gbasize == -1) { printf("ERROR: No (Valid) GBA Card inserted!\n"); VIDEO_WaitVSync(); @@ -309,29 +318,36 @@ int main(int argc, char *argv[]) sleep(2); continue; } + //get rom header for(i = 0; i < 0xC0; i+=4) *(vu32*)(testdump+i) = recvfast(); + //print out all the info from the game printf("Game Name: %.12s\n",(char*)(testdump+0xA0)); printf("Game ID: %.4s\n",(char*)(testdump+0xAC)); printf("Company ID: %.2s\n",(char*)(testdump+0xB0)); - printf("ROM Size: %02.02f MB\n \n",((float)(gbasize/1024))/1024.f); + printf("ROM Size: %02.02f MB\n",((float)(gbasize/1024))/1024.f); + if(savesize > 0) + printf("Save Size: %02.02f KB\n \n",((float)(savesize))/1024.f); + else + printf("No Save File\n \n"); + //generate file paths char gamename[64]; sprintf(gamename,"/dumps/%.12s [%.4s%.2s].gba", (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); - FILE *f = fopen(gamename,"rb"); - if(f) + char savename[64]; + sprintf(savename,"/dumps/%.12s [%.4s%.2s].sav", + (char*)(testdump+0xA0),(char*)(testdump+0xAC),(char*)(testdump+0xB0)); + //let the user choose the option + printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2); + printf("Press B if you want to cancel dumping this game.\n"); + if(savesize > 0) { - fclose(f); - sendsafe(0); - printf("ERROR: Game already dumped! Please insert another game.\n"); - VIDEO_WaitVSync(); - VIDEO_WaitVSync(); - sleep(2); - continue; + printf("Press Y to backup this save file.\n"); + printf("Press X to restore this save file.\n\n"); } - printf("Press A to dump this game, it will take about %i minutes.\n",gbasize/1024/1024*3/2); - printf("Press B if you want to cancel dumping this game.\n\n"); - int dumping = 0; + else + printf("\n"); + int command = 0; while(1) { PAD_ScanPads(); @@ -341,56 +357,169 @@ int main(int argc, char *argv[]) endproc(); else if(btns&PAD_BUTTON_A) { - dumping = 1; + command = 1; break; } else if(btns&PAD_BUTTON_B) break; + else if(savesize > 0) + { + if(btns&PAD_BUTTON_Y) + { + command = 2; + break; + } + else if(btns&PAD_BUTTON_X) + { + command = 3; + break; + } + } } - sendsafe(dumping); - if(dumping == 0) - continue; - //create base file with size - printf("Creating file...\n"); - int fd = open(gamename, O_WRONLY|O_CREAT); - if(fd >= 0) + if(command == 1) { - ftruncate(fd, gbasize); - close(fd); + FILE *f = fopen(gamename,"rb"); + if(f) + { + fclose(f); + command = 0; + printf("ERROR: Game already dumped!\n"); + VIDEO_WaitVSync(); + sleep(2); + } } - f = fopen(gamename,"wb"); - if(!f) + else if(command == 2) { - printf("ERROR: Could not create file! Exit...\n"); - VIDEO_WaitVSync(); - VIDEO_WaitVSync(); - sleep(5); - exit(0); + FILE *f = fopen(savename,"rb"); + if(f) + { + fclose(f); + command = 0; + printf("ERROR: Save already backed up!\n"); + VIDEO_WaitVSync(); + sleep(2); + } } - printf("Dumping...\n"); - u32 bytes_read = 0; - while(gbasize > 0) + else if(command == 3) { - int toread = (gbasize > 0x400000 ? 0x400000 : gbasize); - int j; - for(j = 0; j < toread; j+=4) + size_t readsize = 0; + FILE *f = fopen(savename,"rb"); + if(f) { - *(vu32*)(testdump+j) = recvfast(); - bytes_read+=4; - if((bytes_read&0xFFFF) == 0) + fseek(f,0,SEEK_END); + readsize = ftell(f); + if(readsize != savesize) { - printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f); + command = 0; + printf("ERROR: Save has the wrong size, aborting restore!\n"); VIDEO_WaitVSync(); + sleep(2); + } + else + { + rewind(f); + fread(testdump,readsize,1,f); + } + fclose(f); + } + else + { + command = 0; + printf("ERROR: No Save to restore!\n"); + VIDEO_WaitVSync(); + sleep(2); + } + } + sendsafe(command); + usleep(5000); //wait for it to set next val + if(command == 0) + continue; + else if(command == 1) + { + //create base file with size + printf("Creating file...\n"); + int fd = open(gamename, O_WRONLY|O_CREAT); + if(fd >= 0) + { + ftruncate(fd, gbasize); + close(fd); + } + FILE *f = fopen(gamename,"wb"); + if(!f) + { + printf("ERROR: Could not create file! Exit...\n"); + VIDEO_WaitVSync(); + VIDEO_WaitVSync(); + sleep(5); + exit(0); + } + printf("Dumping...\n"); + u32 bytes_read = 0; + while(gbasize > 0) + { + int toread = (gbasize > 0x400000 ? 0x400000 : gbasize); + int j; + for(j = 0; j < toread; j+=4) + { + *(vu32*)(testdump+j) = recvfast(); + bytes_read+=4; + if((bytes_read&0xFFFF) == 0) + { + printf("\r%02.02f MB done",(float)(bytes_read/1024)/1024.f); + VIDEO_WaitVSync(); + } } - //printf("%02x%02x%02x%02x",resbuf[0],resbuf[1],resbuf[2],resbuf[3]); + fwrite(testdump,toread,1,f); + gbasize -= toread; + } + printf("\nClosing file\n"); + fclose(f); + printf("Game dumped!\n"); + sleep(5); + } + else if(command == 2) + { + FILE *f = fopen(savename,"wb"); + if(!f) + { + printf("ERROR: Could not create file! Exit...\n"); + VIDEO_WaitVSync(); + VIDEO_WaitVSync(); + sleep(5); + exit(0); } - fwrite(testdump,toread,1,f); - gbasize -= toread; + printf("Waiting for GBA\n"); + VIDEO_WaitVSync(); + u32 readval = 0; + while(readval != savesize) + readval = __builtin_bswap32(recvsafe()); + sendsafe(0); //got savesize + usleep(5000); //wait for it to set next val + printf("Receiving...\n"); + for(i = 0; i < savesize; i+=4) + *(vu32*)(testdump+i) = recvsafe(); + printf("Writing save...\n"); + fwrite(testdump,savesize,1,f); + fclose(f); + printf("Save backed up!\n"); + sleep(5); + } + else if(command == 3) + { + printf("Sending save\n"); + VIDEO_WaitVSync(); + u32 readval = 0; + while(readval != savesize) + readval = __builtin_bswap32(recvsafe()); + for(i = 0; i < savesize; i+=4) + sendsafe(__builtin_bswap32(*(vu32*)(testdump+i))); + printf("Waiting for GBA\n"); + while(recvsafe() != 0) + VIDEO_WaitVSync(); + printf("Save restored!\n"); + sendsafe(0); + sleep(5); } - printf("\nClosing file\n"); - fclose(f); - printf("Game dumped!\n"); - sleep(5); } } } -- cgit 1.4.1