From 54caa3588ee6dcb9f199924092d3ef58c0f030c4 Mon Sep 17 00:00:00 2001 From: d0k3 Date: Fri, 26 Apr 2019 02:01:08 +0200 Subject: [PATCH] Added touchscreen calibration from NVRAM (thanks @wolfvak) --- arm9/source/common/touchcal.c | 73 +++++++++++++++++++++++++++++++---- arm9/source/common/touchcal.h | 3 +- arm9/source/godmode.c | 4 +- arm9/source/main.c | 14 ------- 4 files changed, 71 insertions(+), 23 deletions(-) diff --git a/arm9/source/common/touchcal.c b/arm9/source/common/touchcal.c index 750c75b..8495e40 100644 --- a/arm9/source/common/touchcal.c +++ b/arm9/source/common/touchcal.c @@ -1,15 +1,34 @@ #include "touchcal.h" #include "ui.h" #include "hid.h" +#include "crc16.h" +#include "spiflash.h" -bool ShowCalibrationDialog(void) +static const HID_CalibrationData default_calib = { + .screen_x = 0, + .screen_y = 0, + .ts_raw = 0 + // ^ wrong: in my console it's 0x780086 + // but this is very much console dependent + // so it's better to go with a sane default +}; + + +static bool SetCalibrationDefaults(void) +{ + // Hardcoding this isn't ideal but it's better than + // leaving the system without any state to work with + return HID_SetCalibrationData(&default_calib, 1, SCREEN_WIDTH_BOT, SCREEN_HEIGHT); +} + +bool ShowTouchCalibrationDialog(void) { static const u32 dot_positions[][2] = { {16, 16}, - {320 - 16, 240 - 16}, - {16, 240 - 16}, - {320 - 16, 16}, + {SCREEN_WIDTH_BOT - 16, SCREEN_HEIGHT - 16}, + {16, SCREEN_HEIGHT - 16}, + {SCREEN_WIDTH_BOT - 16, 16}, }; HID_CalibrationData calibrations[countof(dot_positions)]; @@ -23,6 +42,9 @@ bool ShowCalibrationDialog(void) DrawStringCenter(BOT_SCREEN, COLOR_STD_FONT, COLOR_STD_BG, "Touch the red crosshairs to\ncalibrate your touchscreen.\n \nUse the stylus for best\nresults!"); + // set calibration defaults + SetCalibrationDefaults(); + // actual calibration for (u32 current_dot = 0; current_dot < countof(dot_positions); current_dot++) { // draw four crosshairs @@ -48,7 +70,7 @@ bool ShowCalibrationDialog(void) } } - return HID_SetCalibrationData(calibrations, countof(dot_positions), 320, 240); + return HID_SetCalibrationData(calibrations, countof(dot_positions), SCREEN_WIDTH_BOT, SCREEN_HEIGHT); } void ShowTouchPlayground(void) @@ -65,12 +87,49 @@ void ShowTouchPlayground(void) while (pressed & BUTTON_TOUCH) { u16 tx, ty; HID_ReadTouchState(&tx, &ty); - if (tx < 320 && ty < 240) + if (tx < SCREEN_WIDTH_BOT && ty < SCREEN_HEIGHT) DrawPixel(BOT_SCREEN, tx, ty, COLOR_BRIGHTYELLOW); DrawStringF(BOT_SCREEN, 16, 16, COLOR_STD_FONT, COLOR_STD_BG, "Current touchscreen coordinates: %3.3d, %3.3d", tx, ty); pressed = HID_ReadState(); } } - +} + +bool CalibrateTouchFromFlash(void) { + HID_CalibrationData data[2]; + + // set calibration defaults + SetCalibrationDefaults(); + + // check SPIflash status + if (!spiflash_get_status()) + return false; + + // check NVRAM console ID + u32 console_id = 0; + spiflash_read(0x001C, 4, (u8*)&console_id); + if (((console_id >> 8) & 0xFF) != 0x57) + return false; // not a 3DS + + // read and check DS fw user settings + // see: https://problemkaputt.de/gbatek.htm#dsfirmwareusersettings + u32 fw_usercfg_buf[0x100 / 0x4]; + u8* fw_usercfg = (u8*) fw_usercfg_buf; + spiflash_read(0x1FE00, 0x100, fw_usercfg); + if (getle16(fw_usercfg + 0x72) != crc16_quick(fw_usercfg, 0x70)) { + ShowPrompt(false, "ugh"); + return false; + } + + // get touchscreen calibration data from user settings + u8 *ts_data = fw_usercfg + 0x58; + for (int i = 0; i < 2; i++) { + int base = i * 6; + data[i].ts_raw = ts_data[base + 1] << 24 | ts_data[base + 0] << 16 | ts_data[base + 3] << 8 | ts_data[base + 2]; + data[i].screen_x = (((int)ts_data[base + 4]) * SCREEN_WIDTH_BOT) / 256; + data[i].screen_y = (((int)ts_data[base + 5]) * SCREEN_HEIGHT) / 192; + } + + return HID_SetCalibrationData(data, 2, SCREEN_WIDTH_BOT, SCREEN_HEIGHT); } diff --git a/arm9/source/common/touchcal.h b/arm9/source/common/touchcal.h index 0bf6485..05c6f28 100644 --- a/arm9/source/common/touchcal.h +++ b/arm9/source/common/touchcal.h @@ -2,5 +2,6 @@ #include "common.h" -bool ShowCalibrationDialog(void); +bool ShowTouchCalibrationDialog(void); void ShowTouchPlayground(void); +bool CalibrateTouchFromFlash(void); diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 7b7c79f..498af05 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -2049,6 +2049,7 @@ u32 GodMode(int entrypoint) { AutoEmuNandBase(true); InitNandCrypto(entrypoint != ENTRY_B9S); InitExtFS(); + CalibrateTouchFromFlash(); // !!! this may need some further checking // custom font handling if (CheckSupportFile("font.pbm")) { @@ -2537,7 +2538,7 @@ u32 GodMode(int entrypoint) { break; } } else if (user_select == calib) { - ShowPrompt(false, "Touchscreen calibration %s!", (ShowCalibrationDialog()) ? "success" : "failed"); + ShowPrompt(false, "Touchscreen calibration %s!", (ShowTouchCalibrationDialog()) ? "success" : "failed"); } else if (user_select == playground) { ShowTouchPlayground(); } else if (user_select == payloads) { @@ -2599,6 +2600,7 @@ u32 ScriptRunner(int entrypoint) { AutoEmuNandBase(true); InitNandCrypto(entrypoint != ENTRY_B9S); InitExtFS(); + CalibrateTouchFromFlash(); // !!! this may need some further checking while (CheckButton(BOOTPAUSE_KEY)); // don't continue while these keys are held while (timer_msec( timer ) < 500); // show splash for at least 0.5 sec diff --git a/arm9/source/main.c b/arm9/source/main.c index 233940c..4d6e8d7 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -1,22 +1,12 @@ #include "godmode.h" #include "power.h" -#include "timer.h" #include "pxi.h" -#include "i2c.h" #include "arm.h" #include "shmem.h" #include "hid.h" -static const HID_CalibrationData default_calib = { - .screen_x = 0, - .screen_y = 0, - .ts_raw = 0 - // ^ wrong: in my console it's 0x780086 - // but this is very much console dependent - // so it's better to go with a sane default -}; void main(int argc, char** argv, int entrypoint) { @@ -33,10 +23,6 @@ void main(int argc, char** argv, int entrypoint) // stored in the thread ID register in the ARM9 ARM_InitSHMEM(); - // Hardcoding this isn't ideal but it's better than - // leaving the system without any state to work with - HID_SetCalibrationData(&default_calib, 1, 320, 240); - #ifdef SCRIPT_RUNNER // Run the script runner if (ScriptRunner(entrypoint) == GODMODE_EXIT_REBOOT)