Improved the waitInput function basing on code from @d0k3, added support for the power button, added possibiity to quit the payload loader menu with START
This commit is contained in:
parent
6d3113c8c3
commit
c83edea7ad
@ -39,9 +39,9 @@
|
|||||||
#define BUTTON_UP (1 << 6)
|
#define BUTTON_UP (1 << 6)
|
||||||
#define BUTTON_DOWN (1 << 7)
|
#define BUTTON_DOWN (1 << 7)
|
||||||
|
|
||||||
|
#define DPAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
|
||||||
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
|
||||||
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_B | BUTTON_X | BUTTON_Y)
|
#define SINGLE_PAYLOAD_BUTTONS (DPAD_BUTTONS | BUTTON_B | BUTTON_X | BUTTON_Y)
|
||||||
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT)
|
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_START | BUTTON_SELECT)
|
||||||
#define EMUNAND_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
|
#define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START)
|
||||||
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
|
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START)
|
||||||
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START)
|
|
@ -239,12 +239,12 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString(CONFIG_TITLE, true, 10, 10, COLOR_TITLE);
|
drawString(CONFIG_TITLE, true, 10, 10, COLOR_TITLE);
|
||||||
drawString("Press A to select, START to save", true, 10, 30, COLOR_WHITE);
|
drawString("Press A to select, START to save", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
||||||
|
|
||||||
//Character to display a selected option
|
//Character to display a selected option
|
||||||
char selected = 'x';
|
char selected = 'x';
|
||||||
|
|
||||||
u32 endPos = 42;
|
u32 endPos = 10 + 2 * SPACING_Y;
|
||||||
|
|
||||||
//Display all the multiple choice options in white
|
//Display all the multiple choice options in white
|
||||||
for(u32 i = 0; i < multiOptionsAmount; i++)
|
for(u32 i = 0; i < multiOptionsAmount; i++)
|
||||||
@ -286,7 +286,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pressed = waitInput();
|
pressed = waitInput(true);
|
||||||
}
|
}
|
||||||
while(!(pressed & MENU_BUTTONS));
|
while(!(pressed & MENU_BUTTONS));
|
||||||
|
|
||||||
@ -394,8 +394,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
|
|||||||
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
|
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
|
||||||
else if(oldPinStatus) fileDelete(PIN_FILE);
|
else if(oldPinStatus) fileDelete(PIN_FILE);
|
||||||
|
|
||||||
//Wait for the pressed buttons to change
|
|
||||||
while(HID_PAD & PIN_BUTTONS);
|
while(HID_PAD & PIN_BUTTONS);
|
||||||
|
startChrono();
|
||||||
chrono(2);
|
while(chrono(false) < 2);
|
||||||
}
|
}
|
@ -56,7 +56,8 @@ bool loadSplash(void)
|
|||||||
{
|
{
|
||||||
swapFramebuffers(true);
|
swapFramebuffers(true);
|
||||||
|
|
||||||
chrono(3);
|
startChrono();
|
||||||
|
while(chrono(false) < 3);
|
||||||
|
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +204,7 @@ void detectAndProcessExceptionDumps(void)
|
|||||||
|
|
||||||
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
|
||||||
|
|
||||||
waitInput();
|
waitInput(false);
|
||||||
mcuPowerOff();
|
mcuPowerOff();
|
||||||
}
|
}
|
||||||
}
|
}
|
34
source/fs.c
34
source/fs.c
@ -196,9 +196,9 @@ void payloadMenu(void)
|
|||||||
{
|
{
|
||||||
FILINFO info;
|
FILINFO info;
|
||||||
u32 payloadNum = 0;
|
u32 payloadNum = 0;
|
||||||
char payloadList[21][49];
|
char payloadList[20][49];
|
||||||
|
|
||||||
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 21)
|
while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0 && payloadNum < 20)
|
||||||
if(info.fname[0] != '.' && memcmp(info.altname + 8, ".BIN", 4) == 0)
|
if(info.fname[0] != '.' && memcmp(info.altname + 8, ".BIN", 4) == 0)
|
||||||
{
|
{
|
||||||
u32 nameLength = strlen(info.fname) - 4;
|
u32 nameLength = strlen(info.fname) - 4;
|
||||||
@ -216,9 +216,10 @@ void payloadMenu(void)
|
|||||||
{
|
{
|
||||||
initScreens();
|
initScreens();
|
||||||
|
|
||||||
drawString("Luma3DS chainloader - Press A to select", true, 10, 10, COLOR_TITLE);
|
drawString("Luma3DS chainloader", true, 10, 10, COLOR_TITLE);
|
||||||
|
drawString("Press A to select, START to quit", true, 10, 10 + SPACING_Y, COLOR_TITLE);
|
||||||
|
|
||||||
for(u32 i = 0, posY = 30, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y)
|
for(u32 i = 0, posY = 10 + 3 * SPACING_Y, color = COLOR_RED; i < payloadNum; i++, posY += SPACING_Y)
|
||||||
{
|
{
|
||||||
drawString(payloadList[i], true, 10, posY, color);
|
drawString(payloadList[i], true, 10, posY, color);
|
||||||
if(color == COLOR_RED) color = COLOR_WHITE;
|
if(color == COLOR_RED) color = COLOR_WHITE;
|
||||||
@ -227,11 +228,11 @@ void payloadMenu(void)
|
|||||||
u32 pressed = 0,
|
u32 pressed = 0,
|
||||||
selectedPayload = 0;
|
selectedPayload = 0;
|
||||||
|
|
||||||
while(pressed != BUTTON_A)
|
while(!(pressed & (BUTTON_A | BUTTON_START)))
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pressed = waitInput();
|
pressed = waitInput(true);
|
||||||
}
|
}
|
||||||
while(!(pressed & MENU_BUTTONS));
|
while(!(pressed & MENU_BUTTONS));
|
||||||
|
|
||||||
@ -257,15 +258,22 @@ void payloadMenu(void)
|
|||||||
|
|
||||||
if(oldSelectedPayload == selectedPayload) continue;
|
if(oldSelectedPayload == selectedPayload) continue;
|
||||||
|
|
||||||
drawString(payloadList[oldSelectedPayload], true, 10, 30 + oldSelectedPayload * SPACING_Y, COLOR_WHITE);
|
drawString(payloadList[oldSelectedPayload], true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE);
|
||||||
drawString(payloadList[selectedPayload], true, 10, 30 + selectedPayload * SPACING_Y, COLOR_RED);
|
drawString(payloadList[selectedPayload], true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED);
|
||||||
}
|
}
|
||||||
|
|
||||||
concatenateStrings(path, "/");
|
if(pressed == BUTTON_A)
|
||||||
concatenateStrings(path, payloadList[selectedPayload]);
|
{
|
||||||
concatenateStrings(path, ".bin");
|
concatenateStrings(path, "/");
|
||||||
loadPayload(0, path);
|
concatenateStrings(path, payloadList[selectedPayload]);
|
||||||
error("The payload is too large or corrupted.");
|
concatenateStrings(path, ".bin");
|
||||||
|
loadPayload(0, path);
|
||||||
|
error("The payload is too large or corrupted.");
|
||||||
|
}
|
||||||
|
|
||||||
|
while(HID_PAD & MENU_BUTTONS);
|
||||||
|
startChrono();
|
||||||
|
while(chrono(false) < 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
source/i2c.c
25
source/i2c.c
@ -115,6 +115,31 @@ static bool i2cSelectRegister(u8 bus_id, u8 reg)
|
|||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
u8 i2cReadRegister(u8 dev_id, u8 reg)
|
||||||
|
{
|
||||||
|
u8 bus_id = i2cGetDeviceBusId(dev_id),
|
||||||
|
dev_addr = i2cGetDeviceRegAddr(dev_id);
|
||||||
|
|
||||||
|
for(u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
|
||||||
|
{
|
||||||
|
if(i2cSelectDevice(bus_id, dev_addr | 1))
|
||||||
|
{
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
i2cStop(bus_id, 1);
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
|
||||||
|
return *i2cGetDataReg(bus_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*i2cGetCntReg(bus_id) = 0xC5;
|
||||||
|
i2cWaitBusy(bus_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
|
||||||
{
|
{
|
||||||
u8 bus_id = i2cGetDeviceBusId(dev_id),
|
u8 bus_id = i2cGetDeviceBusId(dev_id),
|
||||||
|
@ -41,4 +41,5 @@
|
|||||||
#define I2C_DEV_GYRO 10
|
#define I2C_DEV_GYRO 10
|
||||||
#define I2C_DEV_IR 13
|
#define I2C_DEV_IR 13
|
||||||
|
|
||||||
|
u8 i2cReadRegister(u8 dev_id, u8 reg);
|
||||||
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
|
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
|
@ -148,7 +148,8 @@ void main(void)
|
|||||||
if(pinExists && !shouldLoadConfigMenu)
|
if(pinExists && !shouldLoadConfigMenu)
|
||||||
{
|
{
|
||||||
while(HID_PAD & PIN_BUTTONS);
|
while(HID_PAD & PIN_BUTTONS);
|
||||||
chrono(2);
|
startChrono();
|
||||||
|
while(chrono(false) < 2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -157,10 +158,11 @@ void main(void)
|
|||||||
|
|
||||||
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
|
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
|
||||||
|
|
||||||
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START) payloadMenu();
|
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
|
||||||
|
{
|
||||||
/* If L and R/A/Select or one of the single payload buttons are pressed,
|
payloadMenu();
|
||||||
chainload an external payload */
|
pressed = HID_PAD;
|
||||||
|
}
|
||||||
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
|
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
|
||||||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
|
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
|
||||||
|
|
||||||
@ -192,7 +194,7 @@ void main(void)
|
|||||||
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
|
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
|
||||||
{
|
{
|
||||||
FirmwareSource tempNand;
|
FirmwareSource tempNand;
|
||||||
switch(pressed & EMUNAND_BUTTONS)
|
switch(pressed & DPAD_BUTTONS)
|
||||||
{
|
{
|
||||||
case BUTTON_UP:
|
case BUTTON_UP:
|
||||||
tempNand = FIRMWARE_EMUNAND;
|
tempNand = FIRMWARE_EMUNAND;
|
||||||
|
@ -66,7 +66,7 @@ void newPin(bool allowSkipping, u32 pinMode)
|
|||||||
u32 pressed;
|
u32 pressed;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pressed = waitInput();
|
pressed = waitInput(false);
|
||||||
}
|
}
|
||||||
while(!(pressed & PIN_BUTTONS));
|
while(!(pressed & PIN_BUTTONS));
|
||||||
|
|
||||||
@ -156,7 +156,7 @@ bool verifyPin(u32 pinMode)
|
|||||||
u32 pressed;
|
u32 pressed;
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
pressed = waitInput();
|
pressed = waitInput(false);
|
||||||
}
|
}
|
||||||
while(!(pressed & PIN_BUTTONS));
|
while(!(pressed & PIN_BUTTONS));
|
||||||
|
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
* Notices displayed by works containing it.
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c
|
||||||
|
*/
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "i2c.h"
|
#include "i2c.h"
|
||||||
#include "buttons.h"
|
#include "buttons.h"
|
||||||
@ -27,29 +31,37 @@
|
|||||||
#include "draw.h"
|
#include "draw.h"
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
|
||||||
u32 waitInput(void)
|
u32 waitInput(bool isMenu)
|
||||||
{
|
{
|
||||||
|
static u64 dPadDelay = 0;
|
||||||
bool pressedKey = false;
|
bool pressedKey = false;
|
||||||
u32 key;
|
u32 key,
|
||||||
|
oldKey = HID_PAD;
|
||||||
|
|
||||||
//Wait for no keys to be pressed
|
if(isMenu)
|
||||||
while(HID_PAD);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
{
|
||||||
//Wait for a key to be pressed
|
dPadDelay = dPadDelay > 0 ? 87 : 143;
|
||||||
while(!HID_PAD);
|
startChrono();
|
||||||
|
}
|
||||||
|
|
||||||
|
while(!pressedKey)
|
||||||
|
{
|
||||||
key = HID_PAD;
|
key = HID_PAD;
|
||||||
|
|
||||||
//Make sure it's pressed
|
if(!key)
|
||||||
for(u32 i = 0x13000; i > 0; i--)
|
|
||||||
{
|
{
|
||||||
if(key != HID_PAD) break;
|
if(i2cReadRegister(I2C_DEV_MCU, 0x10) == 1) mcuPowerOff();
|
||||||
if(i == 1) pressedKey = true;
|
oldKey = key;
|
||||||
|
dPadDelay = 0;
|
||||||
|
}
|
||||||
|
else if((key != oldKey) || (isMenu && (key & DPAD_BUTTONS) != 0 && (chrono(true) >= dPadDelay)))
|
||||||
|
{
|
||||||
|
//Make sure the key is pressed
|
||||||
|
u32 i;
|
||||||
|
for(i = 0; i < 0x13000 && key == HID_PAD; i++);
|
||||||
|
if(i == 0x13000) pressedKey = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(!pressedKey);
|
|
||||||
|
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
@ -65,38 +77,26 @@ void mcuPowerOff(void)
|
|||||||
while(true);
|
while(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void startChrono(u64 initialTicks)
|
void startChrono(void)
|
||||||
{
|
{
|
||||||
REG_TIMER_CNT(0) = 0; //67MHz
|
REG_TIMER_CNT(0) = 0; //67MHz
|
||||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
|
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 4; //Count-up
|
||||||
|
|
||||||
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = (u16)(initialTicks >> (16 * i));
|
for(u32 i = 0; i < 4; i++) REG_TIMER_VAL(i) = 0;
|
||||||
|
|
||||||
REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
|
REG_TIMER_CNT(0) = 0x80; //67MHz; enabled
|
||||||
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
for(u32 i = 1; i < 4; i++) REG_TIMER_CNT(i) = 0x84; //Count-up; enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void stopChrono(void)
|
u64 chrono(bool isMilliseconds)
|
||||||
{
|
{
|
||||||
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
|
|
||||||
}
|
|
||||||
|
|
||||||
void chrono(u32 seconds)
|
|
||||||
{
|
|
||||||
startChrono(0);
|
|
||||||
|
|
||||||
u64 startingTicks = 0;
|
|
||||||
for(u32 i = 0; i < 4; i++) startingTicks |= REG_TIMER_VAL(i) << (16 * i);
|
|
||||||
|
|
||||||
u64 res;
|
u64 res;
|
||||||
do
|
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
|
||||||
{
|
|
||||||
res = 0;
|
|
||||||
for(u32 i = 0; i < 4; i++) res |= REG_TIMER_VAL(i) << (16 * i);
|
|
||||||
}
|
|
||||||
while(res - startingTicks < seconds * TICKS_PER_SEC);
|
|
||||||
|
|
||||||
stopChrono();
|
if(isMilliseconds) res /= (TICKS_PER_SEC / 1000);
|
||||||
|
else res /= TICKS_PER_SEC;
|
||||||
|
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(const char *message)
|
void error(const char *message)
|
||||||
@ -109,7 +109,7 @@ void error(const char *message)
|
|||||||
u32 posY = drawString(message, true, 10, 30, COLOR_WHITE);
|
u32 posY = drawString(message, true, 10, 30, COLOR_WHITE);
|
||||||
drawString("Press any button to shutdown", true, 10, posY + 2 * SPACING_Y, COLOR_WHITE);
|
drawString("Press any button to shutdown", true, 10, posY + 2 * SPACING_Y, COLOR_WHITE);
|
||||||
|
|
||||||
waitInput();
|
waitInput(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
mcuPowerOff();
|
mcuPowerOff();
|
||||||
|
@ -20,6 +20,10 @@
|
|||||||
* Notices displayed by works containing it.
|
* Notices displayed by works containing it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* waitInput function based on code by d0k3 https://github.com/d0k3/Decrypt9WIP/blob/master/source/hid.c
|
||||||
|
*/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
@ -28,7 +32,8 @@
|
|||||||
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
|
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
|
||||||
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
|
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
|
||||||
|
|
||||||
u32 waitInput(void);
|
u32 waitInput(bool isMenu);
|
||||||
void mcuPowerOff(void);
|
void mcuPowerOff(void);
|
||||||
void chrono(u32 seconds);
|
void startChrono(void);
|
||||||
|
u64 chrono(bool isMilliseconds);
|
||||||
void error(const char *message);
|
void error(const char *message);
|
Reference in New Issue
Block a user