2016-04-05 05:27:28 +02:00
|
|
|
/*
|
|
|
|
* config.c
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "utils.h"
|
|
|
|
#include "screeninit.h"
|
|
|
|
#include "draw.h"
|
|
|
|
#include "fs.h"
|
2016-05-09 03:41:00 +02:00
|
|
|
#include "i2c.h"
|
2016-04-05 05:27:28 +02:00
|
|
|
#include "buttons.h"
|
|
|
|
|
2016-04-11 05:15:44 +02:00
|
|
|
void configureCFW(const char *configPath)
|
2016-04-05 05:27:28 +02:00
|
|
|
{
|
2016-05-09 03:41:00 +02:00
|
|
|
u32 needToDeinit = initScreens();
|
2016-04-05 05:27:28 +02:00
|
|
|
|
|
|
|
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
|
2016-05-09 03:41:00 +02:00
|
|
|
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
const char *multiOptionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )",
|
2016-04-13 00:33:03 +02:00
|
|
|
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
|
2016-04-12 23:18:07 +02:00
|
|
|
|
|
|
|
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
|
2016-04-26 14:11:34 +02:00
|
|
|
"( ) SysNAND is updated (A9LH-only)",
|
2016-04-12 23:18:07 +02:00
|
|
|
"( ) Force A9LH detection",
|
|
|
|
"( ) Use second EmuNAND as default",
|
Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:46:36 +02:00
|
|
|
"( ) Enable region/language emulation",
|
2016-04-26 22:06:19 +02:00
|
|
|
"( ) Enable developer features",
|
2016-04-12 23:18:07 +02:00
|
|
|
"( ) Show current NAND in System Settings",
|
|
|
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
|
|
|
"( ) Enable splash screen with no screen-init" };
|
|
|
|
|
|
|
|
struct multiOption {
|
2016-04-13 15:19:35 +02:00
|
|
|
int posXs[4];
|
2016-04-05 05:27:28 +02:00
|
|
|
int posY;
|
|
|
|
u32 enabled;
|
2016-04-12 23:18:07 +02:00
|
|
|
} multiOptions[] = {
|
|
|
|
{ .posXs = {26, 31, 36, 41} },
|
2016-04-13 00:33:03 +02:00
|
|
|
{ .posXs = {17, 26, 32, 44} }
|
2016-04-12 23:18:07 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
//Calculate the amount of the various kinds of options and pre-select the first single one
|
|
|
|
u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption),
|
|
|
|
singleOptionsAmount = sizeof(singleOptionsText) / sizeof(char *),
|
2016-04-13 15:19:35 +02:00
|
|
|
totalIndexes = multiOptionsAmount + singleOptionsAmount - 1,
|
2016-04-12 23:18:07 +02:00
|
|
|
selectedOption = multiOptionsAmount;
|
|
|
|
|
|
|
|
struct singleOption {
|
|
|
|
int posY;
|
|
|
|
u32 enabled;
|
|
|
|
} singleOptions[singleOptionsAmount];
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
//Parse the existing options
|
|
|
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
|
|
|
multiOptions[i].enabled = MULTICONFIG(i);
|
|
|
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
|
|
|
singleOptions[i].enabled = CONFIG(i);
|
2016-04-05 23:01:46 +02:00
|
|
|
|
|
|
|
//Character to display a selected option
|
|
|
|
char selected = 'x';
|
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
int endPos = 42;
|
2016-04-05 23:01:46 +02:00
|
|
|
|
2016-04-13 00:33:03 +02:00
|
|
|
//Display all the multiple choice options in white
|
2016-04-12 23:18:07 +02:00
|
|
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
2016-04-05 23:01:46 +02:00
|
|
|
{
|
2016-04-12 23:18:07 +02:00
|
|
|
multiOptions[i].posY = endPos + SPACING_Y;
|
|
|
|
endPos = drawString(multiOptionsText[i], 10, multiOptions[i].posY, COLOR_WHITE);
|
|
|
|
drawCharacter(selected, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
|
2016-04-05 23:01:46 +02:00
|
|
|
}
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-04-13 15:19:35 +02:00
|
|
|
endPos += SPACING_Y / 2;
|
|
|
|
u32 color = COLOR_RED;
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-04-13 00:33:03 +02:00
|
|
|
//Display all the normal options in white except for the first one
|
2016-04-13 15:19:35 +02:00
|
|
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
2016-04-12 23:18:07 +02:00
|
|
|
{
|
|
|
|
singleOptions[i].posY = endPos + SPACING_Y;
|
2016-04-13 15:19:35 +02:00
|
|
|
endPos = drawString(singleOptionsText[i], 10, singleOptions[i].posY, color);
|
|
|
|
if(singleOptions[i].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[i].posY, color);
|
|
|
|
color = COLOR_WHITE;
|
2016-04-12 23:18:07 +02:00
|
|
|
}
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
u32 pressed = 0;
|
2016-04-05 23:01:46 +02:00
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
//Boring configuration menu
|
|
|
|
while(pressed != BUTTON_START)
|
|
|
|
{
|
2016-04-13 15:19:35 +02:00
|
|
|
do
|
|
|
|
{
|
2016-04-05 05:27:28 +02:00
|
|
|
pressed = waitInput();
|
|
|
|
}
|
|
|
|
while(!(pressed & MENU_BUTTONS));
|
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
if(pressed != BUTTON_A)
|
2016-04-05 05:27:28 +02:00
|
|
|
{
|
2016-04-13 15:19:35 +02:00
|
|
|
//Remember the previously selected option
|
|
|
|
u32 oldSelectedOption = selectedOption;
|
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
switch(pressed)
|
|
|
|
{
|
|
|
|
case BUTTON_UP:
|
2016-04-13 15:19:35 +02:00
|
|
|
selectedOption = !selectedOption ? totalIndexes : selectedOption - 1;
|
2016-04-12 23:18:07 +02:00
|
|
|
break;
|
|
|
|
case BUTTON_DOWN:
|
2016-04-13 15:19:35 +02:00
|
|
|
selectedOption = selectedOption == totalIndexes ? 0 : selectedOption + 1;
|
2016-04-12 23:18:07 +02:00
|
|
|
break;
|
|
|
|
case BUTTON_LEFT:
|
|
|
|
selectedOption = 0;
|
|
|
|
break;
|
|
|
|
case BUTTON_RIGHT:
|
2016-04-13 15:19:35 +02:00
|
|
|
selectedOption = totalIndexes;
|
2016-04-12 23:18:07 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-04-13 15:19:35 +02:00
|
|
|
if(selectedOption == oldSelectedOption) continue;
|
|
|
|
|
2016-04-13 01:08:13 +02:00
|
|
|
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
|
2016-04-12 23:18:07 +02:00
|
|
|
if(oldSelectedOption < multiOptionsAmount)
|
|
|
|
{
|
|
|
|
drawString(multiOptionsText[oldSelectedOption], 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
|
|
|
drawCharacter(selected, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
|
|
|
|
drawString(singleOptionsText[singleOldSelected], 10, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
|
|
|
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
|
|
|
|
}
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
if(selectedOption < multiOptionsAmount)
|
|
|
|
drawString(multiOptionsText[selectedOption], 10, multiOptions[selectedOption].posY, COLOR_RED);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u32 singleSelected = selectedOption - multiOptionsAmount;
|
|
|
|
drawString(singleOptionsText[singleSelected], 10, singleOptions[singleSelected].posY, COLOR_RED);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-04-13 15:19:35 +02:00
|
|
|
//The selected option's status changed, print the 'x's accordingly
|
2016-04-12 23:18:07 +02:00
|
|
|
if(selectedOption < multiOptionsAmount)
|
|
|
|
{
|
|
|
|
u32 oldEnabled = multiOptions[selectedOption].enabled;
|
|
|
|
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
|
|
|
|
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
|
|
|
|
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
|
|
|
|
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
|
|
|
|
}
|
|
|
|
}
|
2016-04-13 15:19:35 +02:00
|
|
|
|
|
|
|
//In any case, if the current option is enabled (or a multiple choice option is selected) we must display a red 'x'
|
|
|
|
if(selectedOption < multiOptionsAmount)
|
|
|
|
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
u32 singleSelected = selectedOption - multiOptionsAmount;
|
|
|
|
if(singleOptions[singleSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
|
|
|
|
}
|
2016-04-05 05:27:28 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
//Preserve the last-used boot options (last 12 bits)
|
2016-04-12 23:18:07 +02:00
|
|
|
config &= 0x3F;
|
2016-04-05 05:27:28 +02:00
|
|
|
|
|
|
|
//Parse and write the new configuration
|
2016-04-12 23:18:07 +02:00
|
|
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
|
|
|
config |= multiOptions[i].enabled << (i * 2 + 6);
|
|
|
|
for(u32 i = 0; i < singleOptionsAmount; i++)
|
|
|
|
config |= singleOptions[i].enabled << (i + 16);
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-04-12 23:18:07 +02:00
|
|
|
fileWrite(&config, configPath, 4);
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-05-09 03:41:00 +02:00
|
|
|
//Wait for the pressed buttons to change
|
|
|
|
while(HID_PAD == BUTTON_START);
|
2016-04-05 05:27:28 +02:00
|
|
|
|
2016-05-09 03:41:00 +02:00
|
|
|
if(needToDeinit)
|
|
|
|
{
|
|
|
|
//Turn off backlight
|
|
|
|
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
|
|
|
|
deinitScreens();
|
2016-05-09 14:38:20 +02:00
|
|
|
PDN_GPU_CNT = 1;
|
2016-05-09 03:41:00 +02:00
|
|
|
}
|
2016-05-10 01:27:58 +02:00
|
|
|
|
|
|
|
u64 t0 = chrono();
|
2016-05-10 01:38:08 +02:00
|
|
|
while(chrono() - t0 < 2 * TICKS_PER_SEC); //wait for 2s
|
|
|
|
}
|