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:
Aurora 2016-11-13 22:13:24 +01:00
parent 6d3113c8c3
commit c83edea7ad
11 changed files with 110 additions and 69 deletions

View File

@ -39,9 +39,9 @@
#define BUTTON_UP (1 << 6)
#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 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 EMUNAND_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN)
#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 | BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START)
#define MENU_BUTTONS (DPAD_BUTTONS | BUTTON_A | BUTTON_START)
#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | DPAD_BUTTONS | BUTTON_START)

View File

@ -239,12 +239,12 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
initScreens();
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
char selected = 'x';
u32 endPos = 42;
u32 endPos = 10 + 2 * SPACING_Y;
//Display all the multiple choice options in white
for(u32 i = 0; i < multiOptionsAmount; i++)
@ -286,7 +286,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
{
do
{
pressed = waitInput();
pressed = waitInput(true);
}
while(!(pressed & MENU_BUTTONS));
@ -394,8 +394,7 @@ void configMenu(bool isSdMode, bool oldPinStatus, u32 oldPinMode)
if(newPinMode != 0) newPin(oldPinStatus && newPinMode == oldPinMode, newPinMode);
else if(oldPinStatus) fileDelete(PIN_FILE);
//Wait for the pressed buttons to change
while(HID_PAD & PIN_BUTTONS);
chrono(2);
startChrono();
while(chrono(false) < 2);
}

View File

@ -56,7 +56,8 @@ bool loadSplash(void)
{
swapFramebuffers(true);
chrono(3);
startChrono();
while(chrono(false) < 3);
ret = true;
}

View File

@ -204,7 +204,7 @@ void detectAndProcessExceptionDumps(void)
memset32((void *)dumpHeader, 0, dumpHeader->totalSize);
waitInput();
waitInput(false);
mcuPowerOff();
}
}

View File

@ -196,9 +196,9 @@ void payloadMenu(void)
{
FILINFO info;
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)
{
u32 nameLength = strlen(info.fname) - 4;
@ -216,9 +216,10 @@ void payloadMenu(void)
{
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);
if(color == COLOR_RED) color = COLOR_WHITE;
@ -227,11 +228,11 @@ void payloadMenu(void)
u32 pressed = 0,
selectedPayload = 0;
while(pressed != BUTTON_A)
while(!(pressed & (BUTTON_A | BUTTON_START)))
{
do
{
pressed = waitInput();
pressed = waitInput(true);
}
while(!(pressed & MENU_BUTTONS));
@ -257,16 +258,23 @@ void payloadMenu(void)
if(oldSelectedPayload == selectedPayload) continue;
drawString(payloadList[oldSelectedPayload], true, 10, 30 + oldSelectedPayload * SPACING_Y, COLOR_WHITE);
drawString(payloadList[selectedPayload], true, 10, 30 + selectedPayload * SPACING_Y, COLOR_RED);
drawString(payloadList[oldSelectedPayload], true, 10, 10 + (3 + oldSelectedPayload) * SPACING_Y, COLOR_WHITE);
drawString(payloadList[selectedPayload], true, 10, 10 + (3 + selectedPayload) * SPACING_Y, COLOR_RED);
}
if(pressed == BUTTON_A)
{
concatenateStrings(path, "/");
concatenateStrings(path, payloadList[selectedPayload]);
concatenateStrings(path, ".bin");
loadPayload(0, path);
error("The payload is too large or corrupted.");
}
while(HID_PAD & MENU_BUTTONS);
startChrono();
while(chrono(false) < 2);
}
}
}

View File

@ -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)
{
u8 bus_id = i2cGetDeviceBusId(dev_id),

View File

@ -41,4 +41,5 @@
#define I2C_DEV_GYRO 10
#define I2C_DEV_IR 13
u8 i2cReadRegister(u8 dev_id, u8 reg);
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);

View File

@ -148,7 +148,8 @@ void main(void)
if(pinExists && !shouldLoadConfigMenu)
{
while(HID_PAD & PIN_BUTTONS);
chrono(2);
startChrono();
while(chrono(false) < 2);
}
}
else
@ -157,10 +158,11 @@ void main(void)
if(splashMode == 1 && loadSplash()) pressed = HID_PAD;
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START) payloadMenu();
/* If L and R/A/Select or one of the single payload buttons are pressed,
chainload an external payload */
if((pressed & (BUTTON_START | BUTTON_L1)) == BUTTON_START)
{
payloadMenu();
pressed = HID_PAD;
}
else if(((pressed & SINGLE_PAYLOAD_BUTTONS) && !(pressed & (BUTTON_L1 | BUTTON_R1 | BUTTON_A))) ||
((pressed & L_PAYLOAD_BUTTONS) && (pressed & BUTTON_L1))) loadPayload(pressed, NULL);
@ -192,7 +194,7 @@ void main(void)
if(nandType == FIRMWARE_EMUNAND || firmSource == FIRMWARE_EMUNAND)
{
FirmwareSource tempNand;
switch(pressed & EMUNAND_BUTTONS)
switch(pressed & DPAD_BUTTONS)
{
case BUTTON_UP:
tempNand = FIRMWARE_EMUNAND;

View File

@ -66,7 +66,7 @@ void newPin(bool allowSkipping, u32 pinMode)
u32 pressed;
do
{
pressed = waitInput();
pressed = waitInput(false);
}
while(!(pressed & PIN_BUTTONS));
@ -156,7 +156,7 @@ bool verifyPin(u32 pinMode)
u32 pressed;
do
{
pressed = waitInput();
pressed = waitInput(false);
}
while(!(pressed & PIN_BUTTONS));

View File

@ -20,6 +20,10 @@
* 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 "i2c.h"
#include "buttons.h"
@ -27,29 +31,37 @@
#include "draw.h"
#include "cache.h"
u32 waitInput(void)
u32 waitInput(bool isMenu)
{
static u64 dPadDelay = 0;
bool pressedKey = false;
u32 key;
u32 key,
oldKey = HID_PAD;
//Wait for no keys to be pressed
while(HID_PAD);
do
if(isMenu)
{
//Wait for a key to be pressed
while(!HID_PAD);
dPadDelay = dPadDelay > 0 ? 87 : 143;
startChrono();
}
while(!pressedKey)
{
key = HID_PAD;
//Make sure it's pressed
for(u32 i = 0x13000; i > 0; i--)
if(!key)
{
if(key != HID_PAD) break;
if(i == 1) pressedKey = true;
if(i2cReadRegister(I2C_DEV_MCU, 0x10) == 1) mcuPowerOff();
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;
}
@ -65,38 +77,26 @@ void mcuPowerOff(void)
while(true);
}
static inline void startChrono(u64 initialTicks)
void startChrono(void)
{
REG_TIMER_CNT(0) = 0; //67MHz
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
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;
do
{
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)
@ -109,7 +109,7 @@ void error(const char *message)
u32 posY = drawString(message, true, 10, 30, COLOR_WHITE);
drawString("Press any button to shutdown", true, 10, posY + 2 * SPACING_Y, COLOR_WHITE);
waitInput();
waitInput(false);
}
mcuPowerOff();

View File

@ -20,6 +20,10 @@
* 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
#include "types.h"
@ -28,7 +32,8 @@
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
u32 waitInput(void);
u32 waitInput(bool isMenu);
void mcuPowerOff(void);
void chrono(u32 seconds);
void startChrono(void);
u64 chrono(bool isMilliseconds);
void error(const char *message);