Added Circle-Pad controls. Costs about 30 µs frame time.

Note: No calibration support yet. If your Circle-Pad is in bad shape or came out of the factory with drift this will certainly break.
This commit is contained in:
profi200 2020-05-05 23:27:34 +02:00
parent dcc21c92ed
commit 51115a9785
No known key found for this signature in database
GPG Key ID: 17B42AE5911139F3
6 changed files with 85 additions and 49 deletions

View File

@ -21,6 +21,15 @@
#include "types.h"
typedef struct
{
u16 touchX[5];
u16 touchY[5];
u16 cpadY[8];
u16 cpadX[8];
} CdcAdcData;
/**
* @brief Initialize CODEC for Circle-Pad/Touchscreen/Sound.
@ -40,6 +49,8 @@ void CODEC_wakeup(void);
/**
* @brief Get raw ADC data for Circle-Pad/Touchscreen.
*
* @param[in] buf The buffer to write the data to.
* @param data The output data pointer. Must be 4 bytes aligned.
*
* @return Returns true if data was available and false otherwise.
*/
void CODEC_getRawAdcData(u32 buf[13]);
bool CODEC_getRawAdcData(CdcAdcData *data);

View File

@ -64,6 +64,11 @@ enum
KEY_DOWN = KEY_DDOWN | KEY_CPAD_DOWN, // D-Pad Down or Circle Pad Down
KEY_LEFT = KEY_DLEFT | KEY_CPAD_LEFT, // D-Pad Left or Circle Pad Left
KEY_RIGHT = KEY_DRIGHT | KEY_CPAD_RIGHT, // D-Pad Right or Circle Pad Right
// Masks
KEY_DPAD = KEY_DDOWN | KEY_DUP | KEY_DLEFT | KEY_DRIGHT,
KEY_CSTICK = KEY_CSTICK_DOWN | KEY_CSTICK_UP | KEY_CSTICK_LEFT | KEY_CSTICK_RIGHT,
KEY_CPAD = KEY_CPAD_DOWN | KEY_CPAD_UP | KEY_CPAD_LEFT | KEY_CPAD_RIGHT
};
// Extra keys use with hidGetExtraKeys()
@ -97,6 +102,6 @@ void hidScanInput(void);
u32 hidKeysHeld(void);
u32 hidKeysDown(void);
u32 hidKeysUp(void);
//const TouchPos* hidGetTouchPosPtr(void);
//const CpadPos* hidGetCpadPosPtr(void);
const TouchPos* hidGetTouchPosPtr(void);
const CpadPos* hidGetCpadPosPtr(void);
u32 hidGetExtraKeys(u32 clearMask);

View File

@ -19,6 +19,7 @@
// Based on code from https://github.com/xerpi/linux_3ds/blob/master/drivers/input/misc/nintendo3ds_codec_hid.c
#include "types.h"
#include "arm11/hardware/codec.h"
#include "arm11/hardware/spi.h"
#include "arm11/hardware/timer.h"
#include "arm11/hardware/gpio.h"
@ -440,11 +441,17 @@ void CODEC_wakeup(void)
TIMER_sleepMs(18); // Fixed 18 ms delay when unsetting this GPIO.
}
void CODEC_getRawAdcData(u32 buf[13])
bool CODEC_getRawAdcData(CdcAdcData *data)
{
//codecSwitchBank(0x67);
// This reg read seems useless and doesn't affect funtionality.
//codecReadReg(0x26);
if((codecReadReg(0x67, 0x26) & 2u) == 0)
{
codecReadRegBuf(0xFB, 1, (u32*)data, sizeof(CdcAdcData));
codecReadRegBuf(0xFB, 1, buf, 52);
return true;
}
// Codec module does this when data is unavailable. Why?
//codecSwitchBank(0);
return false;
}

View File

@ -32,10 +32,10 @@
#define CPAD_THRESHOLD (400)
static u32 kHeld, kDown, kUp;
static u32 extraKeys;
//TouchPos tPos;
//CpadPos cPos;
static u32 g_kHeld = 0, g_kDown = 0, g_kUp = 0;
static u32 g_extraKeys = 0;
TouchPos tPos = {0};
CpadPos cPos = {0};
@ -45,17 +45,15 @@ void hidInit(void)
if(inited) return;
inited = true;
kUp = kDown = kHeld = 0;
MCU_init();
u8 state = MCU_getExternalHwState();
u32 tmp = ~state<<3 & KEY_SHELL; // Current shell state. Bit is inverted.
tmp |= state<<1 & KEY_BAT_CHARGING; // Current battery charging state
state = MCU_getHidHeld();
tmp |= ~state<<1 & KEY_HOME; // Current HOME button state
extraKeys = tmp;
g_extraKeys = tmp;
//CODEC_init();
CODEC_init();
}
static void updateMcuHidState(void)
@ -63,7 +61,7 @@ static void updateMcuHidState(void)
const u32 state = MCU_getEvents(0x40C07F);
if(state == 0) return;
u32 tmp = extraKeys;
u32 tmp = g_extraKeys;
tmp |= state & (KEY_POWER | KEY_POWER_HELD | KEY_HOME); // Power button pressed/held, HOME button pressed
if(state & 1u<<3) tmp &= ~KEY_HOME; // HOME released
tmp |= state>>1 & (KEY_WIFI | KEY_SHELL); // WiFi switch, shell closed
@ -71,64 +69,68 @@ static void updateMcuHidState(void)
tmp |= state>>10 & KEY_BAT_CHARGING; // Battery started charging
if(state & 1u<<14) tmp &= ~KEY_BAT_CHARGING; // Battery stopped charging
tmp |= state>>16 & KEY_VOL_SLIDER; // Volume slider update
extraKeys = tmp;
g_extraKeys = tmp;
}
/*static u32 rawCodec2Hid(void)
static u32 rawCodec2Hid(void)
{
alignas(4) u8 buf[13 * 4];
CODEC_getRawAdcData((u32*)buf);
static u32 fakeKeysCache = 0;
alignas(4) CdcAdcData adc;
if(!CODEC_getRawAdcData(&adc)) return fakeKeysCache;
// Touchscreen
u32 emuButtons = !(buf[0] & 1u<<4)<<20; // KEY_TOUCH
tPos.x = (buf[0]<<8 | buf[1]) * 320u / 4096u; // TODO: Calibration
tPos.y = (buf[10]<<8 | buf[11]) * 240u / 4096u;
// TODO: Calibration
const u16 tx = __builtin_bswap16(adc.touchX[0]);
u32 fakeKeys = (~tx & 1u<<12)<<8; // KEY_TOUCH
tPos.x = tx * 320u / 4096u;
tPos.y = __builtin_bswap16(adc.touchY[0]) * 240u / 4096u;
// Circle-Pad
cPos.x = -(((buf[36]<<8 | buf[37]) & 0xFFFu) - 2048u); // X axis is inverted
cPos.y = ((buf[20]<<8 | buf[21]) & 0xFFFu) - 2048u;
// TODO: Calibration
cPos.y = (__builtin_bswap16(adc.cpadY[0]) & 0xFFFu) - 2048u;
cPos.x = -((__builtin_bswap16(adc.cpadX[0]) & 0xFFFu) - 2048u); // X axis is inverted.
if((cPos.x >= 0 ? cPos.x : -cPos.x) > CPAD_THRESHOLD)
{
if(cPos.x >= 0) emuButtons |= KEY_CPAD_RIGHT;
else emuButtons |= KEY_CPAD_LEFT;
if(cPos.x >= 0) fakeKeys |= KEY_CPAD_RIGHT;
else fakeKeys |= KEY_CPAD_LEFT;
}
if((cPos.y >= 0 ? cPos.y : -cPos.y) > CPAD_THRESHOLD)
{
if(cPos.y >= 0) emuButtons |= KEY_CPAD_UP;
else emuButtons |= KEY_CPAD_DOWN;
if(cPos.y >= 0) fakeKeys |= KEY_CPAD_UP;
else fakeKeys |= KEY_CPAD_DOWN;
}
return emuButtons;
}*/
fakeKeysCache = fakeKeys;
return fakeKeys;
}
void hidScanInput(void)
{
updateMcuHidState();
const u32 kOld = kHeld;
kHeld = /*rawCodec2Hid() |*/ REG_HID_PAD;
kDown = (~kOld) & kHeld;
kUp = kOld & (~kHeld);
const u32 kOld = g_kHeld;
g_kHeld = rawCodec2Hid() | REG_HID_PAD;
g_kDown = (~kOld) & g_kHeld;
g_kUp = kOld & (~g_kHeld);
}
u32 hidKeysHeld(void)
{
return kHeld;
return g_kHeld;
}
u32 hidKeysDown(void)
{
return kDown;
return g_kDown;
}
u32 hidKeysUp(void)
{
return kUp;
return g_kUp;
}
/*const TouchPos* hidGetTouchPosPtr(void)
const TouchPos* hidGetTouchPosPtr(void)
{
return &tPos;
}
@ -136,12 +138,12 @@ u32 hidKeysUp(void)
const CpadPos* hidGetCpadPosPtr(void)
{
return &cPos;
}*/
}
u32 hidGetExtraKeys(u32 clearMask)
{
const u32 tmp = extraKeys;
extraKeys &= ~clearMask;
const u32 tmp = g_extraKeys;
g_extraKeys &= ~clearMask;
return tmp;
}

View File

@ -67,6 +67,17 @@ void LGY_switchMode(void)
void LGY_handleEvents(void)
{
// Override D-Pad if Circle-Pad is used.
const u32 kHeld = hidKeysHeld();
u16 padSel;
if(kHeld & KEY_CPAD)
{
REG_LGY_PAD_VAL = (kHeld>>24) ^ KEY_DPAD;
padSel = KEY_DPAD;
}
else padSel = 0;
REG_LGY_PAD_SEL = padSel;
LGYFB_processFrame();
// Bit 0 triggers wakeup. Bit 1 sleep state/ack sleep end. Bit 2 unk. Bit 15 IRQ enable (triggers IRQ 89).

View File

@ -49,7 +49,7 @@ int main(void)
GFX_setBrightness(0x30, 0x30);
GFX_gpuInit();
consoleInit(SCREEN_BOT, NULL, false);
CODEC_init();
//CODEC_init();
ee_puts("Prepare legacy mode...");
updateScreens();
@ -62,12 +62,12 @@ int main(void)
do
{
__wfi();
hidScanInput();
if(hidGetExtraKeys(KEY_POWER) & KEY_POWER) break;
LGY_handleEvents();
hidScanInput();
if(hidGetExtraKeys(KEY_POWER) & KEY_POWER) break;
__wfi();
} while(1);
LGY_deinit();