diff --git a/Makefile b/Makefile index a000f12..e975133 100644 --- a/Makefile +++ b/Makefile @@ -16,7 +16,7 @@ TOPDIR ?= $(CURDIR) APP_NAME := DRXUtil APP_SHORTNAME := DRXUtil APP_AUTHOR := GaryOderNichts -APP_VERSION := 1.0 +APP_VERSION := 1.1 include $(DEVKITPRO)/wut/share/wut_rules diff --git a/source/screens/EnableDKMenuScreen.cpp b/source/screens/EnableDKMenuScreen.cpp new file mode 100644 index 0000000..0f478ba --- /dev/null +++ b/source/screens/EnableDKMenuScreen.cpp @@ -0,0 +1,184 @@ +#include "EnableDKMenuScreen.hpp" +#include "Utils.hpp" +#include "Gfx.hpp" + +#include +#include + +namespace { + +bool SetBoardConfig(uint8_t byte) +{ + CCRCDCUicConfig cfg{}; + // custom config id which was added by the gamepad cfw + cfg.configId = 4; + // board config byte + crc16 + cfg.size = 3; + cfg.data[0] = byte; + uint16_t crc = CCRCDCCalcCRC16(cfg.data, 1); + cfg.data[1] = crc & 0xff; + cfg.data[2] = (crc >> 8) & 0xff; + if (CCRCDCPerSetUicConfig(CCR_CDC_DESTINATION_DRC0, &cfg) != 0) { + return false; + } + + // Also update the cached eeprom + return CCRCFGSetCachedEeprom(0, 0x106, cfg.data, cfg.size) == 0; +} + +bool GetBoardConfig(uint8_t& boardConfig) +{ + uint8_t data[3]; + if (CCRCFGGetCachedEeprom(0, 0x106, data, 3) != 0) { + return false; + } + + uint16_t crc = (uint16_t) data[2] << 8 | data[1]; + if (CCRCDCCalcCRC16(&data[0], 1) != crc) { + return false; + } + + boardConfig = data[0]; + return true; +} + +} + +EnableDKMenuScreen::EnableDKMenuScreen() + : mConfirm(false), + mBoardConfig(0), + mDKMenuEnabled(false), + mErrorText() +{ +} + +EnableDKMenuScreen::~EnableDKMenuScreen() +{ +} + +void EnableDKMenuScreen::Draw() +{ + DrawTopBar("EnableDKMenuScreen"); + + switch (mState) + { + case STATE_GET_BOARD_CONFIG: + Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Retrieving board config...", Gfx::ALIGN_CENTER); + break; + case STATE_SELECT: + Gfx::Print(Gfx::SCREEN_WIDTH / 2, 128, 64, Gfx::COLOR_TEXT, + Utils::sprintf("DK Menu is currently %s.\nDo you want to %s it?", + mDKMenuEnabled ? "enabled" : "disabled", + mDKMenuEnabled ? "disable" : "enable"), + Gfx::ALIGN_HORIZONTAL | Gfx::ALIGN_TOP); + for (int i = 0; i < 2; i++) { + int yOff = 360 + static_cast(i) * 100; + Gfx::DrawRectFilled(0, yOff, Gfx::SCREEN_WIDTH, 100, Gfx::COLOR_ALT_BACKGROUND); + Gfx::Print(68, yOff + 100 / 2, 50, Gfx::COLOR_TEXT, i == 0 ? "Back" : (mDKMenuEnabled ? "Disable" : "Enable"), Gfx::ALIGN_VERTICAL); + + if (mConfirm == !!i) { + Gfx::DrawRect(0, yOff, Gfx::SCREEN_WIDTH, 100, 8, Gfx::COLOR_HIGHLIGHTED); + } + } + break; + case STATE_CONFIRM: + Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, + Utils::sprintf("Are you sure you want to %s the DK Menu?\n" + "(Note that updating the board config\nonly works with a modified firmware)", + mDKMenuEnabled ? "disable" : "enable"), Gfx::ALIGN_CENTER); + break; + case STATE_UPDATE: + Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Updating board config...", Gfx::ALIGN_CENTER); + break; + case STATE_DONE: + Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, + Utils::sprintf("Done! DK Menu has been %s.\n%s", + mDKMenuEnabled ? "disabled" : "enabled", + mDKMenuEnabled ? "" : "(Hold L + ZL while powering on the Gamepad to open.)"), + Gfx::ALIGN_CENTER); + break; + case STATE_ERROR: + Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR, "Error!\n" + mErrorText, Gfx::ALIGN_CENTER); + break; + } + + if (mState == STATE_SELECT) { + DrawBottomBar("\ue07d Navigate", "\ue044 Exit", "\ue000 Confirm / \ue001 Back"); + } else if (mState == STATE_CONFIRM) { + DrawBottomBar(nullptr, "\ue044 Exit", "\ue000 Confirm / \ue001 Back"); + } else if (mState == STATE_UPDATE || mState == STATE_GET_BOARD_CONFIG) { + DrawBottomBar(nullptr, "Please wait...", nullptr); + } else { + DrawBottomBar(nullptr, "\ue044 Exit", "\ue001 Back"); + } +} + +bool EnableDKMenuScreen::Update(VPADStatus& input) +{ + switch (mState) + { + case STATE_GET_BOARD_CONFIG: + if (!GetBoardConfig(mBoardConfig)) { + mErrorText = "Failed to retrieve current board configuration."; + mState = STATE_ERROR; + break; + } + mDKMenuEnabled = (mBoardConfig & 0x0C) == 0; + mState = STATE_SELECT; + break; + case STATE_SELECT: + if (input.trigger & VPAD_BUTTON_B) { + return false; + } + + if (input.trigger & VPAD_BUTTON_A) { + if (mConfirm) { + mState = STATE_CONFIRM; + } else { + return false; + } + break; + } + + if (input.trigger & (VPAD_BUTTON_DOWN | VPAD_BUTTON_UP)) { + mConfirm = !mConfirm; + } + break; + case STATE_CONFIRM: + if (input.trigger & VPAD_BUTTON_B) { + return false; + } + + if (input.trigger & VPAD_BUTTON_A) { + mState = STATE_UPDATE; + break; + } + break; + case STATE_UPDATE: { + uint8_t newBoardConfig = mBoardConfig; + // Clear/Set the is retail bits + if (mDKMenuEnabled) { + newBoardConfig |= 0x04; + } else { + newBoardConfig &= ~0x0C; + } + + if (!SetBoardConfig(newBoardConfig)) { + mErrorText = "Failed to set board config.\n(Is the firmware modified properly?)"; + mState = STATE_ERROR; + break; + } + + mState = STATE_DONE; + break; + } + case STATE_DONE: + case STATE_ERROR: + if (input.trigger & VPAD_BUTTON_B) { + return false; + } + break; + } + + return true; +} diff --git a/source/screens/EnableDKMenuScreen.hpp b/source/screens/EnableDKMenuScreen.hpp new file mode 100644 index 0000000..c10439f --- /dev/null +++ b/source/screens/EnableDKMenuScreen.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include "Screen.hpp" +#include +#include + +class EnableDKMenuScreen : public Screen +{ +public: + EnableDKMenuScreen(); + virtual ~EnableDKMenuScreen(); + + void Draw(); + + bool Update(VPADStatus& input); + +private: + enum State { + STATE_GET_BOARD_CONFIG, + STATE_SELECT, + STATE_CONFIRM, + STATE_UPDATE, + STATE_DONE, + STATE_ERROR, + } mState = STATE_GET_BOARD_CONFIG; + + bool mConfirm; + uint8_t mBoardConfig; + bool mDKMenuEnabled; + std::string mErrorText; +}; diff --git a/source/screens/MenuScreen.cpp b/source/screens/MenuScreen.cpp index e2789ef..f1f502a 100644 --- a/source/screens/MenuScreen.cpp +++ b/source/screens/MenuScreen.cpp @@ -4,16 +4,18 @@ #include "FlashScreen.hpp" #include "InfoScreen.hpp" #include "SetRegionScreen.hpp" +#include "EnableDKMenuScreen.hpp" #include MenuScreen::MenuScreen() : mEntries({ - { MENU_ID_INFO, { 0xf085, "Show DRC/DRH information" }}, - { MENU_ID_FLASH, { 0xf1c9, "Flash firmware" }}, - { MENU_ID_SET_REGION, { 0xf0ac, "Set region" }}, - { MENU_ID_ABOUT, { 0xf05a, "About DRXUtil" }}, - // { MENU_ID_EXIT, { 0xf057, "Exit" }}, + { MENU_ID_INFO, { 0xf085, "Show DRC/DRH information" }}, + { MENU_ID_FLASH, { 0xf1c9, "Flash firmware" }}, + { MENU_ID_SET_REGION, { 0xf0ac, "Set region" }}, + { MENU_ID_ENABLE_DKMENU, { 0xf188, "Enable DK Menu" }}, + { MENU_ID_ABOUT, { 0xf05a, "About DRXUtil" }}, + // { MENU_ID_EXIT, { 0xf057, "Exit" }}, }) { @@ -78,6 +80,9 @@ bool MenuScreen::Update(VPADStatus& input) case MENU_ID_SET_REGION: mSubscreen = std::make_unique(); break; + case MENU_ID_ENABLE_DKMENU: + mSubscreen = std::make_unique(); + break; case MENU_ID_ABOUT: mSubscreen = std::make_unique(); break; diff --git a/source/screens/MenuScreen.hpp b/source/screens/MenuScreen.hpp index b89923d..9b3ac46 100644 --- a/source/screens/MenuScreen.hpp +++ b/source/screens/MenuScreen.hpp @@ -21,6 +21,7 @@ private: MENU_ID_INFO, MENU_ID_FLASH, MENU_ID_SET_REGION, + MENU_ID_ENABLE_DKMENU, MENU_ID_ABOUT, MENU_ID_MIN = MENU_ID_INFO, diff --git a/source/screens/SetRegionScreen.hpp b/source/screens/SetRegionScreen.hpp index 69b05e4..46861ed 100644 --- a/source/screens/SetRegionScreen.hpp +++ b/source/screens/SetRegionScreen.hpp @@ -34,6 +34,4 @@ private: REGION_AUSTRALIA = 6, } mRegion = REGION_JAPAN; std::map mRegionEntries; - - std::string mErrorText; };