From 810208f5fdd17b7de7a4dde730247ad028d6f65d Mon Sep 17 00:00:00 2001 From: msiewert76 Date: Fri, 6 May 2011 17:20:21 +0000 Subject: [PATCH] - split slot 1 detection from swap_cart (current version is slightly buggy) - introduce a new hardware detection routine - introduce a new "argv" test, hoping to weed out more bad implementations - convert more strings to upcoming translation interface - some bugfixes --- arm9/source/auxspi.cpp | 8 +- arm9/source/display.cpp | 63 +++----- arm9/source/dsi.cpp | 6 +- arm9/source/fileselect.cpp | 10 +- arm9/source/gba.cpp | 249 ++++++++++++++++++++----------- arm9/source/gba.h | 10 +- arm9/source/globals.cpp | 11 +- arm9/source/globals.h | 11 ++ arm9/source/hardware.cpp | 292 +++++++++++++++++++++++-------------- arm9/source/hardware.h | 12 +- arm9/source/main.cpp | 232 ++++++++++++++++------------- arm9/source/strings.cpp | 29 +++- arm9/source/strings.h | 20 +++ savegame_manager.pnps | 2 +- 14 files changed, 592 insertions(+), 363 deletions(-) diff --git a/arm9/source/auxspi.cpp b/arm9/source/auxspi.cpp index 658829b..c60a96c 100644 --- a/arm9/source/auxspi.cpp +++ b/arm9/source/auxspi.cpp @@ -248,10 +248,10 @@ bool auxspi_has_infrared() void auxspi_erase(bool ir) { - uint8 type = auxspi_save_type(); + uint8 type = auxspi_save_type(ir); if (type == 3) { uint8 size; - size = 1 << (auxspi_save_size_log_2() - 16); + size = 1 << (auxspi_save_size_log_2(ir) - 16); for (int i = 0; i < size; i++) { if (ir) auxspi_disable_infrared(); @@ -280,10 +280,10 @@ void auxspi_erase(bool ir) auxspi_close(); } } else { - int8 size = 1 << max(0, (auxspi_save_size_log_2() - 15)); + int8 size = 1 << max(0, (auxspi_save_size_log_2(ir) - 15)); memset(data, 0, 0x8000); for (int i = 0; i < size; i++) { - auxspi_write_data(i << 15, data, 0x8000, type); + auxspi_write_data(i << 15, data, 0x8000, type, ir); } } } diff --git a/arm9/source/display.cpp b/arm9/source/display.cpp index d040b70..de13916 100644 --- a/arm9/source/display.cpp +++ b/arm9/source/display.cpp @@ -37,16 +37,11 @@ #include "globals.h" #include "strings.h" -#include "auxspi_core.inc" - PrintConsole upperScreen; PrintConsole lowerScreen; -extern uint32 mode; -extern u8 gbatype; - //=========================================================== void displayInit() @@ -68,10 +63,15 @@ void displayInit() void displayPrintUpper() { - extern uint32 ezflash; + /* + //extern uint32 ezflash; extern bool gba; extern uint32 dstype; extern bool slot2; + */ + bool gba = (mode == 1); + u32 dstype = (mode == 3) ? 1 : 0; + bool ir = (slot_1_type == 1) ? true : false; // print upper screen (background) consoleSelect(&upperScreen); @@ -100,29 +100,9 @@ void displayPrintUpper() consoleClear(); // fetch cartridge header (maybe, calling "cardReadHeader" on a FC messes with libfat!) - //bool flash_card = is_flash_card(); - //bool ir = auxspi_has_infrared(); sNDSHeader nds; if (slot_1_type != 2) cardReadHeader((uint8*)&nds); - // search for the correct header - /* - for (int i = 0; i < 0x1000000; i++) - { - char *test = (char*)0x02000000; - if ((test[0]=='C')&&(test[1]=='P')&&(test[2]=='U')&&(test[3]=='D')) { - iprintf("found!"); - while(1); - } - test++; - } - */ - //nds = NDS_HEADER; - /* - if (nds.gameTitle[0] == 0xff) - // DSi - nds = NDS_HEADER; - */ char name[MAXPATHLEN]; // 0) print the mode @@ -158,7 +138,7 @@ void displayPrintUpper() sprintf(&name[0], "----"); if (slot_1_type == 2) { sprintf(&name[0], "Flash Card"); - } else /*if (nds.gameCode[0])*/ { + } else { memcpy(&name[0], &nds.gameCode[0], 4); name[4] = 0x00; } @@ -170,7 +150,7 @@ void displayPrintUpper() sprintf(&name[0], "----"); if (slot_1_type == 2) { sprintf(&name[0], "Flash Card"); - } else /*if (nds.gameTitle[0])*/ { + } else { memcpy(&name[0], &nds.gameTitle[0], 12); name[12] = 0x00; } @@ -183,17 +163,17 @@ void displayPrintUpper() if (slot_1_type == 2) { sprintf(&name[0], "Flash Card"); } else { - uint8 type = auxspi_save_type(); - uint32 size = auxspi_save_size(); + uint8 type = auxspi_save_type(ir); + uint8 size = auxspi_save_size_log_2(ir); switch (type) { case 1: sprintf(&name[0], "Eeprom (%i Bytes)", size); break; case 2: - sprintf(&name[0], "FRAM (%i kB)", size >> 10); + sprintf(&name[0], "FRAM (%i kB)", 1 << (size - 10)); break; case 3: - sprintf(&name[0], "Flash (%i kB)", size >> 10); + sprintf(&name[0], "Flash (%i kB)", 1 << (size - 10)); break; default: sprintf(&name[0], "unknown"); @@ -207,7 +187,6 @@ void displayPrintUpper() consoleSetWindow(&upperScreen, 10, 5, 22, 1); consoleClear(); memset(&name[0], 0, MAXPATHLEN); - //if (auxspi_has_infrared()) { if (slot_1_type == 1) { sprintf(&name[0], "Infrared"); } else { @@ -260,18 +239,18 @@ void displayPrintUpper() if (ezflash) sprintf(name, "SRAM"); else if (gba) { - u8 type = gbatype; + saveTypeGBA type = GetSlot2SaveType(CART_GBA_GAME); u8 size = gbaGetSaveSizeLog2(type); switch (type) { - case 1: - case 2: + case SAVE_GBA_EEPROM_05: + case SAVE_GBA_EEPROM_8: sprintf(name, "EEPROM (%i bytes)", 1 << size); break; - case 3: + case SAVE_GBA_SRAM_32: sprintf(name, "SRAM (%i kB)", 1 << (size - 10)); break; - case 4: - case 5: + case SAVE_GBA_FLASH_64: + case SAVE_GBA_FLASH_128: sprintf(name, "Flash (%i kB)", 1 << (size - 10)); break; default: @@ -292,7 +271,8 @@ void displayPrintUpper() if (ezflash) sprintf(name, "NOR + PSRAM"); else if (gba) - sprintf(name, "(unsupported)"); + // TODO: test for RTC, add function for syncing RTC? + sprintf(name, "???"); else if (slot2) sprintf(name, "----"); else if (dstype == 0) @@ -416,6 +396,9 @@ void displayProgressBar(int cur, int max0) } buffer[31] = ']'; buffer[32] = 0; + + if (max0 == 0) + buffer[0] = 0; iprintf("%s", buffer); } diff --git a/arm9/source/dsi.cpp b/arm9/source/dsi.cpp index e2123dd..e66e0a1 100644 --- a/arm9/source/dsi.cpp +++ b/arm9/source/dsi.cpp @@ -31,11 +31,7 @@ bool isDsi() { -#define SCFG_MODE (*(vu8*)0x4004000) - if(SCFG_MODE) - return (REG_DSIMODE != 0) ? true : false; - - return false; + return (REG_DSIMODE != 0) ? true : false; } bool dsiUnlockSlot1() diff --git a/arm9/source/fileselect.cpp b/arm9/source/fileselect.cpp index 060ab14..daadd4d 100644 --- a/arm9/source/fileselect.cpp +++ b/arm9/source/fileselect.cpp @@ -78,11 +78,11 @@ void ftpGetFileList(const char *dir, netbuf *ctrl, int &num) } } -void fileGetFileList(const char *dir, int num) +void fileGetFileList(const char *dir, int &num) { char *buf = (char*)data; int idx = 0; - memset(buf, 0, 0x8000); + memset(buf, 0, size_buf); DIR *pdir; struct dirent *pent; @@ -96,7 +96,7 @@ void fileGetFileList(const char *dir, int num) stat(fullname, &statbuf); // TODO: check for buffer overflow! - if (idx + strlen(pent->d_name) < 0x8000-2) { + if (idx + strlen(pent->d_name) < size_buf-2) { if (S_ISDIR(statbuf.st_mode)) { int len = sprintf(buf, "d%s\n", pent->d_name); buf += len; @@ -178,6 +178,10 @@ void fileSelect(const char *startdir, char *out_dir, char *out_fname, netbuf *bu ftpGetFileList("/", buf, num_files); else fileGetFileList(startdir, num_files); + if (num_files == 0) { + displayMessage("ERROR"); + while(1); + } filePrintFileList(startdir, first_file, sel_file, num_files, allow_cancel); while (!select) { diff --git a/arm9/source/gba.cpp b/arm9/source/gba.cpp index 4717eee..70692fe 100644 --- a/arm9/source/gba.cpp +++ b/arm9/source/gba.cpp @@ -44,6 +44,7 @@ #include "dsCard.h" #include "display.h" +#include "globals.h" inline u32 min(u32 i, u32 j) { return (i < j) ? i : j;} inline u32 max(u32 i, u32 j) { return (i > j) ? i : j;} @@ -158,7 +159,7 @@ uint8 gbaGetSaveType() for (int i = 0; i < (0x02000000 >> 2); i++, data++) { if (*data == MAGIC_EEPR) { // 2 versions: 512 bytes / 8 kB - return 1; // TODO: Try to figure out how to ID the 512 bytes version... hard way? write/restore! + return 2; // TODO: Try to figure out how to ID the 512 bytes version... hard way? write/restore! } if (*data == MAGIC_SRAM) { // *always* 32 kB @@ -205,21 +206,24 @@ uint32 gbaGetSaveSize(uint8 type) } // local function -//#define E_DEBUG void gbaEepromRead8Bytes(u8 *out, u32 addr, bool short_addr = false) { - // waitstates - //*(volatile unsigned short *)0x04000204 = 0x4317; -#ifdef E_DEBUG - char txt[64]; -#endif + // TODO: this still does not work... figure out somehow how to do it right! + + // waitstates - this is what Rudolph uses... + *(volatile unsigned short *)0x04000204 = 0x4317; + // maximal length of the buffer u16 buf[68]; - // "read" command + + // Prepare a "read" command. + u16 length; + // raw command buf[0] = 1; buf[1] = 1; - // write address + // address if (short_addr) { + length = 9; buf[2] = addr >> 5; buf[3] = addr >> 4; buf[4] = addr >> 3; @@ -227,49 +231,8 @@ void gbaEepromRead8Bytes(u8 *out, u32 addr, bool short_addr = false) buf[6] = addr >> 1; buf[7] = addr; buf[8] = 0; -#if 1 - // does not work - char txt[512]; - sprintf(txt, "EXMEMCNT = %x", REG_EXMEMCNT); - sysSetBusOwners(true, true); - displayMessage(txt); - //u32 ime = enterCriticalSection(); - // EXMEMCNT: 0..1: long sram wait state (18/8) - set to "2", i.e. not the slowest - // EXMEMCNT: 2..3: long ROM wait state (18/8) - REG_EXMEMCNT |= 15; - REG_EXMEMCNT &= ~(1 << 4); - // EXMEMCNT: ~4: 6 waitstates on 2nd access (should be 18 as well, but that's no option!) - dmaCopy((u16*)&buf[0], (u32*)0x09ffff00, 9<<1); - while (*(u16*)0x040000dc != 0); - dmaCopy((u32*)0x09ffff00, (u16*)&buf[0], 68<<1); - while (*(u16*)0x040000dc != 0); - //leaveCriticalSection(ime); -#endif -#if 0 - // TEST - //u32 ime = enterCriticalSection(); - REG_EXMEMCNT |= 3; - u32 ie = REG_IE; - REG_IE = 1 << 11; // DMA3 only - dmaCopy((u16*)&buf[0], (u32*)0x09ffff00, 9 << 1); - REG_EXMEMCNT |= 3; - dmaCopy((u32*)0x09ffff00, (u16*)&buf[0], 68 << 1); - REG_IE = ie; - //leaveCriticalSection(ime); -#endif -#if 0 -#define EEPROM *(u16*)0x0dffff00 - for (int i = 0; i < 9; i++) { - EEPROM = buf[i]; - swiDelay(10); - } - swiDelay(100); - for (int i = 0; i < 68; i++) { - buf[i] = EEPROM; - swiDelay(10); - } -#endif } else { + length = 17; buf[2] = addr >> 13; buf[3] = addr >> 12; buf[4] = addr >> 11; @@ -285,54 +248,159 @@ void gbaEepromRead8Bytes(u8 *out, u32 addr, bool short_addr = false) buf[14] = addr >> 1; buf[15] = addr; buf[16] = 0; - dmaCopy((u16*)&buf[0], (u32*)0x09000000, 17); - dmaCopy((u32*)0x09000000, (u16*)&buf[0], 68); } - // Extract data (there is only one *bit* per halfword!) - u16 *in_pos = &buf[4]; - u8 *out_pos = out; - u8 out_byte; - for(s8 byte = 7; byte >= 0; --byte ) - { - out_byte = 0; - for(s8 bit = 7; bit >= 0; --bit ) - { -#ifdef E_DEBUG + static u32 eeprom = 0x09ffff00; + + // send command to eeprom + displayPrintState("Sending command"); + // commenting this out or not does not have any impact on the EEPROM device. Therefore, + // the following command does not "make" it to the hardware! + DC_FlushRange(&buf[0], sizeof(buf)); + DMA_SRC(3) = (uint32)&buf[0]; + DMA_DEST(3) = (uint32)eeprom; + // there is a bit for eeprom access, but it only seems to freeze the transfer!? + //DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | length; // this bit is expanding to "3 bits" + //DMA_CR(3) = DMA_COPY_HALFWORDS | length; + DMA_CR(3) = DMA_COPY_HALFWORDS | (6 << 27) | length; + while(DMA_CR(3) & DMA_BUSY); + //while ((*(u16*)0x09ffff00 & 1) == 0); + + // get answer from eeprom + displayPrintState("listening"); + DC_FlushRange(&buf[0], sizeof(buf)); + DMA_SRC(3) = (uint32)eeprom; + DMA_DEST(3) = (uint32)&buf[0]; + // there is a bit for eeprom access, but it only seems to freeze the transfer!? + //DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | 68; // this bit is expanding to "3 bits" + //DMA_CR(3) = DMA_COPY_HALFWORDS | 68; + DMA_CR(3) = DMA_COPY_HALFWORDS | (6 << 27) | 68; + while(DMA_CR(3) & DMA_BUSY); + //while ((*(u16*)0x09ffff00 & 1) == 0); + /* - sprintf(txt, "byte: %i, Bit: %i, Val: %x", byte, bit, *in_pos); - displayPrintState(txt); - */ + // Extract data (there is only one *bit* per halfword!) + u16 *in_pos = &buf[4]; + u8 *out_pos = out; + u8 out_byte; + for(s8 byte = 7; byte >= 0; --byte ) + { + out_byte = 0; + for(s8 bit = 7; bit >= 0; --bit ) + { + out_byte += ((*in_pos++)&1)<> 5; + buf[3] = addr >> 4; + buf[4] = addr >> 3; + buf[5] = addr >> 2; + buf[6] = addr >> 1; + buf[7] = addr; + buf[8] = 0; + } else { + length = 17; + buf[2] = addr >> 13; + buf[3] = addr >> 12; + buf[4] = addr >> 11; + buf[5] = addr >> 10; + buf[6] = addr >> 9; + buf[7] = addr >> 8; + buf[8] = addr >> 7; + buf[9] = addr >> 6; + buf[10] = addr >> 5; + buf[11] = addr >> 4; + buf[12] = addr >> 3; + buf[13] = addr >> 2; + buf[14] = addr >> 1; + buf[15] = addr; + buf[16] = 0; + } + + // send command to eeprom + displayPrintState("Sending command"); + static u32 eeprom = 0x09ffff00; + DMA_SRC(3) = (uint32)&buf[0]; + DMA_DEST(3) = (uint32)eeprom; + // there is a bit for eeprom access, but it only seems to freeze the transfer!? + //DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | length; + DMA_CR(3) = DMA_COPY_HALFWORDS | length; + while(DMA_CR(3) & DMA_BUSY); + + // get answer from eeprom + displayPrintState("listening"); + DMA_SRC(3) = (uint32)eeprom; + DMA_DEST(3) = (uint32)&buf[0]; + // there is a bit for eeprom access, but it only seems to freeze the transfer!? + DMA_CR(3) = DMA_COPY_HALFWORDS | DMA_START_CARD | 68; + //DMA_CR(3) = DMA_COPY_HALFWORDS | 68; + while(DMA_CR(3) & DMA_BUSY); + + // Extract data (there is only one *bit* per halfword!) + // TODO: convert this to write format + u16 *in_pos = &buf[4]; + u8 *out_pos = out; + u8 out_byte; + for(s8 byte = 7; byte >= 0; --byte ) + { + out_byte = 0; + for(s8 bit = 7; bit >= 0; --bit ) + { + out_byte += ((*in_pos++)&1)<> 3; end = (src + len - 1) >> 3; u8 *tmp = (u8*)malloc((end-start+1) << 3); u8 *ptr = tmp; - displayPrintState("Reading from Eeprom..."); for (int j = start; j <= end; j++, ptr+=8) { - gbaEepromRead8Bytes(ptr, j, true); + gbaEepromRead8Bytes(ptr, j, eeprom_long); } memcpy(dst, tmp, len); free(tmp); - displayPrintState("Done!"); - break; - } - case 2: { break; } case 3: { @@ -345,10 +413,9 @@ bool gbaReadSave(u8 *dst, u8 src, u32 len, u8 type) break; } case 4: + // FLASH - must be opend by register magic, then blind copy nbanks = 1; case 5: - // FLASH - must be opend by register magic, then blind copy - nbanks = 2; for (int j = 0; j < nbanks; j++) { // we need to wait a few cycles before the hardware reacts! *(u8*)0x0a005555 = 0xaa; @@ -396,7 +463,7 @@ bool gbaIsAtmel() *(u8*)0x0a005555 = 0xf0; // leave ID mode swiDelay(10); // - char txt[128]; + //char txt[128]; sprintf(txt, "Man: %x, Dev: %x", man, dev); displayPrintState(txt); if ((man == 0x3d) && (dev == 0x1f)) @@ -408,12 +475,25 @@ bool gbaIsAtmel() bool gbaWriteSave(u8 *dst, u8 src, u32 len, u8 type) { int nbanks = 2; // for type 4,5 + bool eeprom_long = true; switch (type) { - case 1: - case 2: - // TODO: how does eeprom work? + case 1: { + eeprom_long = false; + } + case 2: { + int start, end; + start = src >> 3; + end = (src + len - 1) >> 3; + u8 *tmp = (u8*)malloc((end-start+1) << 3); + u8 *ptr = tmp; + for (int j = start; j <= end; j++, ptr+=8) { + gbaEepromWrite8Bytes(ptr, j, eeprom_long); + } + memcpy(dst, tmp, len); + free(tmp); break; + } case 3: { // SRAM: blind write u32 start = 0x0a000000 + src; @@ -521,4 +601,5 @@ bool gbaFormatSave(u8 type) swiDelay(10); break; } + return true; } diff --git a/arm9/source/gba.h b/arm9/source/gba.h index dd6160f..8b1d26a 100644 --- a/arm9/source/gba.h +++ b/arm9/source/gba.h @@ -37,11 +37,11 @@ enum cartTypeGBA { enum saveTypeGBA { SAVE_GBA_NONE = 0, - SAVE_GBA_EEPROM_05 = 0x00010001, // 512 bytes - SAVE_GBA_EEPROM_8 = 0x00010002, // 8k - SAVE_GBA_SRAM_32 = 0x00020001, // 32k - SAVE_GBA_FLASH_64 = 0x00040001, // 64k - SAVE_GBA_FLASH_128 = 0x00040002 // 128k + SAVE_GBA_EEPROM_05, // 512 bytes + SAVE_GBA_EEPROM_8, // 8k + SAVE_GBA_SRAM_32, // 32k + SAVE_GBA_FLASH_64, // 64k + SAVE_GBA_FLASH_128 // 128k }; struct dataSlot2 { diff --git a/arm9/source/globals.cpp b/arm9/source/globals.cpp index dc0be5e..4e2c166 100644 --- a/arm9/source/globals.cpp +++ b/arm9/source/globals.cpp @@ -35,4 +35,13 @@ char ftp_user[64] = "ftp_user"; char ftp_pass[64] = "ftp_pass"; int ftp_port = 0; -int ir_delay = 1000; +int ir_delay = 1200; + +char device[16] = "/"; + +char txt[256] = ""; + +u32 mode = 0; +u32 ezflash = 0; + +int slot2 = 0; diff --git a/arm9/source/globals.h b/arm9/source/globals.h index 741c8aa..02196cc 100644 --- a/arm9/source/globals.h +++ b/arm9/source/globals.h @@ -40,4 +40,15 @@ extern int ftp_port; extern int ir_delay; +// all libfat access will be using this device. default value = "/", i.e. "default" DLDI device +extern char device[16]; + +// text buffer for composing various messages +extern char txt[256]; + +extern u32 mode; +extern u32 ezflash; + +extern int slot2; + #endif // GLOBALS_H \ No newline at end of file diff --git a/arm9/source/hardware.cpp b/arm9/source/hardware.cpp index 8f00e7a..c24413d 100644 --- a/arm9/source/hardware.cpp +++ b/arm9/source/hardware.cpp @@ -25,6 +25,8 @@ */ #include +#include + #include #include #include @@ -47,6 +49,7 @@ #include "auxspi.h" #include "strings.h" +#include "dsi.h" using namespace std; @@ -54,6 +57,7 @@ static u32 pitch = 0x40000; // --------------------------------------------------------------------- +// FIXME: after the slot 1 detection was factored out, swap_cart no longer has perfect accuracy! bool swap_cart() { sNDSHeader nds; @@ -67,9 +71,12 @@ bool swap_cart() if (keysCurrent() & KEY_A) { // identify hardware slot_1_type = get_slot1_type(); + // don't try to dump a flash card + if (slot_1_type == 2) + continue; sysSetBusOwners(true, true); + // this will break DLDI on the Cyclops Evolution, but we need it anyway. cardReadHeader((u8*)&nds); - //flash_card = false; displayPrintUpper(); if (!nds.gameTitle[0]) continue; @@ -84,16 +91,21 @@ bool swap_cart() u32 get_slot1_type() { - u8 size1 = auxspi_save_size_log_2(false); + sysSetBusOwners(true, true); + + // Trying to read the save size in IR mode will fail on non-IR devices. + // If we have success, it is an IR device. u8 size2 = auxspi_save_size_log_2(true); + if (size2 > 0) + return 1; - if (size1 == size2) - return 2; // flash card + // It is not an IR game, so maybe it is a regular game. + u8 size1 = auxspi_save_size_log_2(false); + if (size1 > 0) + return 0; - if ((size1 == 0) && (size2 != 0)) - return 1; // ir device - - return 0; // regular game + // No save size test returned a save chip, so it must be a flash card. + return 2; } bool swap_card_game(uint32 size) @@ -101,12 +113,74 @@ bool swap_card_game(uint32 size) return false; } +// This function is called on boot; it detects the hardware configuration and selects the mode. +u32 hwDetect() +{ + // Identify Slot 1 devide. This is used by pretty much everything. + slot_1_type = get_slot1_type(); + + // First, look for a DSi running in DSi mode. + if (isDsi()) { + size_buf = 1 << 23; // 8 MB memory buffer + return 3; + } + size_buf = 1 << 21; // 2 MB memory buffer + + // Identify Slot 2 device. + // First, look for an EZFlash 3in1 + uint32 ime = enterCriticalSection(); + sysSetBusOwners(true, true); + OpenNorWrite(); + ezflash = ReadNorFlashID(); + CloseNorWrite(); + leaveCriticalSection(ime); + chip_reset(); + if (ezflash) + return 2; + + // Okay, maybe it is a regular GBA game instead + if (gbaIsGame()) + return 1; + + // Maybe it is a Slot 2 flash card. + + // Detecting slot 2 flash cards is very evil: + // - They don't usually support argv, so we can't simply test that we are + // running from "fat2". + // - We need a passme compatible slot 1 device, i.e. we can't verify that + // there is a flash card in slot 1 (which usually is). + // - There is only a limited number of Slot 2 flash cards on the market, so + // we could test for this (I think there is a library for this). But if we + // boot from Slot 1, a positive Slot 2 test does not mean that we did boot + // from there - the card may be sitting there unused! + // + // --> So we select slot 2 mode the "dumb" way - with an ini parameter. Unless you swap + // the same microSD card between Slot 1 and Slot 2, this should be the safest mode. + // (If you know a smarter way of doing this, feel free to commit a patch!) + // + if (slot2) + return 4; + + // Try to identify download play mode. This also introduces various complications: + // - The latest libnds versions include code for the SD-slot on the DSi. It does not work + // from flash cards or download play, but it may still result in a positive DLDI driver + // initialisation. So we can't simply run "fatInitDefault" and test return values. + // - Currently, download play mode aims to "insert game first, then run dlp", i.e. + // it does not support hotswapping the game. So we select this mode if there is *no* + // flash card inserted in Slot 1. + // + if (slot_1_type != 2) + return 5; + + // Nothing unique found, so enter WiFi mode + return 0; +} + // -------------------------------------------------------- void hwFormatNor(uint32 page, uint32 count) { uint32 ime = hwGrab3in1(); SetSerialMode(); - //displayPrintState("Formating NOR memory"); displayProgressBar(0, count); for (uint32 i = page; i < page+count; i++) { Block_Erase(i << 18); @@ -139,9 +213,10 @@ void hwBackup3in1() swap_cart(); displayPrintUpper(); - uint8 size = auxspi_save_size_log_2(); + bool ir = (slot_1_type == 1) ? true : false; + uint8 size = auxspi_save_size_log_2(ir); int size_blocks = 1 << max(0, (int8(size) - 18)); // ... in units of 0x40000 bytes - that's 256 kB - uint8 type = auxspi_save_type(); + uint8 type = auxspi_save_type(ir); displayMessage2A(STR_HW_3IN1_FORMAT_NOR, false); hwFormatNor(0, size_blocks+1); @@ -152,26 +227,27 @@ void hwBackup3in1() else size_blocks = 1 << (uint8(size) - 15); u8 *test = (u8*)malloc(0x8000); + if (test == NULL) + while(1); u32 LEN = min(1 << size, 0x8000); for (int i = 0; i < size_blocks; i++) { displayProgressBar(i+1, size_blocks); - auxspi_read_data(i << 15, data, LEN, type); + auxspi_read_data(i << 15, data, LEN, type, ir); uint32 ime = hwGrab3in1(); SetSerialMode(); WriteNorFlash((i << 15) + pitch, data, LEN); hwRelease3in1(ime); - for (int j = 0; j < 4; j++) { - uint32 ime = hwGrab3in1(); - ReadNorFlash(test, (i << 15) + pitch, LEN); - hwRelease3in1(ime); - } + // test if NOR memory is sane, i.e. if we can read what we just wrote + ime = hwGrab3in1(); + ReadNorFlash(test, (i << 15) + pitch, LEN); + hwRelease3in1(ime); if (*((vuint16 *)(FlashBase+0x2002)) == 0x227E) { - displayMessage("ERROR: ID mode active!"); + displayMessage2A(STR_HW_3IN1_ERR_IDMODE, false); while(1); } if (memcmp(test, data, LEN)) { - displayMessage("ERROR: verifying NOR failed"); + displayMessage2A(STR_HW_3IN1_ERR_NOR, false); while(1); } } @@ -201,13 +277,6 @@ void hwBackup3in1() displayMessage2A(STR_HW_3IN1_PLEASE_REBOOT, false); - ime = hwGrab3in1(); - ReadNorFlash((u8*)&data2, 0x1000, sizeof(data2)); // this should work - but it does not! - hwRelease3in1(ime); - char txt[128]; - sprintf(txt, "%.12s", &data2.name[0]); - displayMessage(txt); - while(1) {}; } @@ -220,10 +289,12 @@ void hwDump3in1(uint32 size, const char *gamename) char path[256]; char fname[256] = ""; fileSelect("/", path, fname, 0, true, false); + + // look for an unused filename if (!fname[0]) { uint32 cnt = 0; sprintf(fname, "/%s.%i.sav", gamename, cnt); - char txt[256]; + //char txt[256]; sprintf(txt, stringsGetMessageString(STR_HW_SEEK_UNUSED_FNAME), fname); displayMessage2(txt, false); while (fileExists(fname)) { @@ -238,7 +309,6 @@ void hwDump3in1(uint32 size, const char *gamename) } char fullpath[256]; sprintf(fullpath, "%s/%s", path, fname); - char txt[512]; sprintf(txt, stringsGetMessageString(STR_HW_3IN1_DUMP), fullpath); displayMessage2(txt, false); @@ -259,7 +329,7 @@ void hwDump3in1(uint32 size, const char *gamename) sprintf(txt, stringsGetMessageString(STR_HW_3IN1_DONE_DUMP), fullpath); displayMessage2(txt, false); - while (1); + while (!(keysCurrent() & KEY_B)) {}; } void hwRestore3in1() @@ -270,6 +340,7 @@ void hwRestore3in1() displayMessageA(STR_HW_SELECT_FILE); // lower screen is used for file browser fileSelect("/", path, fname, 0, false, false); char msg[256]; + // This does not have to be translated. sprintf(msg, "%s/%s", path, fname); displayMessage(msg); @@ -303,13 +374,11 @@ void hwRestore3in1() ReadNorFlash(test, (i << 15) + pitch, LEN); hwRelease3in1(ime); if (*((vuint16 *)(FlashBase+0x2002)) == 0x227E) { - displayMessage("ERROR: ID mode active!"); + displayMessage2A(STR_HW_3IN1_ERR_IDMODE, false); while(1); } - if (int err = memcmp(test, data, LEN)) { - char txt[128]; - sprintf(txt, "ERROR: NOR %x/%x: %x -> %x", abs(err), LEN, data[err], test[err]); - displayMessage(txt); + if (memcmp(test, data, LEN)) { + displayMessage2A(STR_HW_3IN1_ERR_NOR, false); while(1); } } @@ -317,25 +386,30 @@ void hwRestore3in1() fclose(file); free(test); - hwRestore3in1_b(size); + hwRestore3in1_b(1 << size); } void hwRestore3in1_b(uint32 size_file) { + bool ir = (slot_1_type == 1) ? true : false; + // Third, swap in a new game - uint32 size = auxspi_save_size_log_2(); + uint32 size = auxspi_save_size_log_2(ir); while ((size_file < size) || (slot_1_type == 2)) { - // TODO: make THIS error message more meaningful! - displayPrintState("File too small or no save chip!"); + if (slot_1_type == 2) + displayMessage2A(STR_HW_SWAP_CARD, false); + else if (size_file < size) + displayMessage2A(STR_HW_WRONG_GAME, false); swap_cart(); - size = auxspi_save_size_log_2(); + ir = (slot_1_type == 1) ? true : false; + size = auxspi_save_size_log_2(ir); } displayPrintUpper(); - uint8 type = auxspi_save_type(); + uint8 type = auxspi_save_type(ir); if (type == 3) { displayMessage2A(STR_HW_FORMAT_GAME, false); - auxspi_erase(); + auxspi_erase(ir); } // And finally, write the save! @@ -363,7 +437,7 @@ void hwRestore3in1_b(uint32 size_file) uint32 ime = hwGrab3in1(); ReadNorFlash(data, (i << shift) + pitch, LEN); hwRelease3in1(ime); - auxspi_write_data(i << shift, data, LEN, type); + auxspi_write_data(i << shift, data, LEN, type, ir); } displayProgressBar(1, 1); @@ -375,11 +449,10 @@ void hwRestore3in1_b(uint32 size_file) // ------------------------------------------------------------ void hwErase() { + bool ir = (slot_1_type == 1) ? true : false; displayMessage2A(STR_HW_WARN_DELETE, true); while (!(keysCurrent() & (KEY_UP | KEY_R | KEY_Y))) {}; - auxspi_erase(); - displayMessage2A(STR_HW_DID_DELETE, true); - while(1); + auxspi_erase(ir); } // ------------------------------------------------------------ @@ -388,44 +461,45 @@ void hwBackupFTP(bool dlp) netbuf *buf, *ndata; int j; static int jmax = 10; + bool ir = (slot_1_type == 1) ? true : false; // Dump save and write it to FTP server // First: swap card if (!dlp) swap_cart(); displayPrintUpper(); - uint8 size = auxspi_save_size_log_2(); + uint8 size = auxspi_save_size_log_2(ir); int size_blocks = 1 << max(0, (int8(size) - 18)); // ... in units of 0x40000 bytes - that's 256 kB - uint8 type = auxspi_save_type(); + uint8 type = auxspi_save_type(ir); if (size < 15) size_blocks = 1; else size_blocks = 1 << (uint8(size) - 15); // Second: connect to FTP server - displayPrintState("FTP: connecting to AP"); + displayMessage2A(STR_HW_FTP_SEEK_AP, false); if (!Wifi_InitDefault(true)) { - displayPrintState("FTP: ERROR: AP not found"); + displayMessage2A(STR_HW_FTP_ERR_AP, true); while(1); } - displayPrintState("FTP: connecting to FTP server"); + displayMessage2A(STR_HW_FTP_SEEK_FTP, false); char fullname[512]; sprintf(fullname, "%s:%i", ftp_ip, ftp_port); j = 0; while (!FtpConnect(fullname, &buf)) { j++; if (j >= jmax) { - displayPrintState("FTP: ERROR: FTP server missing"); + displayMessage2A(STR_HW_FTP_ERR_FTP, true); while(1); } swiDelay(10000); } - displayPrintState("FTP: login"); + displayMessage2A(STR_HW_FTP_LOGIN, false); j = 0; while (!FtpLogin(ftp_user, ftp_pass, buf)) { j++; if (j >= jmax) { - displayPrintState("FTP: ERROR: login failed"); + displayMessage2A(STR_HW_FTP_ERR_LOGIN, true); while(1); } swiDelay(10000); @@ -435,7 +509,7 @@ void hwBackupFTP(bool dlp) char fname[256] =""; memset(fname, 0, 256); displayMessageA(STR_HW_SELECT_FILE_OW); - displayPrintState("FTP: dir"); + displayPrintState("FTP: dir"); // TODO: translate me! fileSelect("/", fdir, fname, buf, true, false); bool newfile; if (!fname[0]) @@ -452,7 +526,6 @@ void hwBackupFTP(bool dlp) int tsize = 0; sprintf(fname, "%.12s.%i.sav", nds.gameTitle, cnt); while (FtpSize(fname, &tsize, FTPLIB_IMAGE, buf) != 0) { - char txt[256]; sprintf(txt, stringsGetMessageString(STR_HW_SEEK_UNUSED_FNAME), fname); displayMessage2(txt, false); if (cnt < 65536) @@ -462,13 +535,13 @@ void hwBackupFTP(bool dlp) while(1); } sprintf(fname, "%.12s.%i.sav", nds.gameTitle, cnt); - displayPrintState(fname); } } // Fourth: dump save displayPrintState(""); - sprintf(fullname, "Writing file:\n%s%s", fdir, fname); + // This may not have to be translated. + sprintf(fullname, "%s%s", fdir, fname); displayMessage(fullname); FtpAccess(fname, FTPLIB_FILE_WRITE, FTPLIB_IMAGE, buf, &ndata); u32 length = 0x200; @@ -476,19 +549,18 @@ void hwBackupFTP(bool dlp) length = 1 << size; for (int i = 0; i < (1 << (size - 9)); i++) { displayProgressBar(i+1, (size_blocks << 6)); - auxspi_read_data(i << 9, (u8*)&data[0], length, type); - int out = 0; - while (out < 512) { - out += FtpWrite((u8*)&data[out], 512-out, ndata); - if (out < 512) { + auxspi_read_data(i << 9, (u8*)&data[0], length, type, ir); + u32 out = 0; + while (out < length) { + u32 delta = FtpWrite((u8*)&data[out], length-out, ndata); + out += delta; + if (delta == 0) { + displayMessage2A(STR_HW_FTP_READ_ONLY, false); + } else { + displayMessage2("", false); + } + if (delta < length) { displayPrintState(stringsGetMessageString(STR_HW_FTP_SLOW)); - /* - debug++; - if (debug >= 2048) { - debug = 0; - displayMessage2("Unable to reach FTP server. Make sure that you have WRITE ACCESS!" - } - */ } else { displayPrintState(""); } @@ -500,7 +572,7 @@ void hwBackupFTP(bool dlp) Wifi_DisconnectAP(); if (dlp) { - displayMessage("Done! Please turn off your DS."); + displayMessage2A(STR_HW_PLEASE_REBOOT, false); while(1); } } @@ -510,32 +582,33 @@ void hwRestoreFTP(bool dlp) netbuf *buf, *ndata; int j; static int jmax = 10; + bool ir = (slot_1_type == 1) ? true : false; // Dump save and write it to FTP server // First: connect to FTP server - displayPrintState("FTP: connecting to AP"); + displayMessage2A(STR_HW_FTP_SEEK_AP, false); if (!Wifi_InitDefault(true)) { - displayPrintState("FTP: ERROR: AP not found"); + displayMessage2A(STR_HW_FTP_ERR_AP, true); while(1); } - displayPrintState("FTP: connecting to FTP server"); + displayMessage2A(STR_HW_FTP_SEEK_FTP, false); char fullname[512]; sprintf(fullname, "%s:%i", ftp_ip, ftp_port); j = 0; while (!FtpConnect(fullname, &buf)) { j++; if (j >= jmax) { - displayPrintState("FTP: ERROR: FTP server missing"); + displayMessage2A(STR_HW_FTP_ERR_FTP, true); while(1); } swiDelay(10000); } - displayPrintState("FTP: login"); + displayMessage2A(STR_HW_FTP_LOGIN, false); j = 0; while (!FtpLogin(ftp_user, ftp_pass, buf)) { j++; if (j >= jmax) { - displayPrintState("FTP: ERROR: login failed"); + displayMessage2A(STR_HW_FTP_ERR_LOGIN, false); while(1); } swiDelay(10000); @@ -545,21 +618,21 @@ void hwRestoreFTP(bool dlp) char fdir[256] = ""; char fname[256] =""; memset(fname, 0, 256); - displayMessage("Please select a file name to\nrestore."); + displayMessageA(STR_HW_SELECT_FILE); displayPrintState("FTP: dir"); - fileSelect("/", fdir, fname, buf, true, false); + fileSelect("/", fdir, fname, buf, false, false); // Third: swap card if (!dlp) swap_cart(); displayPrintUpper(); - uint8 size = auxspi_save_size_log_2(); - uint8 type = auxspi_save_type(); + uint8 size = auxspi_save_size_log_2(ir); + uint8 type = auxspi_save_type(ir); // Fourth: read file displayPrintState(""); FtpChdir(fdir, buf); - sprintf(fullname, "Reading file:\n%s%s", fdir, fname); + sprintf(fullname, "%s%s", fdir, fname); displayMessage(fullname); u32 LEN = 0, num_blocks = 0, shift = 0; switch (type) { @@ -591,8 +664,9 @@ void hwRestoreFTP(bool dlp) #endif } if ((type == 3) && (insecure)) { - displayPrintState("Formating Flash chip"); - auxspi_erase(); + displayMessage2A(STR_HW_FORMAT_GAME, false); + //displayPrintState("Formating Flash chip"); + auxspi_erase(ir); } FtpAccess(fname, FTPLIB_FILE_READ, FTPLIB_IMAGE, buf, &ndata); u8 *pdata = data; @@ -606,36 +680,26 @@ void hwRestoreFTP(bool dlp) else displayPrintState(""); } - /* - int out; - if ((out = FtpRead((u8*)pdata, 512, ndata)) < 512) { - char dings[512]; - sprintf(dings, "Error: requested 512, got %i", out); - displayPrintState(dings); - while(1); - } - */ - // does not fit into memory: insecure mode + // does not fit into memory: unsafe mode + // TODO: reactivate this! if (insecure) { - //char bums[512]; - //sprintf(bums, "addr = %x", (i << 9)+(j << shift)); displayPrintState("Writing save (insecure!)"); for (int j = 0; j < 1 << (9-shift); j++) { - auxspi_write_data((i << 9)+(j << shift), ((u8*)pdata)+(j< 8*16) && (touchXY.py < 8*24)) { displayPrintUpper(); hwErase(); - displayMessage("Done! Please turn off your DS."); + displayMessage2A(STR_HW_DID_DELETE, true); while(1); } } } -int main(int argc, char* argv[]) +bool loadIniFile(char* path) { - sysSetBusOwners(true, true); - - // Init the screens - displayInit(); - - // Init DLDI (file system driver) - // TODO: find some way to skip this when loading from a different exploit/download play/not a flash card - int fat = fatInitDefault(); - if (fat == 0) { - displayPrintState("DLDI error\n"); - while (1) {}; - } - - // test if our flash card supports argv at all. some R4 clones seem to be very picky! - // (untested due to lack of an R4 myself, but I hope it works) - bool has_argv = false; - if (argc) - has_argv = true; + // Don't try to load ini file in DLP mode, we need to get our options from a different source. + // Still trying to figure something out... + if (mode == 5) + return true; + + ini_fd_t ini = 0; // load ini file... - ini_fd_t ini = 0; char inipath[256]; - if (has_argv) { - if (argv[0]) { - char *last = strrchr(argv[0], '/'); - int len = (last - argv[0])+1; - strncpy(bootdir, argv[0], len); - sprintf(inipath, "%s/savegame_manager.ini", bootdir); - if (fileExists(inipath)) - ini = ini_open(inipath, "r", ""); - } + if (path) { + char *last = strrchr(path, '/'); + int len = (last - path)+1; + strncpy(bootdir, path, len); + sprintf(inipath, "%s/savegame_manager.ini", bootdir); + if (fileExists(inipath)) + ini = ini_open(inipath, "r", ""); } if (!ini) { sprintf(inipath, "/savegame_manager.ini"); @@ -321,8 +304,8 @@ int main(int argc, char* argv[]) ini = ini_open(inipath, "r", ""); } if (!ini) { - displayMessage("Unable to open ini file!\nPlease make sure that it is\n1. in this apps folder, or" - "\n2. in the root folder\nIf 1. does not work, use 2."); + // FIXME + displayMessage2A(STR_BOOT_NO_INI,true); while (1); } @@ -335,77 +318,116 @@ int main(int argc, char* argv[]) ini_readString(ini, ftp_pass, 64); ini_locateKey(ini, "ftp_port"); ini_readInt(ini, &ftp_port); - ini_locateKey(ini, "ir_delay"); + + ini_locateKey(ini, "ir_delay"); ini_readInt(ini, &ir_delay); ir_delay = max(ir_delay, 1000); + + ini_locateKey(ini, "slot2"); + ini_readInt(ini, &slot2); + ini_close(ini); // delete temp file (which is a remnant of inilib) remove("/tmpfile"); + return true; +} + +// This is a new attempt to reliably identify if the flash card has argv support or not, +// including R4 clones which may have *bad* argv support. +bool has_argv(int argc, char* argv[]) +{ + // no argv support + if (argc == 0) + return false; + + // bad argv support: if argc is larger than unity, your flash card can't even do + // a proper negative indicator. let us test for 2 argv arguments, just to be safe. + if (argc > 2) + return false; + + /* + // test if argv[0] pointer is valid (scan main memory and WRAM) + if ((argv[0] < 0x02000000) || (argv[0] >= 0x04000000)) + return false; + */ + + // test if argv[0] contains a valid string + char *arg0 = argv[0]; + // test for possible "/path", "fat*:/path" and "sd:/*". + if (*arg0 == 'f') + if (strncasecmp(argv[0], "fat:/", 5) || strncasecmp(argv[0], "fat1:/", 6) + || strncasecmp(argv[0], "fat2:/", 6)) + return true; + + if (*arg0 == 's') + if (strncasecmp(argv[0], "sd:/", 4)) + return true; + + if (*arg0 == '/') + return true; + + return false; +} + +int main(int argc, char* argv[]) +{ + sysSetBusOwners(true, true); + + // Init the screens + displayInit(); + + // detect hardware + mode = hwDetect(); + + // Init DLDI (file system driver), skip for mode == 4,5 which already calls this during + // hardware initialisation + if (mode < 4) { + int fat = fatInitDefault(); + if (fat == 0) { + displayMessage2A(STR_BOOT_DLDI_ERROR,true); + while (1); + } + } + + // Load the ini file with the FTP settings and more options + if (has_argv(argc, argv)) + loadIniFile(argv[0]); + else + loadIniFile(0); + + // prepare the global data buffer + data = (u8*)malloc(size_buf); + // This should not be required, but better safe than sorry. On the DS, it *might* be + // possible that no continuous 2 MB are available. + if (data == NULL) { + size_buf >>= 1; + data = (u8*)malloc(size_buf); + } + // load strings stringsLoadFile(0); - - // Identify hardware and branch to corresponding mode - //displayMessage("Identifying hardware..."); - - // 1) Identify DSi (i.e. memory capacity) - //displayPrintState("ID: DS model"); - if (isDsi()) { - dstype = 1; - size_buf = 1 << 23; // 8 MB - } else { - dstype = 0; - size_buf = 1 << 21; // 2 MB - //size_buf = 1 << 14; // 32 kB - TESTING ONLY! - } - data = (u8*)malloc(size_buf); - - // is there a game card in slot-1? if so, we have been starten with download-play or a new exploit - slot_1_type = get_slot1_type(); - - // don't try to identify Slot-2 in DSi mode. - if (dstype == 0) { - //displayPrintState("ID: Slot 2"); - uint32 ime = enterCriticalSection(); - sysSetBusOwners(true, true); - OpenNorWrite(); - ezflash = ReadNorFlashID(); - CloseNorWrite(); - leaveCriticalSection(ime); - chip_reset(); - - gba = gbaIsGame(); - } - - // Try to identify slot-2 device. Try opening slot-2 root directory - if (argv[0][3] == '2') - slot2 = true; // okay, we got our HW identified; now branch to the corresponding main function/event handler - if (slot_1_type != 2) { - // running from download play, NOR, or a different exploit. enter dlp mode. - mode = 5; - mode_dlp(); - } else if (dstype == 1) { - // DSi/DSiXL, branch to SD-card mode when cracked. - mode = 3; - mode_dsi(); - } else if (slot2) { - mode = 4; - mode_slot2(); - } else if (ezflash != 0) { - // DS with EZFlash found -> branch to 3in1 mode - mode = 2; - mode_3in1(); - } else if (gba) { - // GBA game in slot 2 -> branch to GBA mode - mode = 1; - mode_gba(); - } else { - // failsafe: enter WiFi mode - mode = 0; - mode_wifi(); + switch (mode) { + case 1: + mode_gba(); + break; + case 2: + mode_3in1(); + break; + case 3: + mode_dsi(); + break; + case 4: + mode_slot2(); + break; + case 5: + mode_dlp(); + break; + default: + mode_wifi(); } return 0; diff --git a/arm9/source/strings.cpp b/arm9/source/strings.cpp index e99e856..3fd5190 100644 --- a/arm9/source/strings.cpp +++ b/arm9/source/strings.cpp @@ -31,12 +31,13 @@ #include "libini.h" #include #include "fileselect.h" +#include "globals.h" using namespace std; // a global string array char **message_strings; -char txt[512]; +//char txt[512]; #define ADD_STRING(id,text) strcpy(txt,text);\ message_strings[id] = new char[strlen(txt)+1];\ @@ -59,7 +60,7 @@ bool stringsLoadFile(const char *fname) message_strings = new char*[STR_LAST]; #ifndef NOT_FINISHED ini_locateHeading(ini, ""); - char txt[512]; + //char txt[512]; for (int i = 0; i < STR_LAST; i++) { sprintf(txt, "%i", i); ini_locateKey(ini, txt); @@ -71,7 +72,14 @@ bool stringsLoadFile(const char *fname) // delete temp file (which is a remnant of inilib) remove("/tmpfile"); #else + ADD_STRING(STR_BOOT_NO_INI,"Unable to open ini file!\nPlease make sure that it is\n1. in this apps folder, or" + "\n2. in the root folder\nIf 1. does not work, use 2."); + ADD_STRING(STR_BOOT_MODE_UNSUPPORTED,"This mode is DISABLED.\nPlease restart the system."); + ADD_STRING(STR_BOOT_DLDI_ERROR,"DLDI initialisation error!"); + // ADD_STRING(STR_HW_SWAP_CARD,"Please take out Slot 1\nflash card and insert a game\n\nPress A when done."); + ADD_STRING(STR_HW_WRONG_GAME,"This game has a save chip\nthat is smaller than the\nsave you are going to\nwrite. Please insert a\ndifferent game.\n\nPress A when done."); + ADD_STRING(STR_HW_PLEASE_REBOOT,"Done! Please power off\n(and restart if you want\nto do more)."); // ADD_STRING(STR_HW_SELECT_FILE,"Please select a .sav file."); ADD_STRING(STR_HW_SELECT_FILE_OW,"Please select a file to\noverwrite, or press L+R in afolder to create a new file."); @@ -87,10 +95,25 @@ bool stringsLoadFile(const char *fname) ADD_STRING(STR_HW_3IN1_PLEASE_REBOOT,"Save has been written to\nthe 3in1. Please power off\nand restart this tool."); ADD_STRING(STR_HW_3IN1_CLEAR_FLAG,"Preparing to dump your\nsave... Please wait..."); ADD_STRING(STR_HW_3IN1_DUMP,"Dumping the save from the\n3in1 to your flash card.\nFilename:\n%s"); - ADD_STRING(STR_HW_3IN1_DONE_DUMP,"Done. Your game save has\nbeen dumped using your\n3in1. Filename:\n%s\n\nPlease restart your DS."); + ADD_STRING(STR_HW_3IN1_DONE_DUMP,"Done. Your game save has\nbeen dumped using your\n3in1. Filename:\n%s\n\nPress (B) to continue."); ADD_STRING(STR_HW_3IN1_RESTORE,"Done. Your game save has\nbeen restored using your\n3in1.\n\nPlease restart your DS."); + ADD_STRING(STR_HW_3IN1_ERR_IDMODE,"ERROR!\nID mode still active!"); + ADD_STRING(STR_HW_3IN1_ERR_NOR,"ERROR!\nNOR memory seems to be\ndamaged!"); // + ADD_STRING(STR_HW_FTP_SEEK_AP,"Connecting to an access\npoint...\n\nplease wait..."); + ADD_STRING(STR_HW_FTP_ERR_AP,"ERROR!\nCould not find a compatible\nAccess Point. Please config\nyour WiFi Connection from\na WiFi-enabled game!"); + ADD_STRING(STR_HW_FTP_SEEK_FTP,"Connecting to an FTP\nserver...\n\nplease wait..."); + ADD_STRING(STR_HW_FTP_ERR_FTP,"ERROR!\nCould not find an FTP\nserver. Please refer to\nthe documentation."); + ADD_STRING(STR_HW_FTP_LOGIN,"Logging in..."); + ADD_STRING(STR_HW_FTP_ERR_LOGIN,"ERROR!\nCould not log in to the\nFTP server. Please verify\nyour username and password\nare correct in your\nini file."); + ADD_STRING(STR_HW_FTP_DIR,"Reading FTP directory..."); ADD_STRING(STR_HW_FTP_SLOW,"FTP is slow, please wait..."); + ADD_STRING(STR_HW_FTP_READ_ONLY,"WARNING: could not write to\nyour FTP server! Maybe you\nforgot to enable write\naccess?"); + // + ADD_STRING(STR_HW_GBA_READ,"Reading save from your game.Please wait..."); + ADD_STRING(STR_HW_GBA_DUMP,"Writing save to flash card.\nPlease wait..."); + ADD_STRING(STR_HW_GBA_LOAD,"Reading save from your\nflash card. Filename:\n%s\n\nPlease wait..."); + ADD_STRING(STR_HW_GBA_RESTORE,"Restoring save to your game\n\nPlease wait..."); // ADD_STRING(STR_HW_WARN_DELETE,"This will WIPE OUT your\nentire save! ARE YOU SURE?\n\nPress R+up+Y to confim!"); ADD_STRING(STR_HW_DID_DELETE,"Done. Your game save has\nbeen PERMANENTLY deleted.\n\nPlease restart your DS."); diff --git a/arm9/source/strings.h b/arm9/source/strings.h index 56b9598..76aef93 100644 --- a/arm9/source/strings.h +++ b/arm9/source/strings.h @@ -32,8 +32,13 @@ enum { STR_TITLE_MSG, + STR_BOOT_NO_INI, + STR_BOOT_MODE_UNSUPPORTED, + STR_BOOT_DLDI_ERROR, // STR_HW_SWAP_CARD, + STR_HW_WRONG_GAME, + STR_HW_PLEASE_REBOOT, // STR_HW_SELECT_FILE, STR_HW_SELECT_FILE_OW, @@ -51,8 +56,23 @@ enum { STR_HW_3IN1_DUMP, STR_HW_3IN1_DONE_DUMP, STR_HW_3IN1_RESTORE, + STR_HW_3IN1_ERR_IDMODE, + STR_HW_3IN1_ERR_NOR, // + STR_HW_FTP_SEEK_AP, + STR_HW_FTP_ERR_AP, + STR_HW_FTP_SEEK_FTP, + STR_HW_FTP_ERR_FTP, + STR_HW_FTP_LOGIN, + STR_HW_FTP_ERR_LOGIN, + STR_HW_FTP_DIR, STR_HW_FTP_SLOW, + STR_HW_FTP_READ_ONLY, + // + STR_HW_GBA_READ, + STR_HW_GBA_DUMP, + STR_HW_GBA_LOAD, + STR_HW_GBA_RESTORE, // STR_HW_WARN_DELETE, STR_HW_DID_DELETE, diff --git a/savegame_manager.pnps b/savegame_manager.pnps index daaa261..6edac41 100644 --- a/savegame_manager.pnps +++ b/savegame_manager.pnps @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file