Moved config file to INI, and more
- Add support for saving screen filters color temperature and NTP timezone offset (you still need to go to misc->save config) - some advanced options moved to "in ini file only"; "patch games" is now enabled by default - ntp: fix support for UTC+12 to +14 - remove deprecated custom svc 0x2e
This commit is contained in:
parent
d798ff0efc
commit
676bbf0d88
1
.gitattributes
vendored
1
.gitattributes
vendored
@ -1 +1,2 @@
|
|||||||
*.xml text eol=lf
|
*.xml text eol=lf
|
||||||
|
*.ini text eol=lf
|
||||||
|
@ -162,10 +162,16 @@ memory.o strings.o: CFLAGS += -O3
|
|||||||
patches.o config.o: CFLAGS += -DCONFIG_TITLE="\"$(APP_TITLE) $(REVISION) configuration\""\
|
patches.o config.o: CFLAGS += -DCONFIG_TITLE="\"$(APP_TITLE) $(REVISION) configuration\""\
|
||||||
-DVERSION_MAJOR="$(VERSION_MAJOR)" -DVERSION_MINOR="$(VERSION_MINOR)"\
|
-DVERSION_MAJOR="$(VERSION_MAJOR)" -DVERSION_MINOR="$(VERSION_MINOR)"\
|
||||||
-DVERSION_BUILD="$(VERSION_BUILD)" -DISRELEASE="$(IS_RELEASE)" -DCOMMIT_HASH="0x$(COMMIT)"
|
-DVERSION_BUILD="$(VERSION_BUILD)" -DISRELEASE="$(IS_RELEASE)" -DCOMMIT_HASH="0x$(COMMIT)"
|
||||||
|
config.o ini.o: CFLAGS += -DINI_HANDLER_LINENO=1 -DINI_STOP_ON_FIRST_ERROR=1
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
# you need a rule like this for each extension you use as binary data
|
# you need a rule like this for each extension you use as binary data
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
%.bin.o %_bin.h : %.bin
|
%.bin.o %_bin.h : %.bin
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.ini.o %_ini.h: %.ini
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(bin2o)
|
@$(bin2o)
|
||||||
|
BIN
arm9/data/config_template.ini
Normal file
BIN
arm9/data/config_template.ini
Normal file
Binary file not shown.
@ -25,6 +25,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
#include <strings.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "fs.h"
|
#include "fs.h"
|
||||||
@ -35,6 +36,9 @@
|
|||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
#include "pin.h"
|
#include "pin.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
|
#include "ini.h"
|
||||||
|
|
||||||
|
#include "config_template_ini.h" // note that it has an extra NUL byte inserted
|
||||||
|
|
||||||
#define MAKE_LUMA_VERSION_MCU(major, minor, build) (u16)(((major) & 0xFF) << 8 | ((minor) & 0x1F) << 5 | ((build) & 7))
|
#define MAKE_LUMA_VERSION_MCU(major, minor, build) (u16)(((major) & 0xFF) << 8 | ((minor) & 0x1F) << 5 | ((build) & 7))
|
||||||
|
|
||||||
@ -45,6 +49,403 @@ static CfgData oldConfig;
|
|||||||
static CfgDataMcu configDataMcu;
|
static CfgDataMcu configDataMcu;
|
||||||
static_assert(sizeof(CfgDataMcu) > 0, "wrong data size");
|
static_assert(sizeof(CfgDataMcu) > 0, "wrong data size");
|
||||||
|
|
||||||
|
// INI parsing
|
||||||
|
// ===========================================================
|
||||||
|
|
||||||
|
static const char *singleOptionIniNamesBoot[] = {
|
||||||
|
"autoboot_emunand",
|
||||||
|
"use_emunand_firm_if_r_pressed",
|
||||||
|
"enable_external_firm_and_modules",
|
||||||
|
"enable_game_patching",
|
||||||
|
"show_system_settings_string",
|
||||||
|
"show_gba_boot_screen",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *singleOptionIniNamesMisc[] = {
|
||||||
|
"use_dev_unitinfo",
|
||||||
|
"disable_arm11_exception_handlers",
|
||||||
|
"enable_safe_firm_rosalina",
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *keyNames[] = {
|
||||||
|
"A", "B", "Select", "Start", "Right", "Left", "Up", "Down", "R", "L", "X", "Y",
|
||||||
|
"?", "?",
|
||||||
|
"ZL", "ZR",
|
||||||
|
"?", "?", "?", "?",
|
||||||
|
"Touch",
|
||||||
|
"?", "?", "?",
|
||||||
|
"CStick Right", "CStick Left", "CStick Up", "CStick Down",
|
||||||
|
"CPad Right", "CPad Left", "CPad Up", "CPad Down",
|
||||||
|
};
|
||||||
|
|
||||||
|
static int parseBoolOption(bool *out, const char *val)
|
||||||
|
{
|
||||||
|
*out = false;
|
||||||
|
if (strlen(val) != 1) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val[0] == '0') {
|
||||||
|
return 0;
|
||||||
|
} else if (val[0] == '1') {
|
||||||
|
*out = true;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseDecIntOption(s64 *out, const char *val, s64 minval, s64 maxval)
|
||||||
|
{
|
||||||
|
*out = 0;
|
||||||
|
size_t numDigits = strlen(val);
|
||||||
|
s64 res = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
|
||||||
|
s64 sign = 1;
|
||||||
|
if (numDigits >= 2) {
|
||||||
|
if (val[0] == '+') {
|
||||||
|
++i;
|
||||||
|
} else if (val[0] == '-') {
|
||||||
|
sign = -1;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; i < numDigits; i++) {
|
||||||
|
u64 n = (u64)(val[i] - '0');
|
||||||
|
if (n > 9) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = 10*res + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
res *= sign;
|
||||||
|
if (res <= maxval && res >= minval) {
|
||||||
|
*out = res;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseHexIntOption(u64 *out, const char *val, u64 minval, u64 maxval)
|
||||||
|
{
|
||||||
|
*out = 0;
|
||||||
|
size_t numDigits = strlen(val);
|
||||||
|
u64 res = 0;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < numDigits; i++) {
|
||||||
|
char c = val[i];
|
||||||
|
if ((u64)(c - '0') <= 9) {
|
||||||
|
res = 16*res + (u64)(c - '0');
|
||||||
|
} else if ((u64)(c - 'a') <= 5) {
|
||||||
|
res = 16*res + (u64)(c - 'a' + 10);
|
||||||
|
} else if ((u64)(c - 'A') <= 5) {
|
||||||
|
res = 16*res + (u64)(c - 'A' + 10);
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res <= maxval && res >= minval) {
|
||||||
|
*out = res;
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int parseKeyComboOption(u32 *out, const char *val)
|
||||||
|
{
|
||||||
|
const char *startpos = val;
|
||||||
|
const char *endpos;
|
||||||
|
|
||||||
|
*out = 0;
|
||||||
|
u32 keyCombo = 0;
|
||||||
|
do {
|
||||||
|
// Copy the button name (note that 16 chars is longer than any of the key names)
|
||||||
|
char name[17];
|
||||||
|
endpos = strchr(startpos, '+');
|
||||||
|
size_t n = endpos == NULL ? 16 : endpos - startpos;
|
||||||
|
n = n > 16 ? 16 : n;
|
||||||
|
strncpy(name, startpos, n);
|
||||||
|
name[n] = '\0';
|
||||||
|
|
||||||
|
if (strcmp(name, "?") == 0) {
|
||||||
|
// Lol no, bail out
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (size_t i = 0; i < sizeof(keyNames)/sizeof(keyNames[0]); i++) {
|
||||||
|
if (strcasecmp(keyNames[i], name) == 0) {
|
||||||
|
found = true;
|
||||||
|
keyCombo |= 1u << i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endpos != NULL) {
|
||||||
|
startpos = endpos + 1;
|
||||||
|
}
|
||||||
|
} while(endpos != NULL && *startpos != '\0');
|
||||||
|
|
||||||
|
if (*startpos == '\0') {
|
||||||
|
// Trailing '+'
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
*out = keyCombo;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void menuComboToString(char *out, u32 combo)
|
||||||
|
{
|
||||||
|
char *outOrig = out;
|
||||||
|
out[0] = 0;
|
||||||
|
for(int i = 31; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if(combo & (1 << i))
|
||||||
|
{
|
||||||
|
strcpy(out, keyNames[i]);
|
||||||
|
out += strlen(keyNames[i]);
|
||||||
|
*out++ = '+';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (out != outOrig)
|
||||||
|
out[-1] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool hasIniParseError = false;
|
||||||
|
static int iniParseErrorLine = 0;
|
||||||
|
|
||||||
|
#define CHECK_PARSE_OPTION(res) do { if((res) < 0) { hasIniParseError = true; iniParseErrorLine = lineno; return 0; } } while(false)
|
||||||
|
|
||||||
|
static int configIniHandler(void* user, const char* section, const char* name, const char* value, int lineno)
|
||||||
|
{
|
||||||
|
CfgData *cfg = (CfgData *)user;
|
||||||
|
if (strcmp(section, "meta") == 0) {
|
||||||
|
if (strcmp(name, "config_version_major") == 0) {
|
||||||
|
s64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 0xFFFF));
|
||||||
|
cfg->formatVersionMajor = (u16)opt;
|
||||||
|
return 1;
|
||||||
|
} else if (strcmp(name, "config_version_minor") == 0) {
|
||||||
|
s64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 0xFFFF));
|
||||||
|
cfg->formatVersionMinor = (u16)opt;
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
}
|
||||||
|
} else if (strcmp(section, "boot") == 0) {
|
||||||
|
// Simple options displayed on the Luma3DS boot screen
|
||||||
|
for (size_t i = 0; i < sizeof(singleOptionIniNamesBoot)/sizeof(singleOptionIniNamesBoot[0]); i++) {
|
||||||
|
if (strcmp(name, singleOptionIniNamesBoot[i]) == 0) {
|
||||||
|
bool opt;
|
||||||
|
CHECK_PARSE_OPTION(parseBoolOption(&opt, value));
|
||||||
|
cfg->config |= (u32)opt << i;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multi-choice options displayed on the Luma3DS boot screen
|
||||||
|
|
||||||
|
if (strcmp(name, "default_emunand_number") == 0) {
|
||||||
|
s64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 1, 4));
|
||||||
|
cfg->multiConfig |= (opt - 1) << (2 * (u32)DEFAULTEMU);
|
||||||
|
return 1;
|
||||||
|
} else if (strcmp(name, "brightness_level") == 0) {
|
||||||
|
s64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 1, 4));
|
||||||
|
cfg->multiConfig |= (4 - opt) << (2 * (u32)BRIGHTNESS);
|
||||||
|
return 1;
|
||||||
|
} else if (strcmp(name, "splash_position") == 0) {
|
||||||
|
if (strcasecmp(value, "off") == 0) {
|
||||||
|
cfg->multiConfig |= 0 << (2 * (u32)SPLASH);
|
||||||
|
return 1;
|
||||||
|
} else if (strcasecmp(value, "before payloads") == 0) {
|
||||||
|
cfg->multiConfig |= 1 << (2 * (u32)SPLASH);
|
||||||
|
return 1;
|
||||||
|
} else if (strcasecmp(value, "after payloads") == 0) {
|
||||||
|
cfg->multiConfig |= 2 << (2 * (u32)SPLASH);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
}
|
||||||
|
} else if (strcmp(name, "splash_duration_ms") == 0) {
|
||||||
|
// Not displayed in the menu anymore, but more configurable
|
||||||
|
s64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 0xFFFFFFFFu));
|
||||||
|
cfg->splashDurationMsec = (u32)opt;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else if (strcmp(name, "pin_lock_num_digits") == 0) {
|
||||||
|
s64 opt;
|
||||||
|
u32 encodedOpt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 0, 8));
|
||||||
|
// Only allow for 0 (off), 4, 6 or 8 'digits'
|
||||||
|
switch (opt) {
|
||||||
|
case 0: encodedOpt = 0; break;
|
||||||
|
case 4: encodedOpt = 1; break;
|
||||||
|
case 6: encodedOpt = 2; break;
|
||||||
|
case 8: encodedOpt = 3; break;
|
||||||
|
default: {
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cfg->multiConfig |= encodedOpt << (2 * (u32)PIN);
|
||||||
|
return 1;
|
||||||
|
} else if (strcmp(name, "app_launch_new_3ds_cpu") == 0) {
|
||||||
|
if (strcasecmp(value, "off") == 0) {
|
||||||
|
cfg->multiConfig |= 0 << (2 * (u32)NEWCPU);
|
||||||
|
return 1;
|
||||||
|
} else if (strcasecmp(value, "clock") == 0) {
|
||||||
|
cfg->multiConfig |= 1 << (2 * (u32)NEWCPU);
|
||||||
|
return 1;
|
||||||
|
} else if (strcasecmp(value, "l2") == 0) {
|
||||||
|
cfg->multiConfig |= 2 << (2 * (u32)NEWCPU);
|
||||||
|
return 1;
|
||||||
|
} else if (strcasecmp(value, "clock+l2") == 0) {
|
||||||
|
cfg->multiConfig |= 3 << (2 * (u32)NEWCPU);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
} else if (strcmp(section, "rosalina") == 0) {
|
||||||
|
// Rosalina options
|
||||||
|
if (strcmp(name, "hbldr_3dsx_titleid") == 0) {
|
||||||
|
u64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseHexIntOption(&opt, value, 0, 0xFFFFFFFFFFFFFFFFull));
|
||||||
|
cfg->hbldr3dsxTitleId = opt;
|
||||||
|
return 1;
|
||||||
|
} else if (strcmp(name, "rosalina_menu_combo") == 0) {
|
||||||
|
u32 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseKeyComboOption(&opt, value));
|
||||||
|
cfg->rosalinaMenuCombo = opt;
|
||||||
|
return 1;
|
||||||
|
} else if (strcmp(name, "screen_filters_cct") == 0) {
|
||||||
|
s64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, 1000, 25100));
|
||||||
|
cfg->screenFiltersCct = (u32)opt;
|
||||||
|
return 1;
|
||||||
|
} else if (strcmp(name, "ntp_tz_offset_min") == 0) {
|
||||||
|
s64 opt;
|
||||||
|
CHECK_PARSE_OPTION(parseDecIntOption(&opt, value, -779, 899));
|
||||||
|
cfg->ntpTzOffetMinutes = (s16)opt;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
}
|
||||||
|
} else if (strcmp(section, "misc") == 0) {
|
||||||
|
for (size_t i = 0; i < sizeof(singleOptionIniNamesMisc)/sizeof(singleOptionIniNamesMisc[0]); i++) {
|
||||||
|
if (strcmp(name, singleOptionIniNamesMisc[i]) == 0) {
|
||||||
|
bool opt;
|
||||||
|
CHECK_PARSE_OPTION(parseBoolOption(&opt, value));
|
||||||
|
cfg->config |= (u32)opt << (i + (u32)PATCHUNITINFO);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
} else {
|
||||||
|
CHECK_PARSE_OPTION(-1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t saveLumaIniConfigToStr(char *out)
|
||||||
|
{
|
||||||
|
const CfgData *cfg = &configData;
|
||||||
|
|
||||||
|
char lumaVerStr[64];
|
||||||
|
char lumaRevSuffixStr[16];
|
||||||
|
char rosalinaMenuComboStr[128];
|
||||||
|
|
||||||
|
const char *splashPosStr;
|
||||||
|
const char *n3dsCpuStr;
|
||||||
|
|
||||||
|
switch (MULTICONFIG(SPLASH)) {
|
||||||
|
default: case 0: splashPosStr = "off"; break;
|
||||||
|
case 1: splashPosStr = "before payloads"; break;
|
||||||
|
case 2: splashPosStr = "after payloads"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (MULTICONFIG(NEWCPU)) {
|
||||||
|
default: case 0: n3dsCpuStr = "off"; break;
|
||||||
|
case 1: n3dsCpuStr = "clock"; break;
|
||||||
|
case 2: n3dsCpuStr = "l2"; break;
|
||||||
|
case 3: n3dsCpuStr = "clock+l2"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (VERSION_BUILD != 0) {
|
||||||
|
sprintf(lumaVerStr, "Luma3DS v%d.%d.%d", (int)VERSION_MAJOR, (int)VERSION_MINOR, (int)VERSION_BUILD);
|
||||||
|
} else {
|
||||||
|
sprintf(lumaVerStr, "Luma3DS v%d.%d", (int)VERSION_MAJOR, (int)VERSION_MINOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ISRELEASE) {
|
||||||
|
strcpy(lumaRevSuffixStr, "");
|
||||||
|
} else {
|
||||||
|
sprintf(lumaRevSuffixStr, "-%08lx", (u32)COMMIT_HASH);
|
||||||
|
}
|
||||||
|
|
||||||
|
menuComboToString(rosalinaMenuComboStr, cfg->rosalinaMenuCombo);
|
||||||
|
|
||||||
|
static const int pinOptionToDigits[] = { 0, 4, 6, 8 };
|
||||||
|
int pinNumDigits = pinOptionToDigits[MULTICONFIG(PIN)];
|
||||||
|
|
||||||
|
int n = sprintf(
|
||||||
|
out, (const char *)config_template_ini,
|
||||||
|
lumaVerStr, lumaRevSuffixStr,
|
||||||
|
|
||||||
|
(int)CONFIG_VERSIONMAJOR, (int)CONFIG_VERSIONMINOR,
|
||||||
|
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
|
||||||
|
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
|
||||||
|
(int)CONFIG(PATCHVERSTRING), (int)CONFIG(SHOWGBABOOT),
|
||||||
|
|
||||||
|
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
|
||||||
|
splashPosStr, (unsigned int)cfg->splashDurationMsec,
|
||||||
|
pinNumDigits, n3dsCpuStr,
|
||||||
|
|
||||||
|
cfg->hbldr3dsxTitleId, rosalinaMenuComboStr,
|
||||||
|
(int)cfg->screenFiltersCct, (int)cfg->ntpTzOffetMinutes,
|
||||||
|
|
||||||
|
(int)CONFIG(PATCHUNITINFO), (int)CONFIG(DISABLEARM11EXCHANDLERS),
|
||||||
|
(int)CONFIG(ENABLESAFEFIRMROSALINA)
|
||||||
|
);
|
||||||
|
|
||||||
|
return n < 0 ? 0 : (size_t)n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char tmpIniBuffer[0x2000];
|
||||||
|
|
||||||
|
static bool readLumaIniConfig(void)
|
||||||
|
{
|
||||||
|
u32 rd = fileRead(tmpIniBuffer, "config.ini", sizeof(tmpIniBuffer) - 1);
|
||||||
|
if (rd == 0) return false;
|
||||||
|
|
||||||
|
tmpIniBuffer[rd] = '\0';
|
||||||
|
|
||||||
|
return ini_parse_string(tmpIniBuffer, &configIniHandler, &configData) >= 0 && !hasIniParseError;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool writeLumaIniConfig(void)
|
||||||
|
{
|
||||||
|
size_t n = saveLumaIniConfigToStr(tmpIniBuffer);
|
||||||
|
return n != 0 && fileWrite(tmpIniBuffer, "config.ini", n);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===========================================================
|
||||||
|
|
||||||
static void writeConfigMcu(void)
|
static void writeConfigMcu(void)
|
||||||
{
|
{
|
||||||
u8 data[sizeof(CfgDataMcu)];
|
u8 data[sizeof(CfgDataMcu)];
|
||||||
@ -113,12 +514,19 @@ bool readConfig(void)
|
|||||||
if (!ret)
|
if (!ret)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if(fileRead(&configData, CONFIG_FILE, sizeof(CfgData)) != sizeof(CfgData) ||
|
ret = readLumaIniConfig();
|
||||||
memcmp(configData.magic, "CONF", 4) != 0 ||
|
if(!ret ||
|
||||||
configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
|
configData.formatVersionMajor != CONFIG_VERSIONMAJOR ||
|
||||||
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
|
configData.formatVersionMinor != CONFIG_VERSIONMINOR)
|
||||||
{
|
{
|
||||||
memset(&configData, 0, sizeof(CfgData));
|
memset(&configData, 0, sizeof(CfgData));
|
||||||
|
configData.formatVersionMajor = CONFIG_VERSIONMAJOR;
|
||||||
|
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
|
||||||
|
configData.config |= 1 << PATCHGAMES;
|
||||||
|
configData.splashDurationMsec = 3000;
|
||||||
|
configData.hbldr3dsxTitleId = 0x000400000D921E00ull;
|
||||||
|
configData.rosalinaMenuCombo = 1u << 9 | 1u << 7 | 1u << 2; // L+Start+Select
|
||||||
|
configData.screenFiltersCct = 6500; // default temp, no-op
|
||||||
ret = false;
|
ret = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -137,17 +545,11 @@ void writeConfig(bool isConfigOptions)
|
|||||||
(!isConfigOptions && configData.bootConfig == oldConfig.bootConfig))) return;
|
(!isConfigOptions && configData.bootConfig == oldConfig.bootConfig))) return;
|
||||||
|
|
||||||
if(needConfig == CREATE_CONFIGURATION)
|
if(needConfig == CREATE_CONFIGURATION)
|
||||||
{
|
|
||||||
memcpy(configData.magic, "CONF", 4);
|
|
||||||
configData.formatVersionMajor = CONFIG_VERSIONMAJOR;
|
|
||||||
configData.formatVersionMinor = CONFIG_VERSIONMINOR;
|
|
||||||
|
|
||||||
needConfig = MODIFY_CONFIGURATION;
|
needConfig = MODIFY_CONFIGURATION;
|
||||||
}
|
|
||||||
|
|
||||||
if (!isConfigOptions)
|
if (!isConfigOptions)
|
||||||
writeConfigMcu();
|
writeConfigMcu();
|
||||||
else if(!fileWrite(&configData, CONFIG_FILE, sizeof(CfgData)))
|
else if(!writeLumaIniConfig())
|
||||||
error("Error writing the configuration file");
|
error("Error writing the configuration file");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -156,7 +558,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
static const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )",
|
static const char *multiOptionsText[] = { "Default EmuNAND: 1( ) 2( ) 3( ) 4( )",
|
||||||
"Screen brightness: 4( ) 3( ) 2( ) 1( )",
|
"Screen brightness: 4( ) 3( ) 2( ) 1( )",
|
||||||
"Splash: Off( ) Before( ) After( ) payloads",
|
"Splash: Off( ) Before( ) After( ) payloads",
|
||||||
"Splash duration: 1( ) 3( ) 5( ) 7( ) seconds",
|
|
||||||
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
|
"PIN lock: Off( ) 4( ) 6( ) 8( ) digits",
|
||||||
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
|
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )",
|
||||||
};
|
};
|
||||||
@ -167,9 +568,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
"( ) Enable game patching",
|
"( ) Enable game patching",
|
||||||
"( ) Show NAND or user string in System Settings",
|
"( ) Show NAND or user string in System Settings",
|
||||||
"( ) Show GBA boot screen in patched AGB_FIRM",
|
"( ) Show GBA boot screen in patched AGB_FIRM",
|
||||||
"( ) Set developer UNITINFO",
|
|
||||||
"( ) Disable Arm11 exception handlers",
|
|
||||||
"( ) Enable Rosalina on SAFE_FIRM",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
static const char *optionsDescription[] = { "Select the default EmuNAND.\n\n"
|
||||||
@ -184,12 +582,9 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
"(intended for splashes that display\n"
|
"(intended for splashes that display\n"
|
||||||
"button hints).\n\n"
|
"button hints).\n\n"
|
||||||
"\t* 'After payloads' displays it\n"
|
"\t* 'After payloads' displays it\n"
|
||||||
"afterwards.",
|
"afterwards.\n\n"
|
||||||
|
"Edit the duration in config.ini (3s\n"
|
||||||
"Select how long the splash screen\n"
|
"default).",
|
||||||
"displays.\n\n"
|
|
||||||
"This has no effect if the splash\n"
|
|
||||||
"screen is not enabled.",
|
|
||||||
|
|
||||||
"Activate a PIN lock.\n\n"
|
"Activate a PIN lock.\n\n"
|
||||||
"The PIN will be asked each time\n"
|
"The PIN will be asked each time\n"
|
||||||
@ -254,30 +649,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
|
|
||||||
"Enable showing the GBA boot screen\n"
|
"Enable showing the GBA boot screen\n"
|
||||||
"when booting GBA games.",
|
"when booting GBA games.",
|
||||||
|
|
||||||
"Make the console be always detected\n"
|
|
||||||
"as a development unit, and conversely.\n"
|
|
||||||
"(which breaks online features, amiibo\n"
|
|
||||||
"and retail CIAs, but allows installing\n"
|
|
||||||
"and booting some developer software).\n\n"
|
|
||||||
"Only select this if you know what you\n"
|
|
||||||
"are doing!",
|
|
||||||
|
|
||||||
"Disables the fatal error exception\n"
|
|
||||||
"handlers for the Arm11 CPU.\n\n"
|
|
||||||
"Note: Disabling the exception handlers\n"
|
|
||||||
"will disqualify you from submitting\n"
|
|
||||||
"issues or bug reports to the Luma3DS\n"
|
|
||||||
"GitHub repository!",
|
|
||||||
|
|
||||||
"Enables Rosalina, the kernel ext.\n"
|
|
||||||
"and sysmodule reimplementations on\n"
|
|
||||||
"SAFE_FIRM (New 3DS only).\n\n"
|
|
||||||
"Also suppresses QTM error 0xF96183FE,\n"
|
|
||||||
"allowing to use 8.1-11.3 N3DS on\n"
|
|
||||||
"New 2DS XL consoles.\n\n"
|
|
||||||
"Only select this if you know what you\n"
|
|
||||||
"are doing!",
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FirmwareSource nandType = FIRMWARE_SYSNAND;
|
FirmwareSource nandType = FIRMWARE_SYSNAND;
|
||||||
@ -297,7 +668,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
|
||||||
{ .visible = ISN3DS },
|
{ .visible = ISN3DS },
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -312,9 +682,6 @@ void configMenu(bool oldPinStatus, u32 oldPinMode)
|
|||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
{ .visible = true },
|
||||||
{ .visible = true },
|
|
||||||
{ .visible = true },
|
|
||||||
{ .visible = ISN3DS },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//Calculate the amount of the various kinds of options and pre-select the first single one
|
//Calculate the amount of the various kinds of options and pre-select the first single one
|
||||||
|
@ -33,8 +33,8 @@
|
|||||||
#define BOOTCONFIG(a, b) ((configData.bootConfig >> (a)) & (b))
|
#define BOOTCONFIG(a, b) ((configData.bootConfig >> (a)) & (b))
|
||||||
|
|
||||||
#define CONFIG_FILE "config.bin"
|
#define CONFIG_FILE "config.bin"
|
||||||
#define CONFIG_VERSIONMAJOR 2
|
#define CONFIG_VERSIONMAJOR 3
|
||||||
#define CONFIG_VERSIONMINOR 5
|
#define CONFIG_VERSIONMINOR 0
|
||||||
|
|
||||||
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
#define BOOTCFG_NAND BOOTCONFIG(0, 7)
|
||||||
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
#define BOOTCFG_FIRM BOOTCONFIG(3, 7)
|
||||||
@ -46,7 +46,6 @@ enum multiOptions
|
|||||||
DEFAULTEMU = 0,
|
DEFAULTEMU = 0,
|
||||||
BRIGHTNESS,
|
BRIGHTNESS,
|
||||||
SPLASH,
|
SPLASH,
|
||||||
SPLASH_DURATION,
|
|
||||||
PIN,
|
PIN,
|
||||||
NEWCPU
|
NEWCPU
|
||||||
};
|
};
|
||||||
|
@ -58,8 +58,7 @@ bool loadSplash(void)
|
|||||||
|
|
||||||
swapFramebuffers(true);
|
swapFramebuffers(true);
|
||||||
|
|
||||||
u32 durationIndex = MULTICONFIG(SPLASH_DURATION);
|
wait(configData.splashDurationMsec);
|
||||||
wait(1000ULL + (durationIndex * 2000ULL));
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -447,5 +447,9 @@ bool doLumaUpgradeProcess(void)
|
|||||||
// Try to backup essential files
|
// Try to backup essential files
|
||||||
ok2 = backupEssentialFiles();
|
ok2 = backupEssentialFiles();
|
||||||
|
|
||||||
|
// Clean up some of the old files
|
||||||
|
fileDelete("0:/luma/config.bin");
|
||||||
|
fileDelete("1:/rw/luma/config.bin");
|
||||||
|
|
||||||
return ok && ok2;
|
return ok && ok2;
|
||||||
}
|
}
|
||||||
|
298
arm9/source/ini.c
Normal file
298
arm9/source/ini.c
Normal file
@ -0,0 +1,298 @@
|
|||||||
|
/* inih -- simple .INI file parser
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
Copyright (C) 2009-2020, Ben Hoyt
|
||||||
|
|
||||||
|
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||||
|
home page for more info:
|
||||||
|
|
||||||
|
https://github.com/benhoyt/inih
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "ini.h"
|
||||||
|
|
||||||
|
#if !INI_USE_STACK
|
||||||
|
#if INI_CUSTOM_ALLOCATOR
|
||||||
|
#include <stddef.h>
|
||||||
|
void* ini_malloc(size_t size);
|
||||||
|
void ini_free(void* ptr);
|
||||||
|
void* ini_realloc(void* ptr, size_t size);
|
||||||
|
#else
|
||||||
|
#include <stdlib.h>
|
||||||
|
#define ini_malloc malloc
|
||||||
|
#define ini_free free
|
||||||
|
#define ini_realloc realloc
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define MAX_SECTION 50
|
||||||
|
#define MAX_NAME 50
|
||||||
|
|
||||||
|
/* Used by ini_parse_string() to keep track of string parsing state. */
|
||||||
|
typedef struct {
|
||||||
|
const char* ptr;
|
||||||
|
size_t num_left;
|
||||||
|
} ini_parse_string_ctx;
|
||||||
|
|
||||||
|
/* Strip whitespace chars off end of given string, in place. Return s. */
|
||||||
|
static char* rstrip(char* s)
|
||||||
|
{
|
||||||
|
char* p = s + strlen(s);
|
||||||
|
while (p > s && isspace((unsigned char)(*--p)))
|
||||||
|
*p = '\0';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return pointer to first non-whitespace char in given string. */
|
||||||
|
static char* lskip(const char* s)
|
||||||
|
{
|
||||||
|
while (*s && isspace((unsigned char)(*s)))
|
||||||
|
s++;
|
||||||
|
return (char*)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return pointer to first char (of chars) or inline comment in given string,
|
||||||
|
or pointer to NUL at end of string if neither found. Inline comment must
|
||||||
|
be prefixed by a whitespace character to register as a comment. */
|
||||||
|
static char* find_chars_or_comment(const char* s, const char* chars)
|
||||||
|
{
|
||||||
|
#if INI_ALLOW_INLINE_COMMENTS
|
||||||
|
int was_space = 0;
|
||||||
|
while (*s && (!chars || !strchr(chars, *s)) &&
|
||||||
|
!(was_space && strchr(INI_INLINE_COMMENT_PREFIXES, *s))) {
|
||||||
|
was_space = isspace((unsigned char)(*s));
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
while (*s && (!chars || !strchr(chars, *s))) {
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (char*)s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Similar to strncpy, but ensures dest (size bytes) is
|
||||||
|
NUL-terminated, and doesn't pad with NULs. */
|
||||||
|
static char* strncpy0(char* dest, const char* src, size_t size)
|
||||||
|
{
|
||||||
|
/* Could use strncpy internally, but it causes gcc warnings (see issue #91) */
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < size - 1 && src[i]; i++)
|
||||||
|
dest[i] = src[i];
|
||||||
|
dest[i] = '\0';
|
||||||
|
return dest;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See documentation in header file. */
|
||||||
|
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||||
|
void* user)
|
||||||
|
{
|
||||||
|
/* Uses a fair bit of stack (use heap instead if you need to) */
|
||||||
|
#if INI_USE_STACK
|
||||||
|
char line[INI_MAX_LINE];
|
||||||
|
int max_line = INI_MAX_LINE;
|
||||||
|
#else
|
||||||
|
char* line;
|
||||||
|
size_t max_line = INI_INITIAL_ALLOC;
|
||||||
|
#endif
|
||||||
|
#if INI_ALLOW_REALLOC && !INI_USE_STACK
|
||||||
|
char* new_line;
|
||||||
|
size_t offset;
|
||||||
|
#endif
|
||||||
|
char section[MAX_SECTION] = "";
|
||||||
|
char prev_name[MAX_NAME] = "";
|
||||||
|
|
||||||
|
char* start;
|
||||||
|
char* end;
|
||||||
|
char* name;
|
||||||
|
char* value;
|
||||||
|
int lineno = 0;
|
||||||
|
int error = 0;
|
||||||
|
|
||||||
|
#if !INI_USE_STACK
|
||||||
|
line = (char*)ini_malloc(INI_INITIAL_ALLOC);
|
||||||
|
if (!line) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if INI_HANDLER_LINENO
|
||||||
|
#define HANDLER(u, s, n, v) handler(u, s, n, v, lineno)
|
||||||
|
#else
|
||||||
|
#define HANDLER(u, s, n, v) handler(u, s, n, v)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Scan through stream line by line */
|
||||||
|
while (reader(line, (int)max_line, stream) != NULL) {
|
||||||
|
#if INI_ALLOW_REALLOC && !INI_USE_STACK
|
||||||
|
offset = strlen(line);
|
||||||
|
while (offset == max_line - 1 && line[offset - 1] != '\n') {
|
||||||
|
max_line *= 2;
|
||||||
|
if (max_line > INI_MAX_LINE)
|
||||||
|
max_line = INI_MAX_LINE;
|
||||||
|
new_line = ini_realloc(line, max_line);
|
||||||
|
if (!new_line) {
|
||||||
|
ini_free(line);
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
line = new_line;
|
||||||
|
if (reader(line + offset, (int)(max_line - offset), stream) == NULL)
|
||||||
|
break;
|
||||||
|
if (max_line >= INI_MAX_LINE)
|
||||||
|
break;
|
||||||
|
offset += strlen(line + offset);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
lineno++;
|
||||||
|
|
||||||
|
start = line;
|
||||||
|
#if INI_ALLOW_BOM
|
||||||
|
if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
|
||||||
|
(unsigned char)start[1] == 0xBB &&
|
||||||
|
(unsigned char)start[2] == 0xBF) {
|
||||||
|
start += 3;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
start = lskip(rstrip(start));
|
||||||
|
|
||||||
|
if (strchr(INI_START_COMMENT_PREFIXES, *start)) {
|
||||||
|
/* Start-of-line comment */
|
||||||
|
}
|
||||||
|
#if INI_ALLOW_MULTILINE
|
||||||
|
else if (*prev_name && *start && start > line) {
|
||||||
|
/* Non-blank line with leading whitespace, treat as continuation
|
||||||
|
of previous name's value (as per Python configparser). */
|
||||||
|
if (!HANDLER(user, section, prev_name, start) && !error)
|
||||||
|
error = lineno;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
else if (*start == '[') {
|
||||||
|
/* A "[section]" line */
|
||||||
|
end = find_chars_or_comment(start + 1, "]");
|
||||||
|
if (*end == ']') {
|
||||||
|
*end = '\0';
|
||||||
|
strncpy0(section, start + 1, sizeof(section));
|
||||||
|
*prev_name = '\0';
|
||||||
|
#if INI_CALL_HANDLER_ON_NEW_SECTION
|
||||||
|
if (!HANDLER(user, section, NULL, NULL) && !error)
|
||||||
|
error = lineno;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else if (!error) {
|
||||||
|
/* No ']' found on section line */
|
||||||
|
error = lineno;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (*start) {
|
||||||
|
/* Not a comment, must be a name[=:]value pair */
|
||||||
|
end = find_chars_or_comment(start, "=:");
|
||||||
|
if (*end == '=' || *end == ':') {
|
||||||
|
*end = '\0';
|
||||||
|
name = rstrip(start);
|
||||||
|
value = end + 1;
|
||||||
|
#if INI_ALLOW_INLINE_COMMENTS
|
||||||
|
end = find_chars_or_comment(value, NULL);
|
||||||
|
if (*end)
|
||||||
|
*end = '\0';
|
||||||
|
#endif
|
||||||
|
value = lskip(value);
|
||||||
|
rstrip(value);
|
||||||
|
|
||||||
|
/* Valid name[=:]value pair found, call handler */
|
||||||
|
strncpy0(prev_name, name, sizeof(prev_name));
|
||||||
|
if (!HANDLER(user, section, name, value) && !error)
|
||||||
|
error = lineno;
|
||||||
|
}
|
||||||
|
else if (!error) {
|
||||||
|
/* No '=' or ':' found on name[=:]value line */
|
||||||
|
#if INI_ALLOW_NO_VALUE
|
||||||
|
*end = '\0';
|
||||||
|
name = rstrip(start);
|
||||||
|
if (!HANDLER(user, section, name, NULL) && !error)
|
||||||
|
error = lineno;
|
||||||
|
#else
|
||||||
|
error = lineno;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if INI_STOP_ON_FIRST_ERROR
|
||||||
|
if (error)
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if !INI_USE_STACK
|
||||||
|
ini_free(line);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See documentation in header file. */
|
||||||
|
int ini_parse_file(FILE* file, ini_handler handler, void* user)
|
||||||
|
{
|
||||||
|
return ini_parse_stream((ini_reader)fgets, file, handler, user);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See documentation in header file. */
|
||||||
|
int ini_parse(const char* filename, ini_handler handler, void* user)
|
||||||
|
{
|
||||||
|
FILE* file;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
file = fopen(filename, "r");
|
||||||
|
if (!file)
|
||||||
|
return -1;
|
||||||
|
error = ini_parse_file(file, handler, user);
|
||||||
|
fclose(file);
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* An ini_reader function to read the next line from a string buffer. This
|
||||||
|
is the fgets() equivalent used by ini_parse_string(). */
|
||||||
|
static char* ini_reader_string(char* str, int num, void* stream) {
|
||||||
|
ini_parse_string_ctx* ctx = (ini_parse_string_ctx*)stream;
|
||||||
|
const char* ctx_ptr = ctx->ptr;
|
||||||
|
size_t ctx_num_left = ctx->num_left;
|
||||||
|
char* strp = str;
|
||||||
|
char c;
|
||||||
|
|
||||||
|
if (ctx_num_left == 0 || num < 2)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
while (num > 1 && ctx_num_left != 0) {
|
||||||
|
c = *ctx_ptr++;
|
||||||
|
ctx_num_left--;
|
||||||
|
*strp++ = c;
|
||||||
|
if (c == '\n')
|
||||||
|
break;
|
||||||
|
num--;
|
||||||
|
}
|
||||||
|
|
||||||
|
*strp = '\0';
|
||||||
|
ctx->ptr = ctx_ptr;
|
||||||
|
ctx->num_left = ctx_num_left;
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* See documentation in header file. */
|
||||||
|
int ini_parse_string(const char* string, ini_handler handler, void* user) {
|
||||||
|
ini_parse_string_ctx ctx;
|
||||||
|
|
||||||
|
ctx.ptr = string;
|
||||||
|
ctx.num_left = strlen(string);
|
||||||
|
return ini_parse_stream((ini_reader)ini_reader_string, &ctx, handler,
|
||||||
|
user);
|
||||||
|
}
|
157
arm9/source/ini.h
Normal file
157
arm9/source/ini.h
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
/* inih -- simple .INI file parser
|
||||||
|
|
||||||
|
SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
|
||||||
|
Copyright (C) 2009-2020, Ben Hoyt
|
||||||
|
|
||||||
|
inih is released under the New BSD license (see LICENSE.txt). Go to the project
|
||||||
|
home page for more info:
|
||||||
|
|
||||||
|
https://github.com/benhoyt/inih
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INI_H
|
||||||
|
#define INI_H
|
||||||
|
|
||||||
|
/* Make this header file easier to include in C++ code */
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* Nonzero if ini_handler callback should accept lineno parameter. */
|
||||||
|
#ifndef INI_HANDLER_LINENO
|
||||||
|
#define INI_HANDLER_LINENO 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Typedef for prototype of handler function. */
|
||||||
|
#if INI_HANDLER_LINENO
|
||||||
|
typedef int (*ini_handler)(void* user, const char* section,
|
||||||
|
const char* name, const char* value,
|
||||||
|
int lineno);
|
||||||
|
#else
|
||||||
|
typedef int (*ini_handler)(void* user, const char* section,
|
||||||
|
const char* name, const char* value);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Typedef for prototype of fgets-style reader function. */
|
||||||
|
typedef char* (*ini_reader)(char* str, int num, void* stream);
|
||||||
|
|
||||||
|
/* Parse given INI-style file. May have [section]s, name=value pairs
|
||||||
|
(whitespace stripped), and comments starting with ';' (semicolon). Section
|
||||||
|
is "" if name=value pair parsed before any section heading. name:value
|
||||||
|
pairs are also supported as a concession to Python's configparser.
|
||||||
|
|
||||||
|
For each name=value pair parsed, call handler function with given user
|
||||||
|
pointer as well as section, name, and value (data only valid for duration
|
||||||
|
of handler call). Handler should return nonzero on success, zero on error.
|
||||||
|
|
||||||
|
Returns 0 on success, line number of first error on parse error (doesn't
|
||||||
|
stop on first error), -1 on file open error, or -2 on memory allocation
|
||||||
|
error (only when INI_USE_STACK is zero).
|
||||||
|
*/
|
||||||
|
int ini_parse(const char* filename, ini_handler handler, void* user);
|
||||||
|
|
||||||
|
/* Same as ini_parse(), but takes a FILE* instead of filename. This doesn't
|
||||||
|
close the file when it's finished -- the caller must do that. */
|
||||||
|
int ini_parse_file(FILE* file, ini_handler handler, void* user);
|
||||||
|
|
||||||
|
/* Same as ini_parse(), but takes an ini_reader function pointer instead of
|
||||||
|
filename. Used for implementing custom or string-based I/O (see also
|
||||||
|
ini_parse_string). */
|
||||||
|
int ini_parse_stream(ini_reader reader, void* stream, ini_handler handler,
|
||||||
|
void* user);
|
||||||
|
|
||||||
|
/* Same as ini_parse(), but takes a zero-terminated string with the INI data
|
||||||
|
instead of a file. Useful for parsing INI data from a network socket or
|
||||||
|
already in memory. */
|
||||||
|
int ini_parse_string(const char* string, ini_handler handler, void* user);
|
||||||
|
|
||||||
|
/* Nonzero to allow multi-line value parsing, in the style of Python's
|
||||||
|
configparser. If allowed, ini_parse() will call the handler with the same
|
||||||
|
name for each subsequent line parsed. */
|
||||||
|
#ifndef INI_ALLOW_MULTILINE
|
||||||
|
#define INI_ALLOW_MULTILINE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Nonzero to allow a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of
|
||||||
|
the file. See https://github.com/benhoyt/inih/issues/21 */
|
||||||
|
#ifndef INI_ALLOW_BOM
|
||||||
|
#define INI_ALLOW_BOM 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Chars that begin a start-of-line comment. Per Python configparser, allow
|
||||||
|
both ; and # comments at the start of a line by default. */
|
||||||
|
#ifndef INI_START_COMMENT_PREFIXES
|
||||||
|
#define INI_START_COMMENT_PREFIXES ";#"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Nonzero to allow inline comments (with valid inline comment characters
|
||||||
|
specified by INI_INLINE_COMMENT_PREFIXES). Set to 0 to turn off and match
|
||||||
|
Python 3.2+ configparser behaviour. */
|
||||||
|
#ifndef INI_ALLOW_INLINE_COMMENTS
|
||||||
|
#define INI_ALLOW_INLINE_COMMENTS 1
|
||||||
|
#endif
|
||||||
|
#ifndef INI_INLINE_COMMENT_PREFIXES
|
||||||
|
#define INI_INLINE_COMMENT_PREFIXES ";"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Nonzero to use stack for line buffer, zero to use heap (malloc/free). */
|
||||||
|
#ifndef INI_USE_STACK
|
||||||
|
#define INI_USE_STACK 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Maximum line length for any line in INI file (stack or heap). Note that
|
||||||
|
this must be 3 more than the longest line (due to '\r', '\n', and '\0'). */
|
||||||
|
#ifndef INI_MAX_LINE
|
||||||
|
#define INI_MAX_LINE 200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Nonzero to allow heap line buffer to grow via realloc(), zero for a
|
||||||
|
fixed-size buffer of INI_MAX_LINE bytes. Only applies if INI_USE_STACK is
|
||||||
|
zero. */
|
||||||
|
#ifndef INI_ALLOW_REALLOC
|
||||||
|
#define INI_ALLOW_REALLOC 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Initial size in bytes for heap line buffer. Only applies if INI_USE_STACK
|
||||||
|
is zero. */
|
||||||
|
#ifndef INI_INITIAL_ALLOC
|
||||||
|
#define INI_INITIAL_ALLOC 200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Stop parsing on first error (default is to keep parsing). */
|
||||||
|
#ifndef INI_STOP_ON_FIRST_ERROR
|
||||||
|
#define INI_STOP_ON_FIRST_ERROR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Nonzero to call the handler at the start of each new section (with
|
||||||
|
name and value NULL). Default is to only call the handler on
|
||||||
|
each name=value pair. */
|
||||||
|
#ifndef INI_CALL_HANDLER_ON_NEW_SECTION
|
||||||
|
#define INI_CALL_HANDLER_ON_NEW_SECTION 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Nonzero to allow a name without a value (no '=' or ':' on the line) and
|
||||||
|
call the handler with value NULL in this case. Default is to treat
|
||||||
|
no-value lines as an error. */
|
||||||
|
#ifndef INI_ALLOW_NO_VALUE
|
||||||
|
#define INI_ALLOW_NO_VALUE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Nonzero to use custom ini_malloc, ini_free, and ini_realloc memory
|
||||||
|
allocation functions (INI_USE_STACK must also be 0). These functions must
|
||||||
|
have the same signatures as malloc/free/realloc and behave in a similar
|
||||||
|
way. ini_realloc is only needed if INI_ALLOW_REALLOC is set. */
|
||||||
|
#ifndef INI_CUSTOM_ALLOCATOR
|
||||||
|
#define INI_CUSTOM_ALLOCATOR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* INI_H */
|
@ -129,8 +129,11 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
|
|||||||
|
|
||||||
u16 configFormatVersionMajor, configFormatVersionMinor;
|
u16 configFormatVersionMajor, configFormatVersionMinor;
|
||||||
u32 config, multiConfig, bootConfig;
|
u32 config, multiConfig, bootConfig;
|
||||||
|
u32 splashDurationMsec;
|
||||||
u64 hbldr3dsxTitleId;
|
u64 hbldr3dsxTitleId;
|
||||||
u32 rosalinaMenuCombo;
|
u32 rosalinaMenuCombo;
|
||||||
|
u16 screenFiltersCct;
|
||||||
|
s16 ntpTzOffetMinutes;
|
||||||
} info;
|
} info;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -201,8 +204,11 @@ u32 installK11Extension(u8 *pos, u32 size, bool needToInitSd, u32 baseK11VA, u32
|
|||||||
info->config = configData.config;
|
info->config = configData.config;
|
||||||
info->multiConfig = configData.multiConfig;
|
info->multiConfig = configData.multiConfig;
|
||||||
info->bootConfig = configData.bootConfig;
|
info->bootConfig = configData.bootConfig;
|
||||||
|
info->splashDurationMsec = configData.splashDurationMsec;
|
||||||
info->hbldr3dsxTitleId = configData.hbldr3dsxTitleId;
|
info->hbldr3dsxTitleId = configData.hbldr3dsxTitleId;
|
||||||
info->rosalinaMenuCombo = configData.rosalinaMenuCombo;
|
info->rosalinaMenuCombo = configData.rosalinaMenuCombo;
|
||||||
|
info->screenFiltersCct = configData.screenFiltersCct;
|
||||||
|
info->ntpTzOffetMinutes = configData.ntpTzOffetMinutes;
|
||||||
info->versionMajor = VERSION_MAJOR;
|
info->versionMajor = VERSION_MAJOR;
|
||||||
info->versionMinor = VERSION_MINOR;
|
info->versionMinor = VERSION_MINOR;
|
||||||
info->versionBuild = VERSION_BUILD;
|
info->versionBuild = VERSION_BUILD;
|
||||||
|
@ -61,14 +61,16 @@ typedef volatile s64 vs64;
|
|||||||
#define ISN3DS (CFG11_SOCINFO & 2)
|
#define ISN3DS (CFG11_SOCINFO & 2)
|
||||||
#define ISDEVUNIT (CFG_UNITINFO != 0)
|
#define ISDEVUNIT (CFG_UNITINFO != 0)
|
||||||
|
|
||||||
typedef struct __attribute__((packed, aligned(4)))
|
typedef struct {
|
||||||
{
|
|
||||||
char magic[4];
|
|
||||||
u16 formatVersionMajor, formatVersionMinor;
|
u16 formatVersionMajor, formatVersionMinor;
|
||||||
|
|
||||||
u32 config, multiConfig, bootConfig;
|
u32 config, multiConfig, bootConfig;
|
||||||
|
u32 splashDurationMsec;
|
||||||
|
|
||||||
u64 hbldr3dsxTitleId;
|
u64 hbldr3dsxTitleId;
|
||||||
u32 rosalinaMenuCombo;
|
u32 rosalinaMenuCombo;
|
||||||
|
u16 screenFiltersCct;
|
||||||
|
s16 ntpTzOffetMinutes;
|
||||||
} CfgData;
|
} CfgData;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
|
@ -19,7 +19,6 @@ enum multiOptions
|
|||||||
DEFAULTEMU = 0,
|
DEFAULTEMU = 0,
|
||||||
BRIGHTNESS,
|
BRIGHTNESS,
|
||||||
SPLASH,
|
SPLASH,
|
||||||
SPLASH_DURATION,
|
|
||||||
PIN,
|
PIN,
|
||||||
NEWCPU
|
NEWCPU
|
||||||
};
|
};
|
||||||
|
@ -127,8 +127,11 @@ typedef struct CfwInfo
|
|||||||
|
|
||||||
u16 configFormatVersionMajor, configFormatVersionMinor;
|
u16 configFormatVersionMajor, configFormatVersionMinor;
|
||||||
u32 config, multiConfig, bootConfig;
|
u32 config, multiConfig, bootConfig;
|
||||||
|
u32 splashDurationMsec;
|
||||||
u64 hbldr3dsxTitleId;
|
u64 hbldr3dsxTitleId;
|
||||||
u32 rosalinaMenuCombo;
|
u32 rosalinaMenuCombo;
|
||||||
|
u16 screenFiltersCct;
|
||||||
|
s16 ntpTzOffetMinutes;
|
||||||
} CfwInfo;
|
} CfwInfo;
|
||||||
|
|
||||||
extern CfwInfo cfwInfo;
|
extern CfwInfo cfwInfo;
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Luma3DS
|
|
||||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
|
||||||
* * Requiring preservation of specified reasonable legal notices or
|
|
||||||
* author attributions in that material or in the Appropriate Legal
|
|
||||||
* Notices displayed by works containing it.
|
|
||||||
* * Prohibiting misrepresentation of the origin of that material,
|
|
||||||
* or requiring that modified versions of such material be marked in
|
|
||||||
* reasonable ways as different from the original version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
#include "kernel.h"
|
|
||||||
#include "svc.h"
|
|
||||||
#include "globals.h"
|
|
||||||
|
|
||||||
// DEPRECATED
|
|
||||||
Result GetCFWInfo(CfwInfo *out);
|
|
@ -32,7 +32,6 @@
|
|||||||
#include "svc/GetSystemInfo.h"
|
#include "svc/GetSystemInfo.h"
|
||||||
#include "svc/GetProcessInfo.h"
|
#include "svc/GetProcessInfo.h"
|
||||||
#include "svc/GetThreadInfo.h"
|
#include "svc/GetThreadInfo.h"
|
||||||
#include "svc/GetCFWInfo.h"
|
|
||||||
#include "svc/ConnectToPort.h"
|
#include "svc/ConnectToPort.h"
|
||||||
#include "svc/SendSyncRequest.h"
|
#include "svc/SendSyncRequest.h"
|
||||||
#include "svc/Break.h"
|
#include "svc/Break.h"
|
||||||
@ -105,8 +104,6 @@ void *svcHook(u8 *pageEnd)
|
|||||||
return GetThreadInfoHookWrapper;
|
return GetThreadInfoHookWrapper;
|
||||||
case 0x2D:
|
case 0x2D:
|
||||||
return ConnectToPortHookWrapper;
|
return ConnectToPortHookWrapper;
|
||||||
case 0x2E:
|
|
||||||
return GetCFWInfo; // DEPRECATED
|
|
||||||
case 0x32:
|
case 0x32:
|
||||||
return SendSyncRequestHook;
|
return SendSyncRequestHook;
|
||||||
case 0x3C:
|
case 0x3C:
|
||||||
|
@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of Luma3DS
|
|
||||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
|
||||||
*
|
|
||||||
* This program is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This program is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
|
||||||
* * Requiring preservation of specified reasonable legal notices or
|
|
||||||
* author attributions in that material or in the Appropriate Legal
|
|
||||||
* Notices displayed by works containing it.
|
|
||||||
* * Prohibiting misrepresentation of the origin of that material,
|
|
||||||
* or requiring that modified versions of such material be marked in
|
|
||||||
* reasonable ways as different from the original version.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "svc/GetCFWInfo.h"
|
|
||||||
|
|
||||||
// DEPRECATED
|
|
||||||
Result GetCFWInfo(CfwInfo *out)
|
|
||||||
{
|
|
||||||
return kernelToUsrMemcpy8(out, &cfwInfo, 16) ? 0 : 0xE0E01BF5;
|
|
||||||
}
|
|
@ -57,6 +57,9 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
|
|||||||
case 5:
|
case 5:
|
||||||
*out = cfwInfo.bootConfig;
|
*out = cfwInfo.bootConfig;
|
||||||
break;
|
break;
|
||||||
|
case 6:
|
||||||
|
*out = cfwInfo.splashDurationMsec;
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x100:
|
case 0x100:
|
||||||
*out = (s64)cfwInfo.hbldr3dsxTitleId;
|
*out = (s64)cfwInfo.hbldr3dsxTitleId;
|
||||||
@ -64,6 +67,12 @@ Result GetSystemInfoHook(s64 *out, s32 type, s32 param)
|
|||||||
case 0x101:
|
case 0x101:
|
||||||
*out = cfwInfo.rosalinaMenuCombo;
|
*out = cfwInfo.rosalinaMenuCombo;
|
||||||
break;
|
break;
|
||||||
|
case 0x102:
|
||||||
|
*out = cfwInfo.screenFiltersCct;
|
||||||
|
break;
|
||||||
|
case 0x103:
|
||||||
|
*out = (s64)cfwInfo.ntpTzOffetMinutes;
|
||||||
|
break;
|
||||||
|
|
||||||
case 0x200: // isRelease
|
case 0x200: // isRelease
|
||||||
*out = cfwInfo.flags & 1;
|
*out = cfwInfo.flags & 1;
|
||||||
|
@ -21,7 +21,6 @@ enum multiOptions
|
|||||||
DEFAULTEMU = 0,
|
DEFAULTEMU = 0,
|
||||||
BRIGHTNESS,
|
BRIGHTNESS,
|
||||||
SPLASH,
|
SPLASH,
|
||||||
SPLASH_DURATION,
|
|
||||||
PIN,
|
PIN,
|
||||||
NEWCPU
|
NEWCPU
|
||||||
};
|
};
|
||||||
|
@ -19,7 +19,7 @@ include $(DEVKITARM)/3ds_rules
|
|||||||
TARGET := $(notdir $(CURDIR))
|
TARGET := $(notdir $(CURDIR))
|
||||||
BUILD := build
|
BUILD := build
|
||||||
SOURCES := source source/gdb source/menus source/redshift
|
SOURCES := source source/gdb source/menus source/redshift
|
||||||
DATA := source/gdb/xml
|
DATA := source/gdb/xml data
|
||||||
INCLUDES := include include/gdb include/menus include/redshift
|
INCLUDES := include include/gdb include/menus include/redshift
|
||||||
|
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@ -144,6 +144,11 @@ $(OFILES_SRC) : $(HFILES_BIN)
|
|||||||
@$(bin2o)
|
@$(bin2o)
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
%.xml.o %_xml.h: %.xml
|
%.xml.o %_xml.h: %.xml
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
@echo $(notdir $<)
|
||||||
|
@$(bin2o)
|
||||||
|
#---------------------------------------------------------------------------------
|
||||||
|
%.ini.o %_ini.h: %.ini
|
||||||
#---------------------------------------------------------------------------------
|
#---------------------------------------------------------------------------------
|
||||||
@echo $(notdir $<)
|
@echo $(notdir $<)
|
||||||
@$(bin2o)
|
@$(bin2o)
|
||||||
|
BIN
sysmodules/rosalina/data/config_template.ini
Normal file
BIN
sysmodules/rosalina/data/config_template.ini
Normal file
Binary file not shown.
@ -30,6 +30,7 @@
|
|||||||
#include "menu.h"
|
#include "menu.h"
|
||||||
|
|
||||||
extern Menu miscellaneousMenu;
|
extern Menu miscellaneousMenu;
|
||||||
|
extern int lastNtpTzOffset;
|
||||||
|
|
||||||
void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void);
|
void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void);
|
||||||
void MiscellaneousMenu_ChangeMenuCombo(void);
|
void MiscellaneousMenu_ChangeMenuCombo(void);
|
||||||
|
@ -32,6 +32,7 @@ extern Menu screenFiltersMenu;
|
|||||||
|
|
||||||
extern int screenFiltersCurrentTemperature;
|
extern int screenFiltersCurrentTemperature;
|
||||||
|
|
||||||
|
void ScreenFiltersMenu_SetCct(int cct);
|
||||||
void ScreenFiltersMenu_RestoreCct(void);
|
void ScreenFiltersMenu_RestoreCct(void);
|
||||||
|
|
||||||
void ScreenFiltersMenu_SetDefault(void); // 6500K (default)
|
void ScreenFiltersMenu_SetDefault(void); // 6500K (default)
|
||||||
|
@ -80,7 +80,6 @@ void initSystem(void)
|
|||||||
mappableInit(0x10000000, 0x14000000);
|
mappableInit(0x10000000, 0x14000000);
|
||||||
|
|
||||||
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
|
isN3DS = svcGetSystemInfo(&out, 0x10001, 0) == 0;
|
||||||
|
|
||||||
svcGetSystemInfo(&out, 0x10000, 0x100);
|
svcGetSystemInfo(&out, 0x10000, 0x100);
|
||||||
Luma_SharedConfig->hbldr_3dsx_tid = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out;
|
Luma_SharedConfig->hbldr_3dsx_tid = out == 0 ? HBLDR_DEFAULT_3DSX_TID : (u64)out;
|
||||||
Luma_SharedConfig->use_hbldr = true;
|
Luma_SharedConfig->use_hbldr = true;
|
||||||
@ -88,6 +87,9 @@ void initSystem(void)
|
|||||||
svcGetSystemInfo(&out, 0x10000, 0x101);
|
svcGetSystemInfo(&out, 0x10000, 0x101);
|
||||||
menuCombo = out == 0 ? DEFAULT_MENU_COMBO : (u32)out;
|
menuCombo = out == 0 ? DEFAULT_MENU_COMBO : (u32)out;
|
||||||
|
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 0x103);
|
||||||
|
lastNtpTzOffset = (s16)out;
|
||||||
|
|
||||||
miscellaneousMenu.items[0].title = Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ?
|
miscellaneousMenu.items[0].title = Luma_SharedConfig->hbldr_3dsx_tid == HBLDR_DEFAULT_3DSX_TID ?
|
||||||
"Switch the hb. title to the current app." :
|
"Switch the hb. title to the current app." :
|
||||||
"Switch the hb. title to hblauncher_loader";
|
"Switch the hb. title to hblauncher_loader";
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
#include "menus/n3ds.h"
|
#include "menus/n3ds.h"
|
||||||
#include "menus/cheats.h"
|
#include "menus/cheats.h"
|
||||||
#include "minisoc.h"
|
#include "minisoc.h"
|
||||||
|
#include "menus/screen_filters.h"
|
||||||
|
|
||||||
u32 menuCombo = 0;
|
u32 menuCombo = 0;
|
||||||
bool isHidInitialized = false;
|
bool isHidInitialized = false;
|
||||||
@ -143,7 +144,7 @@ u32 waitCombo(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static MyThread menuThread;
|
static MyThread menuThread;
|
||||||
static u8 ALIGN(8) menuThreadStack[0x1000];
|
static u8 ALIGN(8) menuThreadStack[0x3000];
|
||||||
|
|
||||||
static float batteryPercentage;
|
static float batteryPercentage;
|
||||||
static float batteryVoltage;
|
static float batteryVoltage;
|
||||||
@ -217,7 +218,7 @@ u32 menuCountItems(const Menu *menu)
|
|||||||
|
|
||||||
MyThread *menuCreateThread(void)
|
MyThread *menuCreateThread(void)
|
||||||
{
|
{
|
||||||
if(R_FAILED(MyThread_Create(&menuThread, menuThreadMain, menuThreadStack, 0x1000, 52, CORE_SYSTEM)))
|
if(R_FAILED(MyThread_Create(&menuThread, menuThreadMain, menuThreadStack, 0x3000, 52, CORE_SYSTEM)))
|
||||||
svcBreak(USERBREAK_PANIC);
|
svcBreak(USERBREAK_PANIC);
|
||||||
return &menuThread;
|
return &menuThread;
|
||||||
}
|
}
|
||||||
@ -230,6 +231,14 @@ void menuThreadMain(void)
|
|||||||
while (!isServiceUsable("ac:u") || !isServiceUsable("hid:USER"))
|
while (!isServiceUsable("ac:u") || !isServiceUsable("hid:USER"))
|
||||||
svcSleepThread(500 * 1000 * 1000LL);
|
svcSleepThread(500 * 1000 * 1000LL);
|
||||||
|
|
||||||
|
s64 out;
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 0x102);
|
||||||
|
screenFiltersCurrentTemperature = (int)(u32)out;
|
||||||
|
|
||||||
|
// Careful about race conditions here
|
||||||
|
if (screenFiltersCurrentTemperature != 6500)
|
||||||
|
ScreenFiltersMenu_SetCct(screenFiltersCurrentTemperature);
|
||||||
|
|
||||||
hidInit(); // assume this doesn't fail
|
hidInit(); // assume this doesn't fail
|
||||||
isHidInitialized = true;
|
isHidInitialized = true;
|
||||||
|
|
||||||
|
@ -37,7 +37,34 @@
|
|||||||
#include "ifile.h"
|
#include "ifile.h"
|
||||||
#include "pmdbgext.h"
|
#include "pmdbgext.h"
|
||||||
#include "process_patches.h"
|
#include "process_patches.h"
|
||||||
|
#include "screen_filters.h"
|
||||||
|
#include "config_template_ini.h"
|
||||||
|
|
||||||
|
#define CONFIG(a) (((cfg->config >> (a)) & 1) != 0)
|
||||||
|
#define MULTICONFIG(a) ((cfg->multiConfig >> (2 * (a))) & 3)
|
||||||
|
#define BOOTCONFIG(a, b) ((cfg->bootConfig >> (a)) & (b))
|
||||||
|
|
||||||
|
enum singleOptions
|
||||||
|
{
|
||||||
|
AUTOBOOTEMU = 0,
|
||||||
|
USEEMUFIRM,
|
||||||
|
LOADEXTFIRMSANDMODULES,
|
||||||
|
PATCHGAMES,
|
||||||
|
PATCHVERSTRING,
|
||||||
|
SHOWGBABOOT,
|
||||||
|
PATCHUNITINFO,
|
||||||
|
DISABLEARM11EXCHANDLERS,
|
||||||
|
ENABLESAFEFIRMROSALINA,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum multiOptions
|
||||||
|
{
|
||||||
|
DEFAULTEMU = 0,
|
||||||
|
BRIGHTNESS,
|
||||||
|
SPLASH,
|
||||||
|
PIN,
|
||||||
|
NEWCPU
|
||||||
|
};
|
||||||
typedef struct DspFirmSegmentHeader {
|
typedef struct DspFirmSegmentHeader {
|
||||||
u32 offset;
|
u32 offset;
|
||||||
u32 loadAddrHalfwords;
|
u32 loadAddrHalfwords;
|
||||||
@ -63,6 +90,18 @@ typedef struct DspFirm {
|
|||||||
u8 data[];
|
u8 data[];
|
||||||
} DspFirm;
|
} DspFirm;
|
||||||
|
|
||||||
|
typedef struct CfgData {
|
||||||
|
u16 formatVersionMajor, formatVersionMinor;
|
||||||
|
|
||||||
|
u32 config, multiConfig, bootConfig;
|
||||||
|
u32 splashDurationMsec;
|
||||||
|
|
||||||
|
u64 hbldr3dsxTitleId;
|
||||||
|
u32 rosalinaMenuCombo;
|
||||||
|
u16 screenFiltersCct;
|
||||||
|
s16 ntpTzOffetMinutes;
|
||||||
|
} CfgData;
|
||||||
|
|
||||||
Menu miscellaneousMenu = {
|
Menu miscellaneousMenu = {
|
||||||
"Miscellaneous options menu",
|
"Miscellaneous options menu",
|
||||||
{
|
{
|
||||||
@ -76,6 +115,7 @@ Menu miscellaneousMenu = {
|
|||||||
{},
|
{},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
int lastNtpTzOffset = 0;
|
||||||
|
|
||||||
void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
|
void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void)
|
||||||
{
|
{
|
||||||
@ -192,54 +232,130 @@ void MiscellaneousMenu_ChangeMenuCombo(void)
|
|||||||
while(!(waitInput() & KEY_B) && !menuShouldExit);
|
while(!(waitInput() & KEY_B) && !menuShouldExit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static size_t saveLumaIniConfigToStr(char *out, const CfgData *cfg)
|
||||||
|
{
|
||||||
|
char lumaVerStr[64];
|
||||||
|
char lumaRevSuffixStr[16];
|
||||||
|
char rosalinaMenuComboStr[128];
|
||||||
|
|
||||||
|
const char *splashPosStr;
|
||||||
|
const char *n3dsCpuStr;
|
||||||
|
|
||||||
|
s64 outInfo;
|
||||||
|
svcGetSystemInfo(&outInfo, 0x10000, 0);
|
||||||
|
u32 version = (u32)outInfo;
|
||||||
|
|
||||||
|
svcGetSystemInfo(&outInfo, 0x10000, 1);
|
||||||
|
u32 commitHash = (u32)outInfo;
|
||||||
|
|
||||||
|
svcGetSystemInfo(&outInfo, 0x10000, 0x200);
|
||||||
|
bool isRelease = (bool)outInfo;
|
||||||
|
|
||||||
|
switch (MULTICONFIG(SPLASH)) {
|
||||||
|
default: case 0: splashPosStr = "off"; break;
|
||||||
|
case 1: splashPosStr = "before payloads"; break;
|
||||||
|
case 2: splashPosStr = "after payloads"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (MULTICONFIG(NEWCPU)) {
|
||||||
|
default: case 0: n3dsCpuStr = "off"; break;
|
||||||
|
case 1: n3dsCpuStr = "clock"; break;
|
||||||
|
case 2: n3dsCpuStr = "l2"; break;
|
||||||
|
case 3: n3dsCpuStr = "clock+l2"; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GET_VERSION_REVISION(version) != 0) {
|
||||||
|
sprintf(lumaVerStr, "Luma3DS v%d.%d.%d", (int)GET_VERSION_MAJOR(version), (int)GET_VERSION_MINOR(version), (int)GET_VERSION_REVISION(version));
|
||||||
|
} else {
|
||||||
|
sprintf(lumaVerStr, "Luma3DS v%d.%d", (int)GET_VERSION_MAJOR(version), (int)GET_VERSION_MINOR(version));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isRelease) {
|
||||||
|
strcpy(lumaRevSuffixStr, "");
|
||||||
|
} else {
|
||||||
|
sprintf(lumaRevSuffixStr, "-%08lx", (u32)commitHash);
|
||||||
|
}
|
||||||
|
|
||||||
|
MiscellaneousMenu_ConvertComboToString(rosalinaMenuComboStr, cfg->rosalinaMenuCombo);
|
||||||
|
|
||||||
|
static const int pinOptionToDigits[] = { 0, 4, 6, 8 };
|
||||||
|
int pinNumDigits = pinOptionToDigits[MULTICONFIG(PIN)];
|
||||||
|
|
||||||
|
int n = sprintf(
|
||||||
|
out, (const char *)config_template_ini,
|
||||||
|
lumaVerStr, lumaRevSuffixStr,
|
||||||
|
|
||||||
|
(int)cfg->formatVersionMajor, (int)cfg->formatVersionMinor,
|
||||||
|
(int)CONFIG(AUTOBOOTEMU), (int)CONFIG(USEEMUFIRM),
|
||||||
|
(int)CONFIG(LOADEXTFIRMSANDMODULES), (int)CONFIG(PATCHGAMES),
|
||||||
|
(int)CONFIG(PATCHVERSTRING), (int)CONFIG(SHOWGBABOOT),
|
||||||
|
|
||||||
|
1 + (int)MULTICONFIG(DEFAULTEMU), 4 - (int)MULTICONFIG(BRIGHTNESS),
|
||||||
|
splashPosStr, (unsigned int)cfg->splashDurationMsec,
|
||||||
|
pinNumDigits, n3dsCpuStr,
|
||||||
|
|
||||||
|
cfg->hbldr3dsxTitleId, rosalinaMenuComboStr,
|
||||||
|
(int)cfg->screenFiltersCct, (int)cfg->ntpTzOffetMinutes,
|
||||||
|
|
||||||
|
(int)CONFIG(PATCHUNITINFO), (int)CONFIG(DISABLEARM11EXCHANDLERS),
|
||||||
|
(int)CONFIG(ENABLESAFEFIRMROSALINA)
|
||||||
|
);
|
||||||
|
|
||||||
|
return n < 0 ? 0 : (size_t)n;
|
||||||
|
}
|
||||||
|
|
||||||
void MiscellaneousMenu_SaveSettings(void)
|
void MiscellaneousMenu_SaveSettings(void)
|
||||||
{
|
{
|
||||||
|
char inibuf[0x2000];
|
||||||
|
|
||||||
Result res;
|
Result res;
|
||||||
|
|
||||||
IFile file;
|
IFile file;
|
||||||
u64 total;
|
u64 total;
|
||||||
|
|
||||||
struct PACKED ALIGN(4)
|
CfgData configData;
|
||||||
{
|
|
||||||
char magic[4];
|
|
||||||
u16 formatVersionMajor, formatVersionMinor;
|
|
||||||
|
|
||||||
u32 config, multiConfig, bootConfig;
|
|
||||||
u64 hbldr3dsxTitleId;
|
|
||||||
u32 rosalinaMenuCombo;
|
|
||||||
} configData;
|
|
||||||
|
|
||||||
u32 formatVersion;
|
u32 formatVersion;
|
||||||
u32 config, multiConfig, bootConfig;
|
u32 config, multiConfig, bootConfig;
|
||||||
|
u32 splashDurationMsec;
|
||||||
|
|
||||||
s64 out;
|
s64 out;
|
||||||
bool isSdMode;
|
bool isSdMode;
|
||||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 2))) svcBreak(USERBREAK_ASSERT);
|
svcGetSystemInfo(&out, 0x10000, 2);
|
||||||
formatVersion = (u32)out;
|
formatVersion = (u32)out;
|
||||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 3))) svcBreak(USERBREAK_ASSERT);
|
svcGetSystemInfo(&out, 0x10000, 3);
|
||||||
config = (u32)out;
|
config = (u32)out;
|
||||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 4))) svcBreak(USERBREAK_ASSERT);
|
svcGetSystemInfo(&out, 0x10000, 4);
|
||||||
multiConfig = (u32)out;
|
multiConfig = (u32)out;
|
||||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 5))) svcBreak(USERBREAK_ASSERT);
|
svcGetSystemInfo(&out, 0x10000, 5);
|
||||||
bootConfig = (u32)out;
|
bootConfig = (u32)out;
|
||||||
if(R_FAILED(svcGetSystemInfo(&out, 0x10000, 0x203))) svcBreak(USERBREAK_ASSERT);
|
svcGetSystemInfo(&out, 0x10000, 6);
|
||||||
|
splashDurationMsec = (u32)out;
|
||||||
|
svcGetSystemInfo(&out, 0x10000, 0x203);
|
||||||
isSdMode = (bool)out;
|
isSdMode = (bool)out;
|
||||||
|
|
||||||
memcpy(configData.magic, "CONF", 4);
|
|
||||||
configData.formatVersionMajor = (u16)(formatVersion >> 16);
|
configData.formatVersionMajor = (u16)(formatVersion >> 16);
|
||||||
configData.formatVersionMinor = (u16)formatVersion;
|
configData.formatVersionMinor = (u16)formatVersion;
|
||||||
configData.config = config;
|
configData.config = config;
|
||||||
configData.multiConfig = multiConfig;
|
configData.multiConfig = multiConfig;
|
||||||
configData.bootConfig = bootConfig;
|
configData.bootConfig = bootConfig;
|
||||||
|
configData.splashDurationMsec = splashDurationMsec;
|
||||||
configData.hbldr3dsxTitleId = Luma_SharedConfig->hbldr_3dsx_tid;
|
configData.hbldr3dsxTitleId = Luma_SharedConfig->hbldr_3dsx_tid;
|
||||||
configData.rosalinaMenuCombo = menuCombo;
|
configData.rosalinaMenuCombo = menuCombo;
|
||||||
|
configData.screenFiltersCct = (u16)screenFiltersCurrentTemperature;
|
||||||
|
configData.ntpTzOffetMinutes = (s16)lastNtpTzOffset;
|
||||||
|
|
||||||
|
size_t n = saveLumaIniConfigToStr(inibuf, &configData);
|
||||||
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
FS_ArchiveID archiveId = isSdMode ? ARCHIVE_SDMC : ARCHIVE_NAND_RW;
|
||||||
res = IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/config.bin"), FS_OPEN_CREATE | FS_OPEN_WRITE);
|
if (n > 0)
|
||||||
|
res = IFile_Open(&file, archiveId, fsMakePath(PATH_EMPTY, ""), fsMakePath(PATH_ASCII, "/luma/config.ini"), FS_OPEN_CREATE | FS_OPEN_WRITE);
|
||||||
|
else
|
||||||
|
res = -1;
|
||||||
|
|
||||||
if(R_SUCCEEDED(res))
|
if(R_SUCCEEDED(res))
|
||||||
res = IFile_SetSize(&file, sizeof(configData));
|
res = IFile_SetSize(&file, n);
|
||||||
if(R_SUCCEEDED(res))
|
if(R_SUCCEEDED(res))
|
||||||
res = IFile_Write(&file, &total, &configData, sizeof(configData), 0);
|
res = IFile_Write(&file, &total, inibuf, n, 0);
|
||||||
IFile_Close(&file);
|
IFile_Close(&file);
|
||||||
|
|
||||||
Draw_Lock();
|
Draw_Lock();
|
||||||
@ -390,8 +506,9 @@ void MiscellaneousMenu_UpdateTimeDateNtp(void)
|
|||||||
res = srvIsServiceRegistered(&isSocURegistered, "soc:U");
|
res = srvIsServiceRegistered(&isSocURegistered, "soc:U");
|
||||||
cantStart = R_FAILED(res) || !isSocURegistered;
|
cantStart = R_FAILED(res) || !isSocURegistered;
|
||||||
|
|
||||||
int utcOffset = 12;
|
int dt = 12*60 + lastNtpTzOffset;
|
||||||
int utcOffsetMinute = 0;
|
int utcOffset = dt / 60;
|
||||||
|
int utcOffsetMinute = dt%60;
|
||||||
int absOffset;
|
int absOffset;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@ -405,8 +522,8 @@ void MiscellaneousMenu_UpdateTimeDateNtp(void)
|
|||||||
|
|
||||||
input = waitInput();
|
input = waitInput();
|
||||||
|
|
||||||
if(input & KEY_LEFT) utcOffset = (24 + utcOffset - 1) % 24; // ensure utcOffset >= 0
|
if(input & KEY_LEFT) utcOffset = (27 + utcOffset - 1) % 27; // ensure utcOffset >= 0
|
||||||
if(input & KEY_RIGHT) utcOffset = (utcOffset + 1) % 24;
|
if(input & KEY_RIGHT) utcOffset = (utcOffset + 1) % 27;
|
||||||
if(input & KEY_UP) utcOffsetMinute = (utcOffsetMinute + 1) % 60;
|
if(input & KEY_UP) utcOffsetMinute = (utcOffsetMinute + 1) % 60;
|
||||||
if(input & KEY_DOWN) utcOffsetMinute = (60 + utcOffsetMinute - 1) % 60;
|
if(input & KEY_DOWN) utcOffsetMinute = (60 + utcOffsetMinute - 1) % 60;
|
||||||
Draw_FlushFramebuffer();
|
Draw_FlushFramebuffer();
|
||||||
@ -418,6 +535,7 @@ void MiscellaneousMenu_UpdateTimeDateNtp(void)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
utcOffset -= 12;
|
utcOffset -= 12;
|
||||||
|
lastNtpTzOffset = 60 * utcOffset + utcOffsetMinute;
|
||||||
|
|
||||||
res = srvIsServiceRegistered(&isSocURegistered, "soc:U");
|
res = srvIsServiceRegistered(&isSocURegistered, "soc:U");
|
||||||
cantStart = R_FAILED(res) || !isSocURegistered;
|
cantStart = R_FAILED(res) || !isSocURegistered;
|
||||||
|
@ -45,7 +45,7 @@ typedef union {
|
|||||||
static u16 g_c[0x600];
|
static u16 g_c[0x600];
|
||||||
static Pixel g_px[0x400];
|
static Pixel g_px[0x400];
|
||||||
|
|
||||||
int screenFiltersCurrentTemperature = -1;
|
int screenFiltersCurrentTemperature = 6500;
|
||||||
|
|
||||||
static void ScreenFiltersMenu_WriteLut(const Pixel* lut)
|
static void ScreenFiltersMenu_WriteLut(const Pixel* lut)
|
||||||
{
|
{
|
||||||
@ -90,7 +90,7 @@ static void ScreenFiltersMenu_ApplyColorSettings(color_setting_t* cs)
|
|||||||
ScreenFiltersMenu_WriteLut(g_px);
|
ScreenFiltersMenu_WriteLut(g_px);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ScreenFiltersMenu_SetCct(int cct)
|
void ScreenFiltersMenu_SetCct(int cct)
|
||||||
{
|
{
|
||||||
color_setting_t cs;
|
color_setting_t cs;
|
||||||
memset(&cs, 0, sizeof(cs));
|
memset(&cs, 0, sizeof(cs));
|
||||||
@ -102,6 +102,7 @@ static void ScreenFiltersMenu_SetCct(int cct)
|
|||||||
cs.brightness = 1.0F;*/
|
cs.brightness = 1.0F;*/
|
||||||
|
|
||||||
ScreenFiltersMenu_ApplyColorSettings(&cs);
|
ScreenFiltersMenu_ApplyColorSettings(&cs);
|
||||||
|
screenFiltersCurrentTemperature = cct;
|
||||||
}
|
}
|
||||||
|
|
||||||
Menu screenFiltersMenu = {
|
Menu screenFiltersMenu = {
|
||||||
@ -124,14 +125,13 @@ Menu screenFiltersMenu = {
|
|||||||
#define DEF_CCT_SETTER(temp, name)\
|
#define DEF_CCT_SETTER(temp, name)\
|
||||||
void ScreenFiltersMenu_Set##name(void)\
|
void ScreenFiltersMenu_Set##name(void)\
|
||||||
{\
|
{\
|
||||||
screenFiltersCurrentTemperature = temp;\
|
|
||||||
ScreenFiltersMenu_SetCct(temp);\
|
ScreenFiltersMenu_SetCct(temp);\
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScreenFiltersMenu_RestoreCct(void)
|
void ScreenFiltersMenu_RestoreCct(void)
|
||||||
{
|
{
|
||||||
// Not initialized: return
|
// Not initialized/default: return
|
||||||
if (screenFiltersCurrentTemperature == -1)
|
if (screenFiltersCurrentTemperature == 6500)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Wait for GSP to restore the CCT table
|
// Wait for GSP to restore the CCT table
|
||||||
|
Loading…
x
Reference in New Issue
Block a user