From 1c737d499f61c67a99f50382ab85f42e2049d53a Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Sun, 15 Sep 2024 00:29:25 +0200 Subject: [PATCH] rosalina: add qtm calibration submenu Also steal qtm handle b/c of limitiations (max 3 sessions total) --- sysmodules/rosalina/include/menu.h | 2 +- sysmodules/rosalina/include/menus/n3ds.h | 2 + sysmodules/rosalina/source/main.c | 2 +- sysmodules/rosalina/source/menu.c | 19 ++- sysmodules/rosalina/source/menus/n3ds.c | 178 ++++++++++++++++++++++- 5 files changed, 194 insertions(+), 9 deletions(-) diff --git a/sysmodules/rosalina/include/menu.h b/sysmodules/rosalina/include/menu.h index 2e62656f..93a76f52 100644 --- a/sysmodules/rosalina/include/menu.h +++ b/sysmodules/rosalina/include/menu.h @@ -69,7 +69,7 @@ extern u32 menuCombo; extern bool isHidInitialized; extern bool isQtmInitialized; extern u32 mcuFwVersion; -extern u8 mcuInfoTable[9]; +extern u8 mcuInfoTable[10]; extern bool mcuInfoTableRead; extern const char *topScreenType; extern const char *bottomScreenType; diff --git a/sysmodules/rosalina/include/menus/n3ds.h b/sysmodules/rosalina/include/menus/n3ds.h index 294117e2..fe947398 100644 --- a/sysmodules/rosalina/include/menus/n3ds.h +++ b/sysmodules/rosalina/include/menus/n3ds.h @@ -38,3 +38,5 @@ void N3DSMenu_ChangeClockRate(void); void N3DSMenu_EnableDisableL2Cache(void); void N3DSMenu_ToggleSs3d(void); +void N3DSMenu_TestBarrierPositions(void); +void N3DSMenu_Ss3dCalibration(void); diff --git a/sysmodules/rosalina/source/main.c b/sysmodules/rosalina/source/main.c index ea2d6ed5..432264d1 100644 --- a/sysmodules/rosalina/source/main.c +++ b/sysmodules/rosalina/source/main.c @@ -206,7 +206,7 @@ static void handlePreTermNotification(u32 notificationId) if (isHidInitialized) hidExit(); if (isQtmInitialized) - qtmExit(); + svcCloseHandle(*qtmGetSessionHandle()); // qtmExit(); // Termination request menuShouldExit = true; diff --git a/sysmodules/rosalina/source/menu.c b/sysmodules/rosalina/source/menu.c index cfdec672..bde2271d 100644 --- a/sysmodules/rosalina/source/menu.c +++ b/sysmodules/rosalina/source/menu.c @@ -44,7 +44,7 @@ u32 menuCombo = 0; bool isHidInitialized = false; bool isQtmInitialized = false; u32 mcuFwVersion = 0; -u8 mcuInfoTable[9] = {0}; +u8 mcuInfoTable[10] = {0}; bool mcuInfoTableRead = false; const char *topScreenType = NULL; @@ -289,9 +289,17 @@ static void menuInitializeQtm(void) if (isQtmInitialized) return; - // Open last remaining qtm:sp session (out of 3) on >= 9.3, - // or one of the two qtm:s handles below 9.3 - isQtmInitialized = R_SUCCEEDED(qtmInit(GET_VERSION_MINOR(osGetKernelVersion()) >= 48 ? QTM_SERVICE_SYSTEM_PROCESS : QTM_SERVICE_SYSTEM)); + // Steal QTM handle from GSP, because there is a limit of 3 sessions (or 2 before 9.3) for ALL qtm services + Handle qtmHandle = 0; + for (int i = 0; i < 20 && !qtmIsInitialized(); i++) + { + if (R_SUCCEEDED(svcControlService(SERVICEOP_STEAL_CLIENT_SESSION, &qtmHandle, "qtm:sp"))) + *qtmGetSessionHandle() = qtmHandle; + else + svcSleepThread(100 * 100 * 1000LL); + } + + isQtmInitialized = qtmIsInitialized(); } static inline u32 menuAdvanceCursor(u32 pos, u32 numItems, s32 displ) @@ -335,6 +343,7 @@ void menuThreadMain(void) { while (!isServiceUsable("qtm:u")) svcSleepThread(250 * 1000 * 1000LL); + menuInitializeQtm(); N3DSMenu_UpdateStatus(); } @@ -345,8 +354,6 @@ void menuThreadMain(void) menuReadScreenTypes(); - menuInitializeQtm(); - while(!preTerminationRequested) { svcSleepThread(50 * 1000 * 1000LL); diff --git a/sysmodules/rosalina/source/menus/n3ds.c b/sysmodules/rosalina/source/menus/n3ds.c index f2c44e80..d49669be 100644 --- a/sysmodules/rosalina/source/menus/n3ds.c +++ b/sysmodules/rosalina/source/menus/n3ds.c @@ -25,19 +25,27 @@ */ #include <3ds.h> +#include #include "fmt.h" #include "menus/n3ds.h" #include "memory.h" #include "menu.h" +#include "n3ds.h" +#include "draw.h" static char clkRateBuf[128 + 1]; +static QtmCalibrationData lastQtmCal = {0}; +static bool qtmCalRead = false; + Menu N3DSMenu = { "New 3DS menu", { { "Enable L2 cache", METHOD, .method = &N3DSMenu_EnableDisableL2Cache }, { clkRateBuf, METHOD, .method = &N3DSMenu_ChangeClockRate }, { "Temporarily disable Super-Stable 3D", METHOD, .method = &N3DSMenu_ToggleSs3d, .visibility = &N3DSMenu_CheckNotN2dsXl }, + { "Test parallax barrier positions", METHOD, .method = &N3DSMenu_TestBarrierPositions, .visibility = &N3DSMenu_CheckNotN2dsXl }, + { "Super-Stable 3D calibration", METHOD, .method = &N3DSMenu_Ss3dCalibration, .visibility = &N3DSMenu_CheckNotN2dsXl }, {}, } }; @@ -49,7 +57,7 @@ static QtmStatus lastUpdatedQtmStatus; bool N3DSMenu_CheckNotN2dsXl(void) { // Also check if qtm could be initialized - return isQtmInitialized && mcuInfoTableRead && mcuInfoTable[9] != 5 && !qtmUnavailableAndNotBlacklisted; + return isQtmInitialized && mcuInfoTableRead && mcuInfoTable[9] < 5 && !qtmUnavailableAndNotBlacklisted; } void N3DSMenu_UpdateStatus(void) @@ -116,3 +124,171 @@ void N3DSMenu_ToggleSs3d(void) N3DSMenu_UpdateStatus(); } + +void N3DSMenu_TestBarrierPositions(void) +{ + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + u8 pos = 0; + QTMS_DisableAutoBarrierControl(); // assume it doesn't fail + QTMS_GetCurrentBarrierPosition(&pos); + + u32 pressed = 0; + + do + { + Draw_Lock(); + + Draw_DrawString(10, 10, COLOR_TITLE, "New 3DS menu"); + u32 posY = Draw_DrawString(10, 30, COLOR_WHITE, "Use left/right to adjust the barrier's position.\n\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Each position corresponds to 5.2mm horizontal eye\nmovement (assuming ideal viewing conditions).\n\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Once you figure out the ideal central position, you\ncan then use it in the calibration submenu.\n\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Auto-barrier adjustment behavior is restored on\nexit.\n\n"); + + posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Barrier position: %2hhu\n", pos); + + Draw_FlushFramebuffer(); + pressed = waitInputWithTimeout(1000); + + if (pressed & KEY_LEFT) + { + pos = pos > 11 ? 11 : pos; // pos is 13 when SS3D is disabled/camera is in use + pos = (12 + pos - 1) % 12; + QTMS_SetBarrierPosition(pos); + } + else if (pressed & KEY_RIGHT) + { + pos = pos > 11 ? 11 : pos; // pos is 13 when SS3D is disabled/camera is in use + pos = (pos + 1) % 12; + QTMS_SetBarrierPosition(pos); + } + + Draw_Unlock(); + } while(!menuShouldExit && !(pressed & KEY_B)); + + QTMS_EnableAutoBarrierControl(); +} + +void N3DSMenu_Ss3dCalibration(void) +{ + Draw_Lock(); + Draw_ClearFramebuffer(); + Draw_FlushFramebuffer(); + Draw_Unlock(); + + u8 currentPos; + QtmTrackingData trackingData = {0}; + + if (R_FAILED(QTMS_GetCurrentBarrierPosition(¤tPos))) + currentPos = 13; + + bool calReadFailed = false; + + if (!qtmCalRead) + { + cfguInit(); + calReadFailed = R_FAILED(CFG_GetConfigInfoBlk8(sizeof(QtmCalibrationData), QTM_CAL_CFG_BLK_ID, &lastQtmCal)); + cfguExit(); + if (!calReadFailed) + qtmCalRead = true; + } + + bool trackingDisabled = currentPos == 13; + + if (currentPos < 12) + QTMS_EnableAutoBarrierControl(); // assume this doesn't fail + + u32 pressed = 0; + do + { + if (!trackingDisabled) + { + QTMS_GetCurrentBarrierPosition(¤tPos); + QTMU_GetTrackingData(&trackingData); + } + + Draw_Lock(); + + Draw_DrawString(10, 10, COLOR_TITLE, "New 3DS menu"); + u32 posY = 30; + + if (trackingDisabled) + posY = Draw_DrawString(10, posY, COLOR_WHITE, "SS3D disabled or camera in use.\nPress B to exit this menu.\n"); + else if (calReadFailed) + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Failed to read calibration data.\nPress B to exit this menu.\n"); + else + { + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Right/Left: +- 1\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Up/Down: +- 0.1\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "R/L: +- 0.01\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "A: save to system config\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "Y: reload last saved calibration\n"); + posY = Draw_DrawString(10, posY, COLOR_WHITE, "B: exit this menu\n\n"); + + char calStr[16]; + floatToString(calStr, lastQtmCal.centerBarrierPosition, 2, true); + posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Center position: %-5s\n\n", calStr); + + posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Current barrier position: %-2hhu\n", currentPos); + posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Current eye distance: %-2d cm\n", (int)roundf(qtmEstimateEyeToCameraDistance(&trackingData) / 10.0f)); + posY = Draw_DrawFormattedString(10, posY, COLOR_WHITE, "Optimal eye distance: %-2d cm\n", (int)roundf(lastQtmCal.viewingDistance / 10.0f)); + } + + Draw_FlushFramebuffer(); + pressed = waitInputWithTimeout(15); + + if (!calReadFailed) + { + if (pressed & KEY_LEFT) + { + lastQtmCal.centerBarrierPosition = fmodf(12.0f + lastQtmCal.centerBarrierPosition - 1.0f, 12.0f); + QTMS_SetCalibrationData(&lastQtmCal, false); + } + else if (pressed & KEY_RIGHT) + { + lastQtmCal.centerBarrierPosition = fmodf(lastQtmCal.centerBarrierPosition + 1.0f, 12.0f); + QTMS_SetCalibrationData(&lastQtmCal, false); + } + + if (pressed & KEY_DOWN) + { + lastQtmCal.centerBarrierPosition = fmodf(12.0f + lastQtmCal.centerBarrierPosition - 0.1f, 12.0f); + QTMS_SetCalibrationData(&lastQtmCal, false); + } + else if (pressed & KEY_UP) + { + lastQtmCal.centerBarrierPosition = fmodf(lastQtmCal.centerBarrierPosition + 0.1f, 12.0f); + QTMS_SetCalibrationData(&lastQtmCal, false); + } + + if (pressed & KEY_L) + { + lastQtmCal.centerBarrierPosition = fmodf(12.0f + lastQtmCal.centerBarrierPosition - 0.01f, 12.0f); + QTMS_SetCalibrationData(&lastQtmCal, false); + } + else if (pressed & KEY_R) + { + lastQtmCal.centerBarrierPosition = fmodf(lastQtmCal.centerBarrierPosition + 0.01f, 12.0f); + QTMS_SetCalibrationData(&lastQtmCal, false); + } + + if (pressed & KEY_A) + QTMS_SetCalibrationData(&lastQtmCal, true); + + if (pressed & KEY_Y) + { + cfguInit(); + calReadFailed = R_FAILED(CFG_GetConfigInfoBlk8(sizeof(QtmCalibrationData), QTM_CAL_CFG_BLK_ID, &lastQtmCal)); + cfguExit(); + qtmCalRead = !calReadFailed; + if (qtmCalRead) + QTMS_SetCalibrationData(&lastQtmCal, false); + } + } + + Draw_Unlock(); + } while(!menuShouldExit && !(pressed & KEY_B)); +}