diff --git a/include/arm11/drivers/i2c.h b/include/arm11/drivers/i2c.h index f5ffd43..0d881c0 100644 --- a/include/arm11/drivers/i2c.h +++ b/include/arm11/drivers/i2c.h @@ -123,6 +123,8 @@ void I2C_init(void); */ bool I2C_readRegArray(const I2cDevice devId, const u8 regAddr, void *out, u32 size); +bool I2C_readArray(const I2cDevice devId, void *out, u32 size); + /** * @brief Writes an array of bytes to an array of registers via I2C. * diff --git a/include/arm11/drivers/n3ds_exthid.h b/include/arm11/drivers/n3ds_exthid.h new file mode 100644 index 0000000..507cbe4 --- /dev/null +++ b/include/arm11/drivers/n3ds_exthid.h @@ -0,0 +1,50 @@ +#pragma once + +/* + * This file is part of open_agb_firm + * Copyright (C) 2024 EvansJahja + * + * 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 . + */ +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "types.h" + +enum N3DS_EXTHID_Button { + ZR = (1<<1), + ZL = (1<<2), +}; + +typedef struct +{ + u8 _status; + enum N3DS_EXTHID_Button button; + s8 cstick_y_coarse; + s8 cstick_x_coarse; + u8 _ignored; + s8 cstick_y_fine; + s8 cstick_x_fine; + +} N3DS_EXTHID; + +void N3DS_EXTHID_Poll(void); + +N3DS_EXTHID* N3DS_EXTHID_GetDevice(void); + +#ifdef __cplusplus +} // extern "C" +#endif \ No newline at end of file diff --git a/source/arm11/drivers/hid.c b/source/arm11/drivers/hid.c index cb67f3c..ee2f508 100644 --- a/source/arm11/drivers/hid.c +++ b/source/arm11/drivers/hid.c @@ -27,7 +27,9 @@ #include "arm11/drivers/interrupt.h" #include "arm11/drivers/gpio.h" #include "arm11/drivers/codec.h" +#include "arm11/drivers/n3ds_exthid.h" +#include "arm11/fmt.h" #define MCU_HID_IRQ_MASK (MCU_IRQ_VOL_SLIDER_CHANGE | MCU_IRQ_BATT_CHARGE_START | \ MCU_IRQ_BATT_CHARGE_STOP | MCU_IRQ_SHELL_OPEN | \ @@ -36,15 +38,31 @@ MCU_IRQ_POWER_HELD | MCU_IRQ_POWER_PRESS) #define CPAD_THRESHOLD (400) - +#define CSTICK_THRESHOLD (3) static u32 g_kHeld = 0, g_kDown = 0, g_kUp = 0; static u32 g_extraKeys = 0; +static bool g_useN3DSEXTHID = false; TouchPos g_tPos = {0}; CpadPos g_cPos = {0}; +bool hasN3DSEXTHID(void) +{ + McuSysModel model = MCU_getSystemModel(); + switch(model) + { + case SYS_MODEL_N2DS_XL: + case SYS_MODEL_N3DS: + case SYS_MODEL_N3DS_XL: + return true; + + default: + return false; + } +} + void hidInit(void) { static bool inited = false; @@ -58,7 +76,7 @@ void hidInit(void) state = MCU_getEarlyButtonsHeld(); tmp |= ~state<<1 & KEY_HOME; // Current HOME button state g_extraKeys = tmp; - + g_useN3DSEXTHID = hasN3DSEXTHID(); CODEC_init(); } @@ -111,12 +129,35 @@ static u32 rawCodec2Hid(void) return fakeKeys; } +u32 N3DS_EXTHIDToHid(void) +{ + u32 key = 0; + N3DS_EXTHID* dev = N3DS_EXTHID_GetDevice(); + + key |= (dev->button & ZL) ? KEY_ZL : 0; + key |= (dev->button & ZR) ? KEY_ZR : 0; + + if (dev->cstick_y_coarse >= CSTICK_THRESHOLD) key |= KEY_CSTICK_UP; + if (dev->cstick_y_coarse <= -CSTICK_THRESHOLD) key |= KEY_CSTICK_DOWN; + if (dev->cstick_x_coarse >= CSTICK_THRESHOLD) key |= KEY_CSTICK_LEFT; + if (dev->cstick_x_coarse <= -CSTICK_THRESHOLD) key |= KEY_CSTICK_RIGHT; + + return key; +} + void hidScanInput(void) { updateMcuHidState(); const u32 kOld = g_kHeld; g_kHeld = rawCodec2Hid() | REG_HID_PAD; + + + if (g_useN3DSEXTHID) { + N3DS_EXTHID_Poll(); + g_kHeld |= N3DS_EXTHIDToHid(); + } + g_kDown = (~kOld) & g_kHeld; g_kUp = kOld & (~g_kHeld); } diff --git a/source/arm11/drivers/i2c.c b/source/arm11/drivers/i2c.c index f5b662e..618a48d 100644 --- a/source/arm11/drivers/i2c.c +++ b/source/arm11/drivers/i2c.c @@ -144,6 +144,41 @@ static bool startTransfer(const u8 devAddr, const u8 regAddr, const bool read, c return tries > 0; } +static bool startTransfer_no_reg(const u8 devAddr, const bool read, const I2cState *const state) +{ + u32 tries = 8; + I2cBus *const i2cBus = state->i2cBus; + const KHandle event = state->event; + do + { + // Edge case on previous transfer error (NACK). + // This is a special case where we can't predict when or if + // the IRQ has fired. If it fires after checking but + // before a wfi this would hang. + if(i2cBus->cnt & I2C_EN) waitForEvent(event); + clearEvent(event); + + // Select device and start. + sendByte(i2cBus, devAddr, I2C_START, event); + if(!checkAck(i2cBus)) continue; + + // Select register. + // sendByte(i2cBus, regAddr, 0, event); + // if(!checkAck(i2cBus)) continue; + + // Select device in read mode for read transfer. + if(read) + { + sendByte(i2cBus, devAddr | 1u, I2C_START, event); + if(!checkAck(i2cBus)) continue; + } + + break; + } while(--tries > 0); + + return tries > 0; +} + bool I2C_readRegArray(const I2cDevice devId, const u8 regAddr, void *out, u32 size) { const u8 devAddr = g_i2cDevTable[devId].devAddr; @@ -169,6 +204,31 @@ bool I2C_readRegArray(const I2cDevice devId, const u8 regAddr, void *out, u32 si return res; } +bool I2C_readArray(const I2cDevice devId, void *out, u32 size) +{ + const u8 devAddr = g_i2cDevTable[devId].devAddr; + const I2cState *const state = &g_i2cState[g_i2cDevTable[devId].busId]; + I2cBus *const i2cBus = state->i2cBus; + const KHandle event = state->event; + const KHandle mutex = state->mutex; + u8 *ptr8 = out; + + + bool res = true; + lockMutex(mutex); + if(startTransfer_no_reg(devAddr, true, state)) + { + while(--size) *ptr8++ = recvByte(i2cBus, I2C_ACK, event); + + // Last byte transfer. + *ptr8 = recvByte(i2cBus, I2C_STOP, event); + } + else res = false; + unlockMutex(mutex); + + return res; +} + bool I2C_writeRegArray(const I2cDevice devId, const u8 regAddr, const void *in, u32 size) { const u8 devAddr = g_i2cDevTable[devId].devAddr; diff --git a/source/arm11/drivers/n3ds_exthid.c b/source/arm11/drivers/n3ds_exthid.c new file mode 100644 index 0000000..ea97bee --- /dev/null +++ b/source/arm11/drivers/n3ds_exthid.c @@ -0,0 +1,14 @@ +#include "arm11/drivers/n3ds_exthid.h" +#include "arm11/drivers/i2c.h" + +static N3DS_EXTHID device; + +void N3DS_EXTHID_Poll(void) +{ + I2C_readArray(I2C_DEV_N3DS_HID, &device, sizeof device); +} + +N3DS_EXTHID* N3DS_EXTHID_GetDevice(void) +{ + return &device; +} \ No newline at end of file