mirror of
https://github.com/rvtr/GodMode9i.git
synced 2025-11-02 00:11:07 -04:00
Add restoring DS saves on DS/DS Lite (#141)
This commit is contained in:
parent
4aa294b444
commit
ccf8d0200b
@ -469,7 +469,7 @@ bool driveRemoved(Drive drive) {
|
|||||||
case Drive::sdCard:
|
case Drive::sdCard:
|
||||||
return sdRemoved;
|
return sdRemoved;
|
||||||
case Drive::flashcard:
|
case Drive::flashcard:
|
||||||
return REG_SCFG_MC & BIT(0);
|
return isDSiMode() ? REG_SCFG_MC & BIT(0) : !flashcardMounted;
|
||||||
case Drive::ramDrive:
|
case Drive::ramDrive:
|
||||||
return !ramdriveMounted;
|
return !ramdriveMounted;
|
||||||
case Drive::nand:
|
case Drive::nand:
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "gba.h"
|
#include "gba.h"
|
||||||
#include "lzss.h"
|
#include "lzss.h"
|
||||||
|
#include "main.h"
|
||||||
#include "ndsheaderbanner.h"
|
#include "ndsheaderbanner.h"
|
||||||
#include "read_card.h"
|
#include "read_card.h"
|
||||||
#include "tonccpy.h"
|
#include "tonccpy.h"
|
||||||
@ -151,7 +152,7 @@ void dumpFailMsg(std::string_view msg) {
|
|||||||
font->update(true);
|
font->update(true);
|
||||||
|
|
||||||
scanKeys();
|
scanKeys();
|
||||||
pressed = keysDownRepeat();
|
pressed = keysDown();
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
} while (!(pressed & KEY_A));
|
} while (!(pressed & KEY_A));
|
||||||
}
|
}
|
||||||
@ -574,8 +575,10 @@ void ndsCardSaveDump(const char* filename) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ndsCardSaveRestore(const char *filename) {
|
void ndsCardSaveRestore(const char *filename) {
|
||||||
|
bool usingFlashcard = (io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS) && flashcardMounted;
|
||||||
|
|
||||||
font->clear(false);
|
font->clear(false);
|
||||||
font->print(0, 0, false, STR_RESTORE_SELECTED_SAVE_CARD);
|
font->print(0, 0, false, (usingFlashcard ? STR_RESTORE_SELECTED_SAVE_CARD_FLASHCARD : STR_RESTORE_SELECTED_SAVE_CARD) + "\n\n" + STR_A_YES_B_NO);
|
||||||
font->update(false);
|
font->update(false);
|
||||||
|
|
||||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||||
@ -586,21 +589,16 @@ void ndsCardSaveRestore(const char *filename) {
|
|||||||
font->update(true);
|
font->update(true);
|
||||||
|
|
||||||
scanKeys();
|
scanKeys();
|
||||||
pressed = keysDownRepeat();
|
pressed = keysDown();
|
||||||
swiWaitForVBlank();
|
swiWaitForVBlank();
|
||||||
} while (!(pressed & (KEY_A | KEY_B)));
|
} while (!(pressed & (KEY_A | KEY_B)));
|
||||||
|
|
||||||
if(pressed & KEY_A) {
|
if(pressed & KEY_A) {
|
||||||
int type = cardEepromGetTypeFixed();
|
int type = cardEepromGetTypeFixed();
|
||||||
|
|
||||||
if(type == -1) { // NAND
|
if(type == -1 && !isRegularDS) { // NAND
|
||||||
if (cardInit(&ndsCardHeader) != 0) {
|
if (cardInit(&ndsCardHeader) != 0) {
|
||||||
font->clear(false);
|
dumpFailMsg(STR_UNABLE_TO_RESTORE_SAVE);
|
||||||
font->print(0, 0, false, STR_UNABLE_TO_RESTORE_SAVE);
|
|
||||||
font->update(false);
|
|
||||||
for (int i = 0; i < 60 * 2; i++) {
|
|
||||||
swiWaitForVBlank();
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -646,14 +644,47 @@ void ndsCardSaveRestore(const char *filename) {
|
|||||||
fclose(in);
|
fclose(in);
|
||||||
}
|
}
|
||||||
} else { // SPI
|
} else { // SPI
|
||||||
auxspi_extra card_type = auxspi_has_extra();
|
|
||||||
bool auxspi = card_type == AUXSPI_INFRARED;
|
|
||||||
FILE *in = fopen(filename, "rb");
|
FILE *in = fopen(filename, "rb");
|
||||||
if(in) {
|
if(in) {
|
||||||
unsigned char *buffer;
|
unsigned char *buffer = nullptr;
|
||||||
int size;
|
int size;
|
||||||
int length;
|
int length;
|
||||||
unsigned int num_blocks = 0, shift = 0, LEN = 0;
|
unsigned int num_blocks = 0, shift = 0, LEN = 0;
|
||||||
|
|
||||||
|
// Read save file length
|
||||||
|
fseek(in, 0, SEEK_END);
|
||||||
|
length = ftell(in);
|
||||||
|
fseek(in, 0, SEEK_SET);
|
||||||
|
|
||||||
|
// If using flashcard, read the save and swap carts
|
||||||
|
if(usingFlashcard) {
|
||||||
|
buffer = new unsigned char[length];
|
||||||
|
fread(buffer, 1, length, in);
|
||||||
|
fclose(in);
|
||||||
|
currentDrive = Drive::flashcard;
|
||||||
|
chdir("fat:/");
|
||||||
|
flashcardUnmount();
|
||||||
|
|
||||||
|
font->clear(false);
|
||||||
|
font->print(0, 0, false, STR_EJECT_FLASHCARD_INSERT_GAME + "\n\n" + STR_A_CONTINUE);
|
||||||
|
font->update(false);
|
||||||
|
|
||||||
|
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||||
|
do {
|
||||||
|
// Print time
|
||||||
|
font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen);
|
||||||
|
font->update(true);
|
||||||
|
|
||||||
|
scanKeys();
|
||||||
|
pressed = keysDown();
|
||||||
|
swiWaitForVBlank();
|
||||||
|
} while (!(pressed & KEY_A));
|
||||||
|
|
||||||
|
type = cardEepromGetTypeFixed();
|
||||||
|
}
|
||||||
|
|
||||||
|
auxspi_extra card_type = auxspi_has_extra();
|
||||||
|
bool auxspi = card_type == AUXSPI_INFRARED;
|
||||||
if(auxspi) {
|
if(auxspi) {
|
||||||
size = auxspi_save_size_log_2(card_type);
|
size = auxspi_save_size_log_2(card_type);
|
||||||
type = auxspi_save_type(card_type);
|
type = auxspi_save_type(card_type);
|
||||||
@ -675,11 +706,10 @@ void ndsCardSaveRestore(const char *filename) {
|
|||||||
} else {
|
} else {
|
||||||
size = cardEepromGetSizeFixed();
|
size = cardEepromGetSizeFixed();
|
||||||
}
|
}
|
||||||
fseek(in, 0, SEEK_END);
|
|
||||||
length = ftell(in);
|
|
||||||
fseek(in, 0, SEEK_SET);
|
|
||||||
if(length != (auxspi ? (int)(LEN * num_blocks) : size)) {
|
if(length != (auxspi ? (int)(LEN * num_blocks) : size)) {
|
||||||
fclose(in);
|
if(!usingFlashcard)
|
||||||
|
fclose(in);
|
||||||
dumpFailMsg(STR_SAVE_SIZE_MISMATCH_CARD);
|
dumpFailMsg(STR_SAVE_SIZE_MISMATCH_CARD);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -696,8 +726,12 @@ void ndsCardSaveRestore(const char *filename) {
|
|||||||
else
|
else
|
||||||
cardEepromChipEraseFixed();
|
cardEepromChipEraseFixed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If using flashcard restore from buffer,
|
||||||
|
// otherwise from file so big saves can work
|
||||||
if(auxspi){
|
if(auxspi){
|
||||||
buffer = new unsigned char[LEN];
|
if(!usingFlashcard)
|
||||||
|
buffer = new unsigned char[LEN];
|
||||||
font->print(0, 5, false, "[");
|
font->print(0, 5, false, "[");
|
||||||
font->print(-1, 5, false, "]");
|
font->print(-1, 5, false, "]");
|
||||||
for(unsigned int i = 0; i < num_blocks; i++) {
|
for(unsigned int i = 0; i < num_blocks; i++) {
|
||||||
@ -705,13 +739,18 @@ void ndsCardSaveRestore(const char *filename) {
|
|||||||
font->printf(0, 6, false, Alignment::left, Palette::white, STR_N_OF_N_BYTES.c_str(), i * LEN, length);
|
font->printf(0, 6, false, Alignment::left, Palette::white, STR_N_OF_N_BYTES.c_str(), i * LEN, length);
|
||||||
font->update(false);
|
font->update(false);
|
||||||
|
|
||||||
fread(buffer, 1, LEN, in);
|
if(usingFlashcard) {
|
||||||
auxspi_write_data(i << shift, buffer, LEN, type, card_type);
|
auxspi_write_data(i << shift, buffer + (LEN * i), LEN, type, card_type);
|
||||||
|
} else {
|
||||||
|
fread(buffer, 1, LEN, in);
|
||||||
|
auxspi_write_data(i << shift, buffer, LEN, type, card_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int blocks = size / 32;
|
int blocks = size / 32;
|
||||||
int written = 0;
|
int written = 0;
|
||||||
buffer = new unsigned char[blocks];
|
if(!usingFlashcard)
|
||||||
|
buffer = new unsigned char[blocks];
|
||||||
font->print(0, 5, false, "[");
|
font->print(0, 5, false, "[");
|
||||||
font->print(-1, 5, false, "]");
|
font->print(-1, 5, false, "]");
|
||||||
for(unsigned int i = 0; i < 32; i++) {
|
for(unsigned int i = 0; i < 32; i++) {
|
||||||
@ -719,13 +758,18 @@ void ndsCardSaveRestore(const char *filename) {
|
|||||||
font->printf(0, 6, false, Alignment::left, Palette::white, STR_N_OF_N_BYTES.c_str(), written, size);
|
font->printf(0, 6, false, Alignment::left, Palette::white, STR_N_OF_N_BYTES.c_str(), written, size);
|
||||||
font->update(false);
|
font->update(false);
|
||||||
|
|
||||||
fread(buffer, 1, blocks, in);
|
if(usingFlashcard) {
|
||||||
cardWriteEeprom(written, buffer, blocks, type);
|
cardWriteEeprom(written, buffer + (blocks * i), blocks, type);
|
||||||
|
} else {
|
||||||
|
fread(buffer, 1, blocks, in);
|
||||||
|
cardWriteEeprom(written, buffer, blocks, type);
|
||||||
|
}
|
||||||
written += blocks;
|
written += blocks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete[] buffer;
|
delete[] buffer;
|
||||||
fclose(in);
|
if(!usingFlashcard)
|
||||||
|
fclose(in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -953,7 +997,7 @@ void gbaCartSaveDump(const char *filename) {
|
|||||||
|
|
||||||
void gbaCartSaveRestore(const char *filename) {
|
void gbaCartSaveRestore(const char *filename) {
|
||||||
font->clear(false);
|
font->clear(false);
|
||||||
font->print(0, 0, false, STR_RESTORE_SELECTED_SAVE_CART);
|
font->print(0, 0, false, STR_RESTORE_SELECTED_SAVE_CART + "\n\n" + STR_A_YES_B_NO);
|
||||||
font->update(false);
|
font->update(false);
|
||||||
|
|
||||||
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
// Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
|
||||||
#include <nds.h>
|
#include <nds.h>
|
||||||
|
#include <nds/arm9/dldi.h>
|
||||||
#include <fat.h>
|
#include <fat.h>
|
||||||
|
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
@ -187,7 +188,10 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
|||||||
operations.push_back(FileOperation::trimNds);
|
operations.push_back(FileOperation::trimNds);
|
||||||
}
|
}
|
||||||
if(extension(entry->name, {"sav", "sav1", "sav2", "sav3", "sav4", "sav5", "sav6", "sav7", "sav8", "sav9"})) {
|
if(extension(entry->name, {"sav", "sav1", "sav2", "sav3", "sav4", "sav5", "sav6", "sav7", "sav8", "sav9"})) {
|
||||||
operations.push_back(FileOperation::restoreSave);
|
if(!(io_dldi_data->ioInterface.features & FEATURE_SLOT_NDS) || entry->size <= (1 << 20))
|
||||||
|
operations.push_back(FileOperation::restoreSaveNds);
|
||||||
|
if(isRegularDS && (entry->size == 512 || entry->size == 8192 || entry->size == 32768 || entry->size == 65536 || entry->size == 131072))
|
||||||
|
operations.push_back(FileOperation::restoreSaveGba);
|
||||||
}
|
}
|
||||||
if(currentDrive != Drive::fatImg && extension(entry->name, {"img", "sd", "sav", "pub", "pu1", "pu2", "pu3", "pu4", "pu5", "pu6", "pu7", "pu8", "pu9", "prv", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", "pr8", "pr9"})) {
|
if(currentDrive != Drive::fatImg && extension(entry->name, {"img", "sd", "sav", "pub", "pu1", "pu2", "pu3", "pu4", "pu5", "pu6", "pu7", "pu8", "pu9", "prv", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", "pr8", "pr9"})) {
|
||||||
operations.push_back(FileOperation::mountImg);
|
operations.push_back(FileOperation::mountImg);
|
||||||
@ -238,8 +242,14 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
|||||||
case FileOperation::trimNds:
|
case FileOperation::trimNds:
|
||||||
font->print(3, row++, false, STR_TRIM_NDS);
|
font->print(3, row++, false, STR_TRIM_NDS);
|
||||||
break;
|
break;
|
||||||
case FileOperation::restoreSave:
|
case FileOperation::restoreSaveNds:
|
||||||
font->print(3, row++, false, STR_RESTORE_SAVE);
|
if(!isRegularDS)
|
||||||
|
font->print(3, row++, false, STR_RESTORE_SAVE);
|
||||||
|
else
|
||||||
|
font->print(3, row++, false, STR_RESTORE_SAVE_NDS);
|
||||||
|
break;
|
||||||
|
case FileOperation::restoreSaveGba:
|
||||||
|
font->print(3, row++, false, STR_RESTORE_SAVE_GBA);
|
||||||
break;
|
break;
|
||||||
case FileOperation::mountImg:
|
case FileOperation::mountImg:
|
||||||
font->print(3, row++, false, STR_MOUNT_FAT_IMG);
|
font->print(3, row++, false, STR_MOUNT_FAT_IMG);
|
||||||
@ -328,12 +338,11 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) {
|
|||||||
applaunch = true;
|
applaunch = true;
|
||||||
return FileOperation::bootFile;
|
return FileOperation::bootFile;
|
||||||
break;
|
break;
|
||||||
} case FileOperation::restoreSave: {
|
} case FileOperation::restoreSaveNds: {
|
||||||
if(isDSiMode()) {
|
ndsCardSaveRestore(entry->name.c_str());
|
||||||
ndsCardSaveRestore(entry->name.c_str());
|
break;
|
||||||
} else {
|
} case FileOperation::restoreSaveGba: {
|
||||||
gbaCartSaveRestore(entry->name.c_str());
|
gbaCartSaveRestore(entry->name.c_str());
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
} case FileOperation::copySdOut: {
|
} case FileOperation::copySdOut: {
|
||||||
if (access("sd:/gm9i", F_OK) != 0) {
|
if (access("sd:/gm9i", F_OK) != 0) {
|
||||||
|
|||||||
@ -44,7 +44,8 @@ enum class FileOperation {
|
|||||||
ndsInfo,
|
ndsInfo,
|
||||||
trimNds,
|
trimNds,
|
||||||
mountImg,
|
mountImg,
|
||||||
restoreSave,
|
restoreSaveNds,
|
||||||
|
restoreSaveGba,
|
||||||
showInfo,
|
showInfo,
|
||||||
copySdOut,
|
copySdOut,
|
||||||
copyFatOut,
|
copyFatOut,
|
||||||
|
|||||||
@ -96,6 +96,8 @@ STRING(MOUNT_NITROFS, "Mount NitroFS")
|
|||||||
STRING(SHOW_NDS_INFO, "Show NDS file info")
|
STRING(SHOW_NDS_INFO, "Show NDS file info")
|
||||||
STRING(TRIM_NDS, "Trim NDS file")
|
STRING(TRIM_NDS, "Trim NDS file")
|
||||||
STRING(RESTORE_SAVE, "Restore save")
|
STRING(RESTORE_SAVE, "Restore save")
|
||||||
|
STRING(RESTORE_SAVE_NDS, "Restore save (Slot-1)")
|
||||||
|
STRING(RESTORE_SAVE_GBA, "Restore save (Slot-2)")
|
||||||
STRING(MOUNT_FAT_IMG, "Mount as FAT image")
|
STRING(MOUNT_FAT_IMG, "Mount as FAT image")
|
||||||
STRING(OPEN_HEX, "Open in hex editor")
|
STRING(OPEN_HEX, "Open in hex editor")
|
||||||
STRING(SHOW_DIRECTORY_INFO, "Show directory info")
|
STRING(SHOW_DIRECTORY_INFO, "Show directory info")
|
||||||
@ -150,8 +152,10 @@ STRING(FAILED_TO_RESTORE_SAVE, "Failed to restore the save.")
|
|||||||
STRING(UNABLE_TO_RESTORE_SAVE, "Unable to restore the save.")
|
STRING(UNABLE_TO_RESTORE_SAVE, "Unable to restore the save.")
|
||||||
STRING(SAVE_SIZE_MISMATCH_CARD, "The size of this save doesn't match the size of the inserted game card.\n\nWrite cancelled!")
|
STRING(SAVE_SIZE_MISMATCH_CARD, "The size of this save doesn't match the size of the inserted game card.\n\nWrite cancelled!")
|
||||||
STRING(SAVE_SIZE_MISMATCH_CART, "The size of this save doesn't match the size of the inserted game pak.\n\nWrite cancelled!")
|
STRING(SAVE_SIZE_MISMATCH_CART, "The size of this save doesn't match the size of the inserted game pak.\n\nWrite cancelled!")
|
||||||
STRING(RESTORE_SELECTED_SAVE_CARD, "Restore the selected save to the inserted game card?\n\n(\\A yes, \\B no)")
|
STRING(RESTORE_SELECTED_SAVE_CARD, "Restore the selected save to the inserted game card?")
|
||||||
STRING(RESTORE_SELECTED_SAVE_CART, "Restore the selected save to the inserted game pak?\n\n(\\A yes, \\B no)")
|
STRING(RESTORE_SELECTED_SAVE_CARD_FLASHCARD, "Unmount the flashcard and restore the selected save to a game card?")
|
||||||
|
STRING(RESTORE_SELECTED_SAVE_CART, "Restore the selected save to the inserted game pak?")
|
||||||
|
STRING(EJECT_FLASHCARD_INSERT_GAME, "Eject your flashcard and insert the game card to restore to.")
|
||||||
STRING(PROGRESS, "Progress:")
|
STRING(PROGRESS, "Progress:")
|
||||||
STRING(N_OF_N_BYTES, "%d/%d Bytes")
|
STRING(N_OF_N_BYTES, "%d/%d Bytes")
|
||||||
STRING(NDS_IS_DUMPING, "%s.nds\nis dumping...")
|
STRING(NDS_IS_DUMPING, "%s.nds\nis dumping...")
|
||||||
|
|||||||
@ -91,6 +91,8 @@ MOUNT_NITROFS=Mount NitroFS
|
|||||||
SHOW_NDS_INFO=Show NDS file info
|
SHOW_NDS_INFO=Show NDS file info
|
||||||
TRIM_NDS=Trim NDS file
|
TRIM_NDS=Trim NDS file
|
||||||
RESTORE_SAVE=Restore save
|
RESTORE_SAVE=Restore save
|
||||||
|
RESTORE_SAVE_NDS=Restore save (Slot-1)
|
||||||
|
RESTORE_SAVE_GBA=Restore save (Slot-2)
|
||||||
MOUNT_FAT_IMG=Mount as FAT image
|
MOUNT_FAT_IMG=Mount as FAT image
|
||||||
OPEN_HEX=Open in hex editor
|
OPEN_HEX=Open in hex editor
|
||||||
SHOW_DIRECTORY_INFO=Show directory info
|
SHOW_DIRECTORY_INFO=Show directory info
|
||||||
@ -142,8 +144,10 @@ FAILED_TO_RESTORE_SAVE=Failed to restore the save.
|
|||||||
UNABLE_TO_RESTORE_SAVE=Unable to restore the save.
|
UNABLE_TO_RESTORE_SAVE=Unable to restore the save.
|
||||||
SAVE_SIZE_MISMATCH_CARD=The size of this save doesn't match the size of the inserted game card.\n\nWrite cancelled!
|
SAVE_SIZE_MISMATCH_CARD=The size of this save doesn't match the size of the inserted game card.\n\nWrite cancelled!
|
||||||
SAVE_SIZE_MISMATCH_CART=The size of this save doesn't match the size of the inserted game pak.\n\nWrite cancelled!
|
SAVE_SIZE_MISMATCH_CART=The size of this save doesn't match the size of the inserted game pak.\n\nWrite cancelled!
|
||||||
RESTORE_SELECTED_SAVE_CARD=Restore the selected save to the inserted game card?\n\n(\A yes, \B no)
|
RESTORE_SELECTED_SAVE_CARD=Restore the selected save to the inserted game card?
|
||||||
RESTORE_SELECTED_SAVE_CART=Restore the selected save to the inserted game pak?\n\n(\A yes, \B no)
|
RESTORE_SELECTED_SAVE_CARD_FLASHCARD=Unmount the flashcard and restore the selected save to a game card?
|
||||||
|
RESTORE_SELECTED_SAVE_CART=Restore the selected save to the inserted game pak?
|
||||||
|
EJECT_FLASHCARD_INSERT_GAME=Eject your flashcard and insert the game card to restore to.
|
||||||
PROGRESS=Progress:
|
PROGRESS=Progress:
|
||||||
N_OF_N_BYTES=%d/%d Bytes
|
N_OF_N_BYTES=%d/%d Bytes
|
||||||
NDS_IS_DUMPING=%s.nds\nis dumping...
|
NDS_IS_DUMPING=%s.nds\nis dumping...
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user