diff --git a/arm11/source/hw/codec.c b/arm11/source/hw/codec.c index 04aa1e8..53eec4b 100755 --- a/arm11/source/hw/codec.c +++ b/arm11/source/hw/codec.c @@ -157,7 +157,7 @@ static void CODEC_GetRawData(u8 *buffer) void CODEC_Get(CODEC_Input *input) { - u8 raw_data[0x34] = {0}; + u8 raw_data[0x34]; s16 cpad_x, cpad_y; bool ts_pressed; @@ -167,15 +167,8 @@ void CODEC_Get(CODEC_Input *input) cpad_y = ((raw_data[0x14] << 8 | raw_data[0x15]) & 0xFFF) - 2048; // X axis is inverted - if (abs(cpad_x) > CPAD_THRESH) - input->cpad_x = -cpad_x / CPAD_FACTOR; - else - input->cpad_x = 0; - - if (abs(cpad_y) > CPAD_THRESH) - input->cpad_y = cpad_y / CPAD_FACTOR; - else - input->cpad_y = 0; + input->cpad_x = (abs(cpad_x) > CPAD_THRESH) ? -cpad_x / CPAD_FACTOR : 0; + input->cpad_y = (abs(cpad_y) > CPAD_THRESH) ? cpad_y / CPAD_FACTOR : 0; ts_pressed = !(raw_data[0] & BIT(4)); if (ts_pressed) { diff --git a/arm11/source/hw/codec.h b/arm11/source/hw/codec.h index 25e2a85..5434ed5 100755 --- a/arm11/source/hw/codec.h +++ b/arm11/source/hw/codec.h @@ -2,8 +2,6 @@ #include -#define CODEC_TOUCH_VALID(x) ((x) != 0xFFFFFFFF) - typedef struct { s16 cpad_x, cpad_y; s16 ts_x, ts_y; diff --git a/arm9/source/common/hid.c b/arm9/source/common/hid.c index dee4dba..1bb6516 100644 --- a/arm9/source/common/hid.c +++ b/arm9/source/common/hid.c @@ -4,8 +4,12 @@ #include "screenshot.h" // for screenshots #include "arm.h" +#include "fixp.h" #include "shmem.h" +#define HID_TOUCH_MAXPOINT (0x1000) +#define HID_TOUCH_MIDPOINT (HID_TOUCH_MAXPOINT / 2) + // there's some weird thing going on when reading this // with an LDRD instruction so for now they'll be two // separate things - hopefully LTO won't get in the way @@ -19,6 +23,66 @@ u32 HID_ReadRawTouchState(void) return ARM_GetSHMEM()->hid_state >> 32; } +static u32 ts_x_org, ts_y_org; +static fixp_t ts_x_mult, ts_y_mult; +void HID_ReadTouchState(u16 *x, u16 *y) +{ + u32 ts; + fixp_t tx, ty; + + ts = HID_ReadRawTouchState(); + tx = INT_TO_FIXP(HID_RAW_TX(ts) - HID_TOUCH_MIDPOINT); + ty = INT_TO_FIXP(HID_RAW_TY(ts) - HID_TOUCH_MIDPOINT); + + *x = FIXP_TO_INT(fixp_round(fixp_product(tx, ts_x_mult))) + ts_x_org; + *y = FIXP_TO_INT(fixp_round(fixp_product(ty, ts_y_mult))) + ts_y_org; +} + +bool HID_SetCalibrationData(const HID_CalibrationData *calibs, int point_cnt, u32 screen_w, u32 screen_h) +{ + int x_mid, y_mid; + fixp_t avg_x, avg_y; + + if (!screen_w || !screen_h || point_cnt <= 0) + return false; + + x_mid = screen_w / 2; + y_mid = screen_h / 2; + + avg_x = 0; + avg_y = 0; + + for (int i = 0; i < point_cnt; i++) { + const HID_CalibrationData *data = &calibs[i]; + fixp_t screen_x, screen_y, touch_x, touch_y; + + // translate the [0, screen_w] x [0, screen_h] system + // to [-screen_w/2, screen_w/2] x [-screen_h/2, screen_h/2] + screen_x = INT_TO_FIXP(data->screen_x - x_mid); + screen_y = INT_TO_FIXP(data->screen_y - y_mid); + + // same thing for raw touchscreen data + touch_x = INT_TO_FIXP(HID_RAW_TX(data->ts_raw) - HID_TOUCH_MIDPOINT); + touch_y = INT_TO_FIXP(HID_RAW_TY(data->ts_raw) - HID_TOUCH_MIDPOINT); + + // if the data retrieved came right in the middle, it's invalid + if (!screen_x || !screen_y || !touch_x || !touch_y) + return false; + + avg_x += fixp_quotient(screen_x, touch_x); + avg_y += fixp_quotient(screen_y, touch_y); + } + + ts_x_mult = avg_x / point_cnt; + ts_y_mult = avg_y / point_cnt; + + ts_x_org = x_mid; + ts_y_org = y_mid; + return true; +} + +#include "ui.h" + u32 InputWait(u32 timeout_sec) { static u64 delay = 0; u64 timer = timer_start(); diff --git a/arm9/source/common/hid.h b/arm9/source/common/hid.h index 814aff6..4b7b825 100644 --- a/arm9/source/common/hid.h +++ b/arm9/source/common/hid.h @@ -6,13 +6,26 @@ // see: http://3dbrew.org/wiki/CONFIG9_Registers // see: http://3dbrew.org/wiki/EMMC_Registers - -u32 HID_ReadState(void); -u32 HID_ReadRawTouchState(void); - #define CART_STATE (~(*(volatile u8*)0x10000010) & 0x1) #define SD_STATE ((*(volatile u16*)0x1000601C) & (0x1<<5)) +#define HID_RAW_TX(t) ((s32)(((t) / (1 << 16)) & 0xFFF)) +#define HID_RAW_TY(t) ((s32)((t) & 0xFFF)) + +u32 HID_ReadState(void); + +// ts_raw is the raw touchscreen value obtained when pressing down +// the touchscreen at the screen coordinates [screen_x, screen_y] +// note: no point can be at the center +typedef struct { + u32 ts_raw; + int screen_x, screen_y; +} HID_CalibrationData; + +u32 HID_ReadRawTouchState(void); +void HID_ReadTouchState(u16 *x, u16 *y); +bool HID_SetCalibrationData(const HID_CalibrationData *calibs, int point_cnt, u32 screen_w, u32 screen_h); + u32 InputWait(u32 timeout_sec); bool CheckButton(u32 button); diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 56e555e..5367f46 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -2184,7 +2184,7 @@ u32 GodMode(int entrypoint) { last_write_perm = GetWritePermissions(); continue; } - + // handle user input u32 pad_state = InputWait(3); bool switched = (pad_state & BUTTON_R1); diff --git a/arm9/source/main.c b/arm9/source/main.c index 61f4101..233940c 100644 --- a/arm9/source/main.c +++ b/arm9/source/main.c @@ -7,6 +7,17 @@ #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) { (void) argc; @@ -22,6 +33,10 @@ 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) diff --git a/common/fixp.h b/common/fixp.h new file mode 100755 index 0000000..fd5dc43 --- /dev/null +++ b/common/fixp.h @@ -0,0 +1,37 @@ +#pragma once + +// Fixed point math operations + +#include +#include + +typedef int32_t fixp_t; + +// 12 bit precision was chosen because +// that's the touchscreen's ADC resolution +#define FIXP_PRECISION (12) + +#define INT_TO_FIXP(i) ((fixp_t)((i) * (1 << FIXP_PRECISION))) +#define FIXP_TO_INT(f) ((fixp_t)((f) / (1 << FIXP_PRECISION))) + +#define FIXP_WHOLE_UNIT INT_TO_FIXP(1) +#define FIXP_HALF_UNIT (FIXP_WHOLE_UNIT / 2) +#define FIXP_ZERO_UNIT (0) + +#define FIXP_FRAC_MASK (FIXP_WHOLE_UNIT - 1) +#define FIXP_UNIT_MASK (~0 & ~FIXP_FRAC_MASK) + +static inline fixp_t fixp_product(fixp_t a, fixp_t b) +{ + return (((s64)a * (s64)b) >> FIXP_PRECISION); +} + +static inline fixp_t fixp_quotient(fixp_t a, fixp_t b) +{ + return ((s64)a << FIXP_PRECISION) / b; +} + +static inline fixp_t fixp_round(fixp_t n) +{ + return (n + FIXP_HALF_UNIT) & FIXP_UNIT_MASK; +}