mirror of
https://github.com/GaryOderNichts/DRXUtil.git
synced 2025-03-01 19:35:21 +01:00
New functionality
This commit is contained in:
parent
fe99770abb
commit
609a314aba
4
Makefile
4
Makefile
@ -16,7 +16,7 @@ TOPDIR ?= $(CURDIR)
|
||||
APP_NAME := DRXUtil
|
||||
APP_SHORTNAME := DRXUtil
|
||||
APP_AUTHOR := GaryOderNichts
|
||||
APP_VERSION := 1.1
|
||||
APP_VERSION := 1.2
|
||||
|
||||
include $(DEVKITPRO)/wut/share/wut_rules
|
||||
|
||||
@ -37,7 +37,7 @@ SOURCES := source source/screens
|
||||
DATA := data
|
||||
INCLUDES := source include
|
||||
CONTENT :=
|
||||
ICON :=
|
||||
ICON :=
|
||||
TV_SPLASH :=
|
||||
DRC_SPLASH :=
|
||||
|
||||
|
284
source/screens/DrcFFlashScreen.cpp
Normal file
284
source/screens/DrcFFlashScreen.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
#include "DrcFFlashScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "ProcUI.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <nsysccr/cfg.h>
|
||||
#include <nn/ccr.h>
|
||||
|
||||
namespace {
|
||||
|
||||
void SoftwareUpdateCallback(IOSError error, void* arg)
|
||||
{
|
||||
DrcFFlashScreen* drcFFlashScreen = static_cast<DrcFFlashScreen*>(arg);
|
||||
|
||||
drcFFlashScreen->OnUpdateCompleted(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DrcFFlashScreen::~DrcFFlashScreen()
|
||||
{
|
||||
}
|
||||
|
||||
void DrcFFlashScreen::Draw()
|
||||
{
|
||||
DrawTopBar("DrcFFlashScreen");
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_PREPARE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Preparing...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_CONFIRM2: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR,
|
||||
Utils::sprintf("Are you really really really sure?\n"
|
||||
"About to flash all firmware.\n"
|
||||
"You may brick the DRC!!\n"),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_UPDATE_LANG:
|
||||
case STATE_UPDATE_FIRM: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Starting update...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING_LANG: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2 - 32, 64, Gfx::COLOR_TEXT, Utils::sprintf("Updating language... %d%% done.\nDo not turn the power off.", mFlashingProgress), Gfx::ALIGN_CENTER);
|
||||
Gfx::DrawRect(64, Gfx::SCREEN_HEIGHT / 2 + 80, Gfx::SCREEN_WIDTH - 128, 64, 5, Gfx::COLOR_ACCENT);
|
||||
Gfx::DrawRectFilled(64, Gfx::SCREEN_HEIGHT / 2 + 80, (Gfx::SCREEN_WIDTH - 128) * (mFlashingProgress / 100.0f), 64, Gfx::COLOR_ACCENT);
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING_FIRM: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2 - 32, 64, Gfx::COLOR_TEXT, Utils::sprintf("Updating firmware... %d%% done.\nDo not turn the power off.", mFlashingProgress), Gfx::ALIGN_CENTER);
|
||||
Gfx::DrawRect(64, Gfx::SCREEN_HEIGHT / 2 + 80, Gfx::SCREEN_WIDTH - 128, 64, 5, Gfx::COLOR_ACCENT);
|
||||
Gfx::DrawRectFilled(64, Gfx::SCREEN_HEIGHT / 2 + 80, (Gfx::SCREEN_WIDTH - 128) * (mFlashingProgress / 100.0f), 64, Gfx::COLOR_ACCENT);
|
||||
break;
|
||||
}
|
||||
case STATE_ACTIVATE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Activating update...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("Done!\n"
|
||||
"DRC was updated successfully."),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR, "Error:\n" + mErrorString, Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mState == STATE_CONFIRM2) {
|
||||
DrawBottomBar(nullptr, "\ue044 Exit", "\ue000 Confirm / \ue001 Back");
|
||||
} else if (mState == STATE_PREPARE || mState == STATE_UPDATE_FIRM || mState == STATE_UPDATE_LANG || mState == STATE_FLASHING_FIRM || mState == STATE_FLASHING_LANG || mState == STATE_ACTIVATE) {
|
||||
DrawBottomBar(nullptr, "Please wait...", nullptr);
|
||||
} else if (mState == STATE_DONE || mState == STATE_ERROR) {
|
||||
DrawBottomBar(nullptr, nullptr, "\ue001 Back");
|
||||
}
|
||||
}
|
||||
|
||||
bool DrcFFlashScreen::Update(VPADStatus& input) // Here is the core logic
|
||||
{
|
||||
flashUtils.ReadFirmwareHeader("/vol/external01/lang.bin", mLanguageHeader);
|
||||
uint32_t targetVersion = mLanguageHeader.version; // We will read this value later
|
||||
flashUtils.ReadFirmwareHeader("/vol/external01/drc_fw.bin", mFirmwareHeader);
|
||||
uint32_t firmwareVersion = mFirmwareHeader.version;
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_CONFIRM2: { // Ask the user before starting writes
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_A) {
|
||||
mState = STATE_UPDATE_LANG;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_PREPARE: { // When picked, copy firmware and language to MLC.
|
||||
if (!flashUtils.CheckVersionSafety(firmwareVersion, targetVersion)) {
|
||||
mErrorString = "Language version not valid for the DRC firmware!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
// Copy to MLC so IOS-PAD can install it
|
||||
mFirmwarePath = "/vol/storage_mlc01/usr/tmp/drc_fw.bin"; // copy firmware
|
||||
if (!flashUtils.CopyFile("/vol/external01/drc_fw.bin", "storage_mlc01:/usr/tmp/drc_fw.bin")) {
|
||||
mErrorString = "Failed to copy firmware to MLC";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mLangPath = "/vol/storage_mlc01/usr/tmp/lang.bin"; // copy language
|
||||
if (!flashUtils.CopyFile("/vol/external01/lang.bin", "storage_mlc01:/usr/tmp/lang.bin")) {
|
||||
mErrorString = "Failed to copy language to MLC";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mState = STATE_CONFIRM2; // ask user
|
||||
break;
|
||||
}
|
||||
case STATE_UPDATE_LANG: {
|
||||
ProcUI::SetHomeButtonMenuEnabled(false); // avoid funny situatuions
|
||||
|
||||
if (!flashUtils.CaffeineInvalidate()) {
|
||||
mErrorString = "Failed to invalidate caffeine.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// Abort any potential pending software updates
|
||||
CCRCDCSoftwareAbort(CCR_CDC_DESTINATION_DRC0); // avoid funny situations (this shouldnt matter afaict)
|
||||
|
||||
// Reattach the DRC in update mode
|
||||
if (!flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_FWUPDATE, FALSE)) {
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to reattach DRC in update mode.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mFlashingProgress = 0;
|
||||
mUpdateComplete = false;
|
||||
mUpdateResult = 0;
|
||||
if (CCRCDCSoftwareLangUpdate(CCR_CDC_DESTINATION_DRC0, mLangPath.c_str(), &targetVersion, SoftwareUpdateCallback, this) != 0) { // Flash language first because it's forgivable somewhat.
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to start language update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mState = STATE_FLASHING_LANG; // Track progress
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING_LANG: {
|
||||
// Update progress
|
||||
CCRCDCFWInfo fwInfo{};
|
||||
if (CCRCDCGetFWInfo(CCR_CDC_DESTINATION_DRC0, &fwInfo) == 0) {
|
||||
mFlashingProgress = fwInfo.updateProgress;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
|
||||
// Check if update complete
|
||||
if (mUpdateComplete) {
|
||||
if (mUpdateResult == IOS_ERROR_OK) {
|
||||
mState = STATE_UPDATE_FIRM;
|
||||
} else {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Software update failed.";
|
||||
mState = STATE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_UPDATE_FIRM: {
|
||||
ProcUI::SetHomeButtonMenuEnabled(false); // keep avoiding funnies in case there are any.
|
||||
// Hey do you like the idea of making that ErrEula "No HOME" popup?
|
||||
if (!flashUtils.CaffeineInvalidate()) {
|
||||
mErrorString = "Failed to invalidate caffeine.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mFlashingProgress = 0;
|
||||
mUpdateComplete = false;
|
||||
mUpdateResult = 0;
|
||||
if (CCRCDCSoftwareUpdate(CCR_CDC_DESTINATION_DRC0, mFirmwarePath.c_str(), SoftwareUpdateCallback, this) != 0) { // Now flash firmware.
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to start software update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mState = STATE_FLASHING_FIRM; // Track progress
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING_FIRM: {
|
||||
// Update progress
|
||||
CCRCDCFWInfo fwInfo{};
|
||||
if (CCRCDCGetFWInfo(CCR_CDC_DESTINATION_DRC0, &fwInfo) == 0) {
|
||||
mFlashingProgress = fwInfo.updateProgress;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
|
||||
// Check if update complete
|
||||
if (mUpdateComplete) {
|
||||
if (mUpdateResult == IOS_ERROR_OK) {
|
||||
mState = STATE_ACTIVATE;
|
||||
} else {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Software update failed.";
|
||||
mState = STATE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ACTIVATE: {
|
||||
// Activate the newly flashed language
|
||||
uint32_t langActivateSuccess = 0;
|
||||
CCRCDCSoftwareLangActivate(CCR_CDC_DESTINATION_DRC0, targetVersion, &langActivateSuccess);
|
||||
if (langActivateSuccess != 0 || CCRCDCSoftwareActivate(CCR_CDC_DESTINATION_DRC0) != 0) {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to activate one of the updates.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// Put the gamepad back into active mode
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (!flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE)) {
|
||||
// 10 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 10) {
|
||||
// At this point we don't really care if it times out or not
|
||||
break;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(1000));
|
||||
}
|
||||
|
||||
mState = STATE_DONE;
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrcFFlashScreen::OnUpdateCompleted(int32_t result)
|
||||
{
|
||||
mUpdateComplete = true;
|
||||
mUpdateResult = result;
|
||||
}
|
43
source/screens/DrcFFlashScreen.hpp
Normal file
43
source/screens/DrcFFlashScreen.hpp
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include "FlashUtils.hpp"
|
||||
|
||||
class DrcFFlashScreen : public Screen
|
||||
{
|
||||
public:
|
||||
// DrcLangScreen();
|
||||
virtual ~DrcFFlashScreen();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
void OnUpdateCompleted(int32_t result);
|
||||
private:
|
||||
enum State {
|
||||
STATE_PREPARE,
|
||||
STATE_CONFIRM2,
|
||||
STATE_UPDATE_LANG,
|
||||
STATE_FLASHING_LANG,
|
||||
STATE_UPDATE_FIRM,
|
||||
STATE_FLASHING_FIRM,
|
||||
STATE_ACTIVATE,
|
||||
STATE_DONE,
|
||||
STATE_ERROR,
|
||||
} mState = STATE_PREPARE;
|
||||
|
||||
struct FileEntry {
|
||||
uint16_t icon;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
std::string mErrorString;
|
||||
std::string mFirmwarePath;
|
||||
std::string mLangPath;
|
||||
FlashUtils::FirmwareHeader mLanguageHeader;
|
||||
FlashUtils::FirmwareHeader mFirmwareHeader;
|
||||
int32_t mFlashingProgress;
|
||||
bool mUpdateComplete;
|
||||
int32_t mUpdateResult;
|
||||
};
|
@ -1,4 +1,4 @@
|
||||
#include "FlashScreen.hpp"
|
||||
#include "DrcFlashScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "ProcUI.hpp"
|
||||
#include "Utils.hpp"
|
||||
@ -33,161 +33,16 @@ bool GetDRCFirmwarePath(std::string& path)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadFirmwareHeader(const std::string& path, FlashScreen::FirmwareHeader& header)
|
||||
{
|
||||
FILE* f = fopen(path.c_str(), "rb");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fread(&header, 1, sizeof(header), f) != sizeof(header)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyFile(const std::string& srcPath, const std::string& dstPath)
|
||||
{
|
||||
FILE* inf = fopen(srcPath.c_str(), "rb");
|
||||
if (!inf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* outf = fopen(dstPath.c_str(), "wb");
|
||||
if (!outf) {
|
||||
fclose(inf);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t buf[4096];
|
||||
size_t bytesRead;
|
||||
while ((bytesRead = fread(buf, 1, sizeof(buf), inf)) > 0) {
|
||||
if (fwrite(buf, 1, bytesRead, outf) != bytesRead) {
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(inf)) {
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CaffeineInvalidate()
|
||||
{
|
||||
CCRCDCSoftwareVersion version;
|
||||
CCRCDCSoftwareGetVersion(CCR_CDC_DESTINATION_DRC0, &version);
|
||||
|
||||
// Only newer versions have caffeine
|
||||
if (version.runningVersion >= 0x180a0000) {
|
||||
return CCRSysCaffeineSetCaffeineSlot(0xff) == 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WaitForEeprom(uint32_t drcSlot)
|
||||
{
|
||||
uint8_t val;
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (CCRCFGGetCachedEeprom(drcSlot, 0, &val, sizeof(val)) == -1) {
|
||||
// 2 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReattachDRC(CCRCDCDestination dest, CCRCDCDrcStateEnum targetState, BOOL unknown)
|
||||
{
|
||||
// Get the current DRC state
|
||||
CCRCDCDrcState state;
|
||||
int32_t res = CCRCDCSysGetDrcState(dest, &state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.state == CCR_CDC_DRC_STATE_STANDALONE) {
|
||||
state.state = CCR_CDC_DRC_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
// Nothing to do if we're already in the target state
|
||||
if (state.state == targetState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
__CCRSysInitReattach(dest - CCR_CDC_DESTINATION_DRC0);
|
||||
|
||||
// Set target state
|
||||
state.state = targetState;
|
||||
res = CCRCDCSysSetDrcState(dest, &state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the DRC to reattach
|
||||
res = __CCRSysWaitReattach(dest - CCR_CDC_DESTINATION_DRC0, unknown);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for EEPROM
|
||||
if (!WaitForEeprom(dest - CCR_CDC_DESTINATION_DRC0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we're in the state we want
|
||||
res = CCRCDCSysGetDrcState(dest, &state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.state != targetState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbortUpdate(CCRCDCDestination dest)
|
||||
{
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (CCRCDCSoftwareAbort(dest) != 0) {
|
||||
// 3 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SoftwareUpdateCallback(IOSError error, void* arg)
|
||||
{
|
||||
FlashScreen* flashScreen = static_cast<FlashScreen*>(arg);
|
||||
DrcFlashScreen* drcFlashScreen = static_cast<DrcFlashScreen*>(arg);
|
||||
|
||||
flashScreen->OnUpdateCompleted(error);
|
||||
drcFlashScreen->OnUpdateCompleted(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FlashScreen::FlashScreen()
|
||||
DrcFlashScreen::DrcFlashScreen()
|
||||
: mFileEntries({
|
||||
{FILE_ORIGINAL, {0xf187, "Original Firmware"}},
|
||||
{FILE_SDCARD, {0xf7c2, "From SD Card (\"sd:/drc_fw.bin\")"}},
|
||||
@ -195,13 +50,13 @@ FlashScreen::FlashScreen()
|
||||
{
|
||||
}
|
||||
|
||||
FlashScreen::~FlashScreen()
|
||||
DrcFlashScreen::~DrcFlashScreen()
|
||||
{
|
||||
}
|
||||
|
||||
void FlashScreen::Draw()
|
||||
void DrcFlashScreen::Draw()
|
||||
{
|
||||
DrawTopBar("FlashScreen");
|
||||
DrawTopBar("DrcFlashScreen");
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
@ -275,7 +130,7 @@ void FlashScreen::Draw()
|
||||
}
|
||||
}
|
||||
|
||||
bool FlashScreen::Update(VPADStatus& input)
|
||||
bool DrcFlashScreen::Update(VPADStatus& input)
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
@ -330,8 +185,8 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
std::string doptPath = originalFirmwarePath;
|
||||
doptPath.replace(prefixPos, sizeof("/vol/storage_mlc01") - 1, "storage_mlc01:");
|
||||
|
||||
FirmwareHeader originalFirmwareHeader;
|
||||
if (!ReadFirmwareHeader(doptPath, originalFirmwareHeader)) {
|
||||
FlashUtils::FirmwareHeader originalFirmwareHeader;
|
||||
if (!flashUtils.ReadFirmwareHeader(doptPath, originalFirmwareHeader)) {
|
||||
mErrorString = "Failed to read original DRC firmware header";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
@ -341,23 +196,23 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
mFirmwarePath = originalFirmwarePath;
|
||||
mFirmwareHeader = originalFirmwareHeader;
|
||||
} else if (mFile == FILE_SDCARD) {
|
||||
if (!ReadFirmwareHeader("/vol/external01/drc_fw.bin", mFirmwareHeader)) {
|
||||
if (!flashUtils.ReadFirmwareHeader("/vol/external01/drc_fw.bin", mFirmwareHeader)) {
|
||||
mErrorString = "Failed to read DRC firmware header";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
// Don't allow downgrading lower than the version on NAND,
|
||||
// otherwise this might cause bricks without flashing the language files?
|
||||
if (mFirmwareHeader.version < originalFirmwareHeader.version) {
|
||||
mErrorString = Utils::sprintf("Not allowing versions lower than version on NAND.\n(Firmware 0x%08x Original 0x%08x)", mFirmwareHeader.version, originalFirmwareHeader.version);
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
}*/
|
||||
|
||||
// Copy to MLC so IOS-PAD can install it
|
||||
mFirmwarePath = "/vol/storage_mlc01/usr/tmp/drc_fw.bin";
|
||||
if (!CopyFile("/vol/external01/drc_fw.bin", "storage_mlc01:/usr/tmp/drc_fw.bin")) {
|
||||
if (!flashUtils.CopyFile("/vol/external01/drc_fw.bin", "storage_mlc01:/usr/tmp/drc_fw.bin")) {
|
||||
mErrorString = "Failed to copy firmware to MLC";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
@ -366,6 +221,18 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t extId = 0;
|
||||
if (CCRCDCSoftwareGetExtId(CCR_CDC_DESTINATION_DRC0, CCR_CDC_EXT_LANGUAGE, &extId) != 0) {
|
||||
mErrorString = "Failed to get DRC language version!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
if (!flashUtils.CheckVersionSafety(mFirmwareHeader.version, extId)) {
|
||||
mErrorString = "Firmware version not valid for the DRC language!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mState = STATE_CONFIRM2;
|
||||
break;
|
||||
@ -373,7 +240,7 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
case STATE_UPDATE: {
|
||||
ProcUI::SetHomeButtonMenuEnabled(false);
|
||||
|
||||
if (!CaffeineInvalidate()) {
|
||||
if (!flashUtils.CaffeineInvalidate()) {
|
||||
mErrorString = "Failed to invalidate caffeine.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
@ -383,8 +250,8 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
CCRCDCSoftwareAbort(CCR_CDC_DESTINATION_DRC0);
|
||||
|
||||
// Reattach the DRC in update mode
|
||||
if (!ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_FWUPDATE, FALSE)) {
|
||||
ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
if (!flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_FWUPDATE, FALSE)) {
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to reattach DRC in update mode.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
@ -394,8 +261,8 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
mUpdateComplete = false;
|
||||
mUpdateResult = 0;
|
||||
if (CCRCDCSoftwareUpdate(CCR_CDC_DESTINATION_DRC0, mFirmwarePath.c_str(), SoftwareUpdateCallback, this) != 0) {
|
||||
AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to start software update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
@ -418,8 +285,8 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
if (mUpdateResult == IOS_ERROR_OK) {
|
||||
mState = STATE_ACTIVATE;
|
||||
} else {
|
||||
AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Software update failed.";
|
||||
mState = STATE_ERROR;
|
||||
}
|
||||
@ -429,8 +296,8 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
case STATE_ACTIVATE: {
|
||||
// Activate the newly flashed firmware
|
||||
if (CCRCDCSoftwareActivate(CCR_CDC_DESTINATION_DRC0) != 0) {
|
||||
AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to activate software update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
@ -438,7 +305,7 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
|
||||
// Put the gamepad back into active mode
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (!ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE)) {
|
||||
while (!flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE)) {
|
||||
// 10 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 10) {
|
||||
// At this point we don't really care if it times out or not
|
||||
@ -473,7 +340,7 @@ bool FlashScreen::Update(VPADStatus& input)
|
||||
return true;
|
||||
}
|
||||
|
||||
void FlashScreen::OnUpdateCompleted(int32_t result)
|
||||
void DrcFlashScreen::OnUpdateCompleted(int32_t result)
|
||||
{
|
||||
mUpdateComplete = true;
|
||||
mUpdateResult = result;
|
@ -1,21 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include "FlashUtils.hpp"
|
||||
#include <map>
|
||||
|
||||
class FlashScreen : public Screen
|
||||
class DrcFlashScreen : public Screen
|
||||
{
|
||||
public:
|
||||
struct FirmwareHeader {
|
||||
uint32_t version;
|
||||
uint32_t blockSize;
|
||||
uint32_t sequencePerSession;
|
||||
uint32_t imageSize;
|
||||
};
|
||||
|
||||
public:
|
||||
FlashScreen();
|
||||
virtual ~FlashScreen();
|
||||
DrcFlashScreen();
|
||||
virtual ~DrcFlashScreen();
|
||||
|
||||
void Draw();
|
||||
|
||||
@ -48,7 +42,7 @@ private:
|
||||
|
||||
std::string mErrorString;
|
||||
std::string mFirmwarePath;
|
||||
FirmwareHeader mFirmwareHeader;
|
||||
FlashUtils::FirmwareHeader mFirmwareHeader;
|
||||
|
||||
int32_t mFlashingProgress;
|
||||
bool mUpdateComplete;
|
229
source/screens/DrcLangScreen.cpp
Normal file
229
source/screens/DrcLangScreen.cpp
Normal file
@ -0,0 +1,229 @@
|
||||
#include "DrcLangScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "ProcUI.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <nsysccr/cfg.h>
|
||||
#include <nn/ccr.h>
|
||||
|
||||
namespace {
|
||||
|
||||
void SoftwareUpdateCallback(IOSError error, void* arg)
|
||||
{
|
||||
DrcLangScreen* drcLangScreen = static_cast<DrcLangScreen*>(arg);
|
||||
|
||||
drcLangScreen->OnUpdateCompleted(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DrcLangScreen::~DrcLangScreen()
|
||||
{
|
||||
}
|
||||
|
||||
void DrcLangScreen::Draw()
|
||||
{
|
||||
DrawTopBar("DrcLangScreen");
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_PREPARE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Preparing...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_CONFIRM2: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR,
|
||||
Utils::sprintf("Are you really really really sure?\n"
|
||||
"About to flash langpack.\n"
|
||||
"Lanuage packs mismatching the firmware\nwill brick your GamePad!\n"),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_UPDATE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Starting update...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2 - 32, 64, Gfx::COLOR_TEXT, Utils::sprintf("Flashing... %d%%", mFlashingProgress), Gfx::ALIGN_CENTER);
|
||||
Gfx::DrawRect(64, Gfx::SCREEN_HEIGHT / 2 + 32, Gfx::SCREEN_WIDTH - 128, 64, 5, Gfx::COLOR_ACCENT);
|
||||
Gfx::DrawRectFilled(64, Gfx::SCREEN_HEIGHT / 2 + 32, (Gfx::SCREEN_WIDTH - 128) * (mFlashingProgress / 100.0f), 64, Gfx::COLOR_ACCENT);
|
||||
break;
|
||||
}
|
||||
case STATE_ACTIVATE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Activating language pack...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("Done!\n"
|
||||
"Flashed new language pack"),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR, "Error:\n" + mErrorString, Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mState == STATE_CONFIRM2) {
|
||||
DrawBottomBar(nullptr, "\ue044 Exit", "\ue000 Confirm / \ue001 Back");
|
||||
} else if (mState == STATE_PREPARE || mState == STATE_UPDATE || mState == STATE_FLASHING || mState == STATE_ACTIVATE) {
|
||||
DrawBottomBar(nullptr, "Please wait...", nullptr);
|
||||
} else if (mState == STATE_DONE || mState == STATE_ERROR) {
|
||||
DrawBottomBar(nullptr, nullptr, "\ue001 Back");
|
||||
}
|
||||
}
|
||||
|
||||
bool DrcLangScreen::Update(VPADStatus& input)
|
||||
{
|
||||
flashUtils.ReadFirmwareHeader("/vol/external01/lang.bin", mFirmwareHeader);
|
||||
uint32_t targetVersion = mFirmwareHeader.version;
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_CONFIRM2: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_A) {
|
||||
mState = STATE_UPDATE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_PREPARE: {
|
||||
// Perform compatibility check
|
||||
// Writing only language, must obtain firmware from DRC
|
||||
CCRCDCSoftwareVersion deviceVersion;
|
||||
CCRCDCSoftwareGetVersion(CCR_CDC_DESTINATION_DRC0, &deviceVersion);
|
||||
if (!flashUtils.CheckVersionSafety(deviceVersion.runningVersion, targetVersion)) {
|
||||
mErrorString = "Language version not valid for the DRC firmware!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
// Copy to MLC so IOS-PAD can install it
|
||||
mFirmwarePath = "/vol/storage_mlc01/usr/tmp/lang.bin";
|
||||
if (!flashUtils.CopyFile("/vol/external01/lang.bin", "storage_mlc01:/usr/tmp/lang.bin")) {
|
||||
mErrorString = "Failed to copy firmware to MLC";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mState = STATE_CONFIRM2;
|
||||
break;
|
||||
}
|
||||
case STATE_UPDATE: {
|
||||
ProcUI::SetHomeButtonMenuEnabled(false);
|
||||
|
||||
if (!flashUtils.CaffeineInvalidate()) {
|
||||
mErrorString = "Failed to invalidate caffeine.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// Abort any potential pending software updates
|
||||
CCRCDCSoftwareAbort(CCR_CDC_DESTINATION_DRC0);
|
||||
|
||||
// Reattach the DRC in update mode
|
||||
if (!flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_FWUPDATE, FALSE)) {
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to reattach DRC in update mode.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mFlashingProgress = 0;
|
||||
mUpdateComplete = false;
|
||||
mUpdateResult = 0;
|
||||
if (CCRCDCSoftwareLangUpdate(CCR_CDC_DESTINATION_DRC0, mFirmwarePath.c_str(), &targetVersion, SoftwareUpdateCallback, this) != 0) {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to start software update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mState = STATE_FLASHING;
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING: {
|
||||
// Update progress
|
||||
CCRCDCFWInfo fwInfo{};
|
||||
if (CCRCDCGetFWInfo(CCR_CDC_DESTINATION_DRC0, &fwInfo) == 0) {
|
||||
mFlashingProgress = fwInfo.updateProgress;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
|
||||
// Check if update complete
|
||||
if (mUpdateComplete) {
|
||||
if (mUpdateResult == IOS_ERROR_OK) {
|
||||
mState = STATE_ACTIVATE;
|
||||
} else {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Software update failed.";
|
||||
mState = STATE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ACTIVATE: {
|
||||
// Activate the newly flashed language
|
||||
uint32_t langActivateSuccess = 0;
|
||||
CCRCDCSoftwareLangActivate(CCR_CDC_DESTINATION_DRC0, targetVersion, &langActivateSuccess);
|
||||
if (langActivateSuccess != 0) {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRC0);
|
||||
flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE);
|
||||
mErrorString = "Failed to activate software update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// Put the gamepad back into active mode
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (!flashUtils.ReattachDRC(CCR_CDC_DESTINATION_DRC0, CCR_CDC_DRC_STATE_ACTIVE, FALSE)) {
|
||||
// 10 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 10) {
|
||||
// At this point we don't really care if it times out or not
|
||||
break;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(1000));
|
||||
}
|
||||
|
||||
mState = STATE_DONE;
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrcLangScreen::OnUpdateCompleted(int32_t result)
|
||||
{
|
||||
mUpdateComplete = true;
|
||||
mUpdateResult = result;
|
||||
}
|
39
source/screens/DrcLangScreen.hpp
Normal file
39
source/screens/DrcLangScreen.hpp
Normal file
@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include "FlashUtils.hpp"
|
||||
|
||||
class DrcLangScreen : public Screen
|
||||
{
|
||||
public:
|
||||
// DrcLangScreen();
|
||||
virtual ~DrcLangScreen();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
void OnUpdateCompleted(int32_t result);
|
||||
private:
|
||||
enum State {
|
||||
STATE_PREPARE,
|
||||
STATE_CONFIRM2,
|
||||
STATE_UPDATE,
|
||||
STATE_FLASHING,
|
||||
STATE_ACTIVATE,
|
||||
STATE_DONE,
|
||||
STATE_ERROR,
|
||||
} mState = STATE_PREPARE;
|
||||
|
||||
struct FileEntry {
|
||||
uint16_t icon;
|
||||
const char* name;
|
||||
};
|
||||
|
||||
std::string mErrorString;
|
||||
std::string mFirmwarePath;
|
||||
FlashUtils::FirmwareHeader mFirmwareHeader;
|
||||
int32_t mFlashingProgress;
|
||||
bool mUpdateComplete;
|
||||
int32_t mUpdateResult;
|
||||
};
|
95
source/screens/DrcScreenPicker.cpp
Normal file
95
source/screens/DrcScreenPicker.cpp
Normal file
@ -0,0 +1,95 @@
|
||||
#include "DrcScreenPicker.hpp"
|
||||
#include "SetRegionScreen.hpp"
|
||||
#include "EepromScreen.hpp"
|
||||
#include "PairScreen.hpp"
|
||||
#include "EnableDKMenuScreen.hpp"
|
||||
#include "FormatScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
DrcScreenPicker::DrcScreenPicker()
|
||||
: mEntries({
|
||||
{ MENU_ID_SET_REGION, { 0xf0ac, "Set region" }},
|
||||
{ MENU_ID_DUMP_EEPROM, { 0xf08b, "Dump EEPROMs" }},
|
||||
{ MENU_ID_DRC_PAIR, { 0xf0c1, "Pair DRC..." }},
|
||||
{ MENU_ID_ENABLE_DKMENU, { 0xf188, "Enable DK Menu" }},
|
||||
{ MENU_ID_DRC_RESET, { 0xf079, "Reset DRC" }},
|
||||
})
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DrcScreenPicker::~DrcScreenPicker()
|
||||
{
|
||||
}
|
||||
|
||||
void DrcScreenPicker::Draw()
|
||||
{
|
||||
if (mSubscreen) {
|
||||
mSubscreen->Draw();
|
||||
return;
|
||||
}
|
||||
|
||||
DrawTopBar("DrcScreenPicker");
|
||||
|
||||
// draw entries
|
||||
for (MenuID id = MENU_ID_MIN; id <= MENU_ID_MAX; id = static_cast<MenuID>(id + 1)) {
|
||||
int yOff = 75 + static_cast<int>(id) * 150;
|
||||
Gfx::DrawRectFilled(0, yOff, Gfx::SCREEN_WIDTH, 150, Gfx::COLOR_ALT_BACKGROUND);
|
||||
Gfx::DrawIcon(68, yOff + 150 / 2, 60, Gfx::COLOR_TEXT, mEntries[id].icon);
|
||||
Gfx::Print(128 + 8, yOff + 150 / 2, 60, Gfx::COLOR_TEXT, mEntries[id].name, Gfx::ALIGN_VERTICAL);
|
||||
|
||||
if (id == mSelected) {
|
||||
Gfx::DrawRect(0, yOff, Gfx::SCREEN_WIDTH, 150, 8, Gfx::COLOR_HIGHLIGHTED);
|
||||
}
|
||||
}
|
||||
|
||||
DrawBottomBar("\ue07d Navigate", "\ue044 Exit", "\ue000 Select / \ue001 Back");
|
||||
}
|
||||
|
||||
bool DrcScreenPicker::Update(VPADStatus& input)
|
||||
{
|
||||
if (mSubscreen) {
|
||||
if (!mSubscreen->Update(input)) {
|
||||
// subscreen wants to exit
|
||||
mSubscreen.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_DOWN) {
|
||||
if (mSelected < MENU_ID_MAX) {
|
||||
mSelected = static_cast<MenuID>(mSelected + 1);
|
||||
}
|
||||
} else if (input.trigger & VPAD_BUTTON_UP) {
|
||||
if (mSelected > MENU_ID_MIN) {
|
||||
mSelected = static_cast<MenuID>(mSelected - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_A) {
|
||||
switch (mSelected) {
|
||||
case MENU_ID_SET_REGION:
|
||||
mSubscreen = std::make_unique<SetRegionScreen>();
|
||||
break;
|
||||
case MENU_ID_DUMP_EEPROM:
|
||||
mSubscreen = std::make_unique<EepromScreen>();
|
||||
break;
|
||||
case MENU_ID_DRC_PAIR:
|
||||
mSubscreen = std::make_unique<PairScreen>();
|
||||
break;
|
||||
case MENU_ID_ENABLE_DKMENU:
|
||||
mSubscreen = std::make_unique<EnableDKMenuScreen>();
|
||||
break;
|
||||
case MENU_ID_DRC_RESET:
|
||||
mSubscreen = std::make_unique<FormatScreen>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
37
source/screens/DrcScreenPicker.hpp
Normal file
37
source/screens/DrcScreenPicker.hpp
Normal file
@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
class DrcScreenPicker : public Screen
|
||||
{
|
||||
public:
|
||||
DrcScreenPicker();
|
||||
virtual ~DrcScreenPicker();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Screen> mSubscreen;
|
||||
|
||||
enum MenuID {
|
||||
MENU_ID_SET_REGION,
|
||||
MENU_ID_DUMP_EEPROM,
|
||||
MENU_ID_DRC_PAIR,
|
||||
MENU_ID_ENABLE_DKMENU,
|
||||
MENU_ID_DRC_RESET,
|
||||
|
||||
MENU_ID_MIN = MENU_ID_SET_REGION,
|
||||
MENU_ID_MAX = MENU_ID_DRC_RESET,
|
||||
};
|
||||
|
||||
struct MenuEntry {
|
||||
uint16_t icon;
|
||||
const char* name;
|
||||
};
|
||||
std::map<MenuID, MenuEntry> mEntries;
|
||||
MenuID mSelected = MENU_ID_MIN;
|
||||
};
|
335
source/screens/DrhFlashScreen.cpp
Normal file
335
source/screens/DrhFlashScreen.cpp
Normal file
@ -0,0 +1,335 @@
|
||||
#include "DrhFlashScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "ProcUI.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <nsysccr/cfg.h>
|
||||
#include <nn/ccr.h>
|
||||
#include <coreinit/launch.h>
|
||||
|
||||
#define OS_TITLE_ID_REBOOT 0xFFFFFFFFFFFFFFFEllu
|
||||
|
||||
namespace {
|
||||
/*
|
||||
bool ReadFirmwareHeader(const std::string& path, DrhFlashScreen::FirmwareHeader& header)
|
||||
{
|
||||
FILE* f = fopen(path.c_str(), "rb");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fread(&header, 1, sizeof(header), f) != sizeof(header)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CopyFile(const std::string& srcPath, const std::string& dstPath)
|
||||
{
|
||||
FILE* inf = fopen(srcPath.c_str(), "rb");
|
||||
if (!inf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* outf = fopen(dstPath.c_str(), "wb");
|
||||
if (!outf) {
|
||||
fclose(inf);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t buf[4096];
|
||||
size_t bytesRead;
|
||||
while ((bytesRead = fread(buf, 1, sizeof(buf), inf)) > 0) {
|
||||
if (fwrite(buf, 1, bytesRead, outf) != bytesRead) {
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(inf)) {
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CaffeineInvalidate()
|
||||
{
|
||||
CCRCDCSoftwareVersion version;
|
||||
CCRCDCSoftwareGetVersion(CCR_CDC_DESTINATION_DRH, &version);
|
||||
|
||||
// Only newer versions have caffeine
|
||||
if (version.runningVersion >= 0x180a0000) {
|
||||
return CCRSysCaffeineSetCaffeineSlot(0xff) == 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReattachDRH(CCRCDCDrhStateEnum targetState, BOOL unknown)
|
||||
{
|
||||
// Get the current DRC state
|
||||
CCRCDCDrhState state;
|
||||
int32_t res = CCRCDCSysGetDrhState(&state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Nothing to do if we're already in the target state
|
||||
if (state.state == targetState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set target state
|
||||
state.state = targetState;
|
||||
res = CCRCDCSysSetDrhState(&state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we're in the state we want
|
||||
res = CCRCDCSysGetDrhState(&state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.state != targetState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AbortUpdate(CCRCDCDestination dest)
|
||||
{
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (CCRCDCSoftwareAbort(dest) != 0) {
|
||||
// 3 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
}
|
||||
|
||||
return true;
|
||||
}*/
|
||||
|
||||
void SoftwareUpdateCallback(IOSError error, void* arg)
|
||||
{
|
||||
DrhFlashScreen* drhFlashScreen = static_cast<DrhFlashScreen*>(arg);
|
||||
|
||||
drhFlashScreen->OnUpdateCompleted(error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DrhFlashScreen::DrhFlashScreen()
|
||||
{
|
||||
}
|
||||
|
||||
DrhFlashScreen::~DrhFlashScreen()
|
||||
{
|
||||
}
|
||||
|
||||
void DrhFlashScreen::Draw()
|
||||
{
|
||||
DrawTopBar("DrhFlashScreen");
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_PREPARE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Preparing...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_CONFIRM2: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("DRH update is ready.\n"
|
||||
"About to flash firmware version 0x%08x.\n"
|
||||
"Would you like to start the update now?\n", mFirmwareHeader.version),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_UPDATE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Starting update...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2 - 32, 64, Gfx::COLOR_TEXT, Utils::sprintf("Updating... %d%%", mFlashingProgress), Gfx::ALIGN_CENTER);
|
||||
Gfx::DrawRect(64, Gfx::SCREEN_HEIGHT / 2 + 32, Gfx::SCREEN_WIDTH - 128, 64, 5, Gfx::COLOR_ACCENT);
|
||||
Gfx::DrawRectFilled(64, Gfx::SCREEN_HEIGHT / 2 + 32, (Gfx::SCREEN_WIDTH - 128) * (mFlashingProgress / 100.0f), 64, Gfx::COLOR_ACCENT);
|
||||
break;
|
||||
}
|
||||
case STATE_ACTIVATE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Activating firmware...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("The update is complete.\n"
|
||||
"The console will now restart."),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR, "Error:\n" + mErrorString, Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (mState == STATE_CONFIRM2) {
|
||||
DrawBottomBar(nullptr, "\ue044 Exit", "\ue000 Confirm / \ue001 Back");
|
||||
} else if (mState == STATE_PREPARE || mState == STATE_UPDATE || mState == STATE_FLASHING || mState == STATE_ACTIVATE) {
|
||||
DrawBottomBar(nullptr, "Please wait...", nullptr);
|
||||
} else if (mState == STATE_DONE) {
|
||||
DrawBottomBar(nullptr, nullptr, "\ue000 Reboot");
|
||||
} else if (mState == STATE_ERROR) {
|
||||
DrawBottomBar(nullptr, nullptr, "\ue001 Back");
|
||||
}
|
||||
}
|
||||
|
||||
bool DrhFlashScreen::Update(VPADStatus& input)
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_CONFIRM2: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_A) {
|
||||
mState = STATE_UPDATE;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_PREPARE: {
|
||||
if (!flashUtils.ReadFirmwareHeader("/vol/external01/drh_fw.bin", mFirmwareHeader)) {
|
||||
mErrorString = "Failed to read DRH firmware header";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
// Copy to MLC so IOS-PAD can install it
|
||||
mFirmwarePath = "/vol/storage_mlc01/usr/tmp/drh_fw.bin";
|
||||
if (!flashUtils.CopyFile("/vol/external01/drh_fw.bin", "storage_mlc01:/usr/tmp/drh_fw.bin")) {
|
||||
mErrorString = "Failed to copy firmware to MLC";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mState = STATE_CONFIRM2;
|
||||
break;
|
||||
}
|
||||
case STATE_UPDATE: {
|
||||
ProcUI::SetHomeButtonMenuEnabled(false);
|
||||
|
||||
if (!flashUtils.CaffeineInvalidate()) {
|
||||
mErrorString = "Failed to invalidate caffeine.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// Abort any potential pending software updates
|
||||
CCRCDCSoftwareAbort(CCR_CDC_DESTINATION_DRH);
|
||||
|
||||
mFlashingProgress = 0;
|
||||
mUpdateComplete = false;
|
||||
mUpdateResult = 0;
|
||||
if (CCRCDCSoftwareUpdate(CCR_CDC_DESTINATION_DRH, mFirmwarePath.c_str(), SoftwareUpdateCallback, this) != 0) {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRH);
|
||||
flashUtils.ReattachDRH(CCR_CDC_SYS_DRH_STATE_CAFE, FALSE);
|
||||
mErrorString = "Failed to start software update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
mState = STATE_FLASHING;
|
||||
break;
|
||||
}
|
||||
case STATE_FLASHING: {
|
||||
// Update progress
|
||||
CCRCDCFWInfo fwInfo{};
|
||||
if (CCRCDCGetFWInfo(CCR_CDC_DESTINATION_DRH, &fwInfo) == 0) {
|
||||
mFlashingProgress = fwInfo.updateProgress;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
|
||||
// Check if update complete
|
||||
if (mUpdateComplete) {
|
||||
if (mUpdateResult == IOS_ERROR_OK) {
|
||||
mState = STATE_ACTIVATE;
|
||||
} else {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRH);
|
||||
flashUtils.ReattachDRH(CCR_CDC_SYS_DRH_STATE_CAFE, FALSE);
|
||||
mErrorString = "Software update failed - error " + std::to_string(mUpdateResult);
|
||||
mState = STATE_ERROR;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ACTIVATE: {
|
||||
// Activate the newly flashed firmware
|
||||
if (CCRCDCSoftwareActivate(CCR_CDC_DESTINATION_DRH) != 0) {
|
||||
flashUtils.AbortUpdate(CCR_CDC_DESTINATION_DRH);
|
||||
flashUtils.ReattachDRH(CCR_CDC_SYS_DRH_STATE_CAFE, FALSE);
|
||||
mErrorString = "Failed to activate software update.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
// Put the DRH back into active mode
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (!flashUtils.ReattachDRH(CCR_CDC_SYS_DRH_STATE_CAFE, FALSE)) {
|
||||
// 10 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 10) {
|
||||
// At this point we don't really care if it times out or not
|
||||
break;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(1000));
|
||||
}
|
||||
|
||||
mState = STATE_DONE;
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
if (input.trigger & VPAD_BUTTON_A) {
|
||||
// Reboot system to apply changes
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
OSLaunchTitlev(OS_TITLE_ID_REBOOT, 0, NULL);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrhFlashScreen::OnUpdateCompleted(int32_t result)
|
||||
{
|
||||
mUpdateComplete = true;
|
||||
mUpdateResult = result;
|
||||
}
|
48
source/screens/DrhFlashScreen.hpp
Normal file
48
source/screens/DrhFlashScreen.hpp
Normal file
@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include "FlashUtils.hpp"
|
||||
#include <map>
|
||||
|
||||
class DrhFlashScreen : public Screen
|
||||
{
|
||||
|
||||
public:
|
||||
DrhFlashScreen();
|
||||
virtual ~DrhFlashScreen();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
void OnUpdateCompleted(int32_t result);
|
||||
|
||||
private:
|
||||
enum State {
|
||||
STATE_PREPARE,
|
||||
STATE_CONFIRM2,
|
||||
STATE_UPDATE,
|
||||
STATE_FLASHING,
|
||||
STATE_ACTIVATE,
|
||||
STATE_DONE,
|
||||
STATE_ERROR,
|
||||
} mState = STATE_PREPARE;
|
||||
|
||||
enum FileID {
|
||||
FILE_ORIGINAL,
|
||||
FILE_SDCARD,
|
||||
} mFile = FILE_ORIGINAL;
|
||||
struct FileEntry {
|
||||
uint16_t icon;
|
||||
const char* name;
|
||||
};
|
||||
std::map<FileID, FileEntry> mFileEntries;
|
||||
|
||||
std::string mErrorString;
|
||||
std::string mFirmwarePath;
|
||||
FlashUtils::FirmwareHeader mFirmwareHeader;
|
||||
|
||||
int32_t mFlashingProgress;
|
||||
bool mUpdateComplete;
|
||||
int32_t mUpdateResult;
|
||||
};
|
119
source/screens/EepromScreen.cpp
Normal file
119
source/screens/EepromScreen.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
#include "EepromScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "ProcUI.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <nsysccr/cfg.h>
|
||||
#include <nn/ccr.h>
|
||||
|
||||
namespace {
|
||||
|
||||
bool WriteFile(const uint8_t *source, const std::string& dstPath)
|
||||
{
|
||||
FILE* outf = fopen(dstPath.c_str(), "wb");
|
||||
if (!outf) {
|
||||
return false;
|
||||
}
|
||||
if (fwrite(source, 1, 4096, outf) != 0) { // DRC EEPROM size up until "DEADBABE" string appears to be 5E0h bytes, unless you dump the 2nd DRC. What the hell does it add..?
|
||||
fclose(outf);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(outf);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
EepromScreen::EepromScreen(){}
|
||||
EepromScreen::~EepromScreen(){}
|
||||
void EepromScreen::Draw()
|
||||
{
|
||||
DrawTopBar("EepromScreen");
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_DUMP: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Reading data", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("Saved to eeprom.bin\nPress B"),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR, "Error:\n" + mErrorString, Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mState == STATE_ERROR || STATE_DONE)
|
||||
DrawBottomBar(nullptr, nullptr, "\ue001 Back");
|
||||
}
|
||||
|
||||
bool EepromScreen::Update(VPADStatus& input) // This is the core logic part
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_DUMP: {
|
||||
CCRCDCEepromData readout0;
|
||||
uint8_t readoutarray0[0x304];
|
||||
CCRCDCEepromData readout1; // If a 2nd DRC is present, we will write this
|
||||
uint8_t readoutarray1[0x304];
|
||||
// Read EEPROM
|
||||
if(CCRCDCPerGetUicEeprom(CCR_CDC_DESTINATION_DRC0, &readout0) != 0){
|
||||
mErrorString = "Read failed!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
// Write to SD card
|
||||
// Convert to uint8_t so that this can be processed by fwrite
|
||||
uint8_t versionarray0[4];
|
||||
for (int i=0; i<4 ;++i)
|
||||
versionarray0[i] = ((uint8_t*)&readout0.version)[3-i];
|
||||
memcpy(&readoutarray0[0], versionarray0, 4);
|
||||
memcpy(&readoutarray0[4], readout0.data, 0x300);
|
||||
WriteFile(readoutarray0, "/vol/external01/eeprom0.bin");
|
||||
// If we read the DRC1 EEPROM
|
||||
if(CCRCDCPerGetUicEeprom(CCR_CDC_DESTINATION_DRC1, &readout1) == 0){
|
||||
uint8_t versionarray1[4];
|
||||
for (int i=0; i<4 ;++i)
|
||||
versionarray1[i] = ((uint8_t*)&readout1.version)[3-i];
|
||||
memcpy(&readoutarray1[0], versionarray1, 4);
|
||||
memcpy(&readoutarray1[4], readout1.data, 0x300);
|
||||
WriteFile(readoutarray1, "/vol/external01/eeprom1.bin");
|
||||
}
|
||||
mState = STATE_DONE;
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void EepromScreen::OnDumpCompleted()
|
||||
{
|
||||
mDumpComplete = true;
|
||||
}
|
29
source/screens/EepromScreen.hpp
Normal file
29
source/screens/EepromScreen.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include <map>
|
||||
|
||||
class EepromScreen : public Screen
|
||||
{
|
||||
public:
|
||||
EepromScreen();
|
||||
virtual ~EepromScreen();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
void OnDumpCompleted();
|
||||
|
||||
private:
|
||||
enum State {
|
||||
STATE_DUMP,
|
||||
STATE_DONE,
|
||||
STATE_ERROR,
|
||||
} mState = STATE_DUMP;
|
||||
|
||||
std::string mErrorString;
|
||||
|
||||
|
||||
bool mDumpComplete;
|
||||
};
|
@ -181,4 +181,4 @@ bool EnableDKMenuScreen::Update(VPADStatus& input)
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
@ -28,4 +28,4 @@ private:
|
||||
uint8_t mBoardConfig;
|
||||
bool mDKMenuEnabled;
|
||||
std::string mErrorText;
|
||||
};
|
||||
};
|
91
source/screens/FlashScreenPicker.cpp
Normal file
91
source/screens/FlashScreenPicker.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include "FlashScreenPicker.hpp"
|
||||
#include "DrhFlashScreen.hpp"
|
||||
#include "DrcFlashScreen.hpp"
|
||||
#include "DrcLangScreen.hpp"
|
||||
#include "DrcFFlashScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
FlashScreenPicker::FlashScreenPicker()
|
||||
: mEntries({
|
||||
{ MENU_ID_DRHFLASH, { 0xf085, "Flash DRH firmware" }},
|
||||
{ MENU_ID_DRCFLASH, { 0xf1c9, "Flash DRC firmware" }},
|
||||
{ MENU_ID_DRCLANG, { 0xf302, "Flash DRC language" }},
|
||||
{ MENU_ID_DRCFFLASH, { 0xe4c7, "Flash DRC fully" }},
|
||||
// { MENU_ID_EXIT, { 0xf057, "Exit" }},
|
||||
})
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
FlashScreenPicker::~FlashScreenPicker()
|
||||
{
|
||||
}
|
||||
|
||||
void FlashScreenPicker::Draw()
|
||||
{
|
||||
if (mSubscreen) {
|
||||
mSubscreen->Draw();
|
||||
return;
|
||||
}
|
||||
|
||||
DrawTopBar("FlashScreenPicker");
|
||||
|
||||
// draw entries
|
||||
for (MenuID id = MENU_ID_MIN; id <= MENU_ID_MAX; id = static_cast<MenuID>(id + 1)) {
|
||||
int yOff = 75 + static_cast<int>(id) * 150;
|
||||
Gfx::DrawRectFilled(0, yOff, Gfx::SCREEN_WIDTH, 150, Gfx::COLOR_ALT_BACKGROUND);
|
||||
Gfx::DrawIcon(68, yOff + 150 / 2, 60, Gfx::COLOR_TEXT, mEntries[id].icon);
|
||||
Gfx::Print(128 + 8, yOff + 150 / 2, 60, Gfx::COLOR_TEXT, mEntries[id].name, Gfx::ALIGN_VERTICAL);
|
||||
|
||||
if (id == mSelected) {
|
||||
Gfx::DrawRect(0, yOff, Gfx::SCREEN_WIDTH, 150, 8, Gfx::COLOR_HIGHLIGHTED);
|
||||
}
|
||||
}
|
||||
|
||||
DrawBottomBar("\ue07d Navigate", "\ue044 Exit", "\ue000 Select / \ue001 Back");
|
||||
}
|
||||
|
||||
bool FlashScreenPicker::Update(VPADStatus& input)
|
||||
{
|
||||
if (mSubscreen) {
|
||||
if (!mSubscreen->Update(input)) {
|
||||
// subscreen wants to exit
|
||||
mSubscreen.reset();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_DOWN) {
|
||||
if (mSelected < MENU_ID_MAX) {
|
||||
mSelected = static_cast<MenuID>(mSelected + 1);
|
||||
}
|
||||
} else if (input.trigger & VPAD_BUTTON_UP) {
|
||||
if (mSelected > MENU_ID_MIN) {
|
||||
mSelected = static_cast<MenuID>(mSelected - 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_A) {
|
||||
switch (mSelected) {
|
||||
case MENU_ID_DRHFLASH:
|
||||
mSubscreen = std::make_unique<DrhFlashScreen>();
|
||||
break;
|
||||
case MENU_ID_DRCFLASH:
|
||||
mSubscreen = std::make_unique<DrcFlashScreen>();
|
||||
break;
|
||||
case MENU_ID_DRCLANG:
|
||||
mSubscreen = std::make_unique<DrcLangScreen>();
|
||||
break;
|
||||
case MENU_ID_DRCFFLASH:
|
||||
mSubscreen = std::make_unique<DrcFFlashScreen>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
36
source/screens/FlashScreenPicker.hpp
Normal file
36
source/screens/FlashScreenPicker.hpp
Normal file
@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
class FlashScreenPicker : public Screen
|
||||
{
|
||||
public:
|
||||
FlashScreenPicker();
|
||||
virtual ~FlashScreenPicker();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Screen> mSubscreen;
|
||||
|
||||
enum MenuID {
|
||||
MENU_ID_DRHFLASH,
|
||||
MENU_ID_DRCFLASH,
|
||||
MENU_ID_DRCLANG,
|
||||
MENU_ID_DRCFFLASH,
|
||||
|
||||
MENU_ID_MIN = MENU_ID_DRHFLASH,
|
||||
MENU_ID_MAX = MENU_ID_DRCFFLASH,
|
||||
};
|
||||
|
||||
struct MenuEntry {
|
||||
uint16_t icon;
|
||||
const char* name;
|
||||
};
|
||||
std::map<MenuID, MenuEntry> mEntries;
|
||||
MenuID mSelected = MENU_ID_MIN;
|
||||
};
|
217
source/screens/FlashUtils.cpp
Normal file
217
source/screens/FlashUtils.cpp
Normal file
@ -0,0 +1,217 @@
|
||||
#include "FlashUtils.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <nsysccr/cfg.h>
|
||||
#include <nn/ccr.h>
|
||||
|
||||
FlashUtils flashUtils;
|
||||
|
||||
bool FlashUtils::CopyFile(const std::string& srcPath, const std::string& dstPath)
|
||||
{
|
||||
FILE* inf = fopen(srcPath.c_str(), "rb");
|
||||
if (!inf) {
|
||||
return false;
|
||||
}
|
||||
|
||||
FILE* outf = fopen(dstPath.c_str(), "wb");
|
||||
if (!outf) {
|
||||
fclose(inf);
|
||||
return false;
|
||||
}
|
||||
|
||||
uint8_t buf[4096];
|
||||
size_t bytesRead;
|
||||
while ((bytesRead = fread(buf, 1, sizeof(buf), inf)) > 0) {
|
||||
if (fwrite(buf, 1, bytesRead, outf) != bytesRead) {
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (ferror(inf)) {
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(inf);
|
||||
fclose(outf);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlashUtils::ReadFirmwareHeader(const std::string& path, FlashUtils::FirmwareHeader& header)
|
||||
{
|
||||
FILE* f = fopen(path.c_str(), "rb");
|
||||
if (!f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (fread(&header, 1, sizeof(header), f) != sizeof(header)) {
|
||||
fclose(f);
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlashUtils::CheckVersionSafety(const uint32_t firmver, const uint32_t langver)
|
||||
{
|
||||
// Very crude way to do the checks universally, but it works well enough
|
||||
// We take the firmware version as well as the language version (w/o region - am I stupid?) and compare them
|
||||
if ((firmver == 0x190c0117 || firmver == 0xfe000000) && ((langver & 0xFFFF00) ^ 0x170200)==0){ // Only patched firmware uses language v5890
|
||||
return true;
|
||||
} else if (firmver == 0x18140116 && not ((langver & 0xFFFF00) ^ 0x160400)){
|
||||
return true;
|
||||
} else if (firmver == 0x17080114 && not ((langver & 0xFFFF00) ^ 0x140000)){
|
||||
return true;
|
||||
} else if ((firmver == 0x151e0113 || firmver == 0x15060113 || firmver == 0x14060113) && not ((langver & 0xFFFF00) ^ 0x130000)){ // 3 versions have used language v4864
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool FlashUtils::CaffeineInvalidate()
|
||||
{
|
||||
CCRCDCSoftwareVersion version;
|
||||
CCRCDCSoftwareGetVersion(CCR_CDC_DESTINATION_DRC0, &version);
|
||||
|
||||
// Only newer versions have caffeine
|
||||
if (version.runningVersion >= 0x180a0000) {
|
||||
return CCRSysCaffeineSetCaffeineSlot(0xff) == 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlashUtils::WaitForEeprom(uint32_t drcSlot)
|
||||
{
|
||||
uint8_t val;
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (CCRCFGGetCachedEeprom(drcSlot, 0, &val, sizeof(val)) == -1) {
|
||||
// 2 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlashUtils::ReattachDRC(CCRCDCDestination dest, CCRCDCDrcStateEnum targetState, BOOL unknown)
|
||||
{
|
||||
// Get the current DRC state
|
||||
CCRCDCDrcState state;
|
||||
int32_t res = CCRCDCSysGetDrcState(dest, &state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not sure what state 3 is
|
||||
if (state.state == CCR_CDC_DRC_STATE_STANDALONE) {
|
||||
state.state = CCR_CDC_DRC_STATE_ACTIVE;
|
||||
}
|
||||
|
||||
// Nothing to do if we're already in the target state
|
||||
if (state.state == targetState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
__CCRSysInitReattach(dest - CCR_CDC_DESTINATION_DRC0);
|
||||
|
||||
// Set target state
|
||||
state.state = targetState;
|
||||
res = CCRCDCSysSetDrcState(dest, &state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for the DRC to reattach
|
||||
res = __CCRSysWaitReattach(dest - CCR_CDC_DESTINATION_DRC0, unknown);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for EEPROM
|
||||
if (!WaitForEeprom(dest - CCR_CDC_DESTINATION_DRC0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we're in the state we want
|
||||
res = CCRCDCSysGetDrcState(dest, &state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.state != targetState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FlashUtils::ReattachDRH(CCRCDCDrhStateEnum targetState, BOOL unknown)
|
||||
{
|
||||
// Get the current DRC state
|
||||
CCRCDCDrhState state;
|
||||
int32_t res = CCRCDCSysGetDrhState(&state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Nothing to do if we're already in the target state
|
||||
if (state.state == targetState) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Set target state
|
||||
state.state = targetState;
|
||||
res = CCRCDCSysSetDrhState(&state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if we're in the state we want
|
||||
res = CCRCDCSysGetDrhState(&state);
|
||||
if (res != 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (state.state != targetState) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool FlashUtils::AbortUpdate(CCRCDCDestination dest)
|
||||
{
|
||||
OSTime startTime = OSGetSystemTime();
|
||||
while (CCRCDCSoftwareAbort(dest) != 0) {
|
||||
// 3 second timeout
|
||||
if (OSTicksToSeconds(OSGetSystemTime() - startTime) > 3) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OSSleepTicks(OSMillisecondsToTicks(200));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
/*
|
||||
void SoftwareUpdateCallback(IOSError error, void* arg)
|
||||
{
|
||||
FlashUtils* flashUtils = static_cast<FlashUtils*>(arg);
|
||||
|
||||
flashUtils->OnUpdateCompleted(error);
|
||||
}
|
||||
*/
|
34
source/screens/FlashUtils.hpp
Normal file
34
source/screens/FlashUtils.hpp
Normal file
@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
|
||||
#include <coreinit/mcp.h>
|
||||
#include <coreinit/thread.h>
|
||||
#include <coreinit/filesystem_fsa.h>
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <nsysccr/cfg.h>
|
||||
#include <nn/ccr.h>
|
||||
|
||||
class FlashUtils
|
||||
{
|
||||
public:
|
||||
void OnUpdateCompleted(int32_t result);
|
||||
struct FirmwareHeader {
|
||||
uint32_t version;
|
||||
uint32_t blockSize;
|
||||
uint32_t sequencePerSession;
|
||||
uint32_t imageSize;
|
||||
};
|
||||
bool CopyFile(const std::string& srcPath, const std::string& dstPath);
|
||||
bool ReadFirmwareHeader(const std::string& path, FlashUtils::FirmwareHeader& header);
|
||||
bool CheckVersionSafety(const uint32_t firmver, const uint32_t langver);
|
||||
bool CaffeineInvalidate();
|
||||
bool WaitForEeprom(uint32_t drcSlot);
|
||||
bool ReattachDRC(CCRCDCDestination dest, CCRCDCDrcStateEnum targetState, BOOL unknown);
|
||||
bool ReattachDRH(CCRCDCDrhStateEnum targetState, BOOL unknown);
|
||||
bool AbortUpdate(CCRCDCDestination dest);
|
||||
|
||||
};
|
||||
|
||||
extern FlashUtils flashUtils;
|
||||
|
83
source/screens/FormatScreen.cpp
Normal file
83
source/screens/FormatScreen.cpp
Normal file
@ -0,0 +1,83 @@
|
||||
#include "FormatScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "ProcUI.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <sysapp/launch.h>
|
||||
#include <nn/ccr.h>
|
||||
|
||||
namespace {}
|
||||
|
||||
FormatScreen::FormatScreen(){
|
||||
CCRCDCSetMultiDrc(1); // Having multiple DRCs enabled will make it impossible to erase a gamepad.
|
||||
}
|
||||
FormatScreen::~FormatScreen(){}
|
||||
void FormatScreen::Draw()
|
||||
{
|
||||
DrawTopBar("FormatScreen");
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_UPDATE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Resetting data", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("Done!"),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR, "Error:\n" + mErrorString, Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool FormatScreen::Update(VPADStatus& input) // This is the core logic part
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_UPDATE: {
|
||||
ProcUI::SetHomeButtonMenuEnabled(false);
|
||||
|
||||
|
||||
// Abort any potential pending software updates
|
||||
CCRCDCSoftwareAbort(CCR_CDC_DESTINATION_DRC0);
|
||||
|
||||
// Erase DRC
|
||||
if(CCRSysInitializeSettings() != 0){
|
||||
mErrorString = "Erase failed.";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mState = STATE_DONE;
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
CCRCDCSysConsoleShutdownInd(CCR_CDC_DESTINATION_DRC0); // Power off device to apply changes
|
||||
SYSLaunchMenu();
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FormatScreen::OnEraseCompleted()
|
||||
{
|
||||
mEraseComplete = true;
|
||||
}
|
29
source/screens/FormatScreen.hpp
Normal file
29
source/screens/FormatScreen.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include <map>
|
||||
|
||||
class FormatScreen : public Screen
|
||||
{
|
||||
public:
|
||||
FormatScreen();
|
||||
virtual ~FormatScreen();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
void OnEraseCompleted();
|
||||
|
||||
private:
|
||||
enum State {
|
||||
STATE_UPDATE,
|
||||
STATE_DONE,
|
||||
STATE_ERROR,
|
||||
} mState = STATE_UPDATE;
|
||||
|
||||
std::string mErrorString;
|
||||
|
||||
|
||||
bool mEraseComplete;
|
||||
};
|
@ -153,4 +153,4 @@ bool MainScreen::Update(VPADStatus& input)
|
||||
void MainScreen::DrawStatus(std::string status, SDL_Color color)
|
||||
{
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, color, status, Gfx::ALIGN_CENTER);
|
||||
}
|
||||
}
|
@ -1,21 +1,19 @@
|
||||
#include "MenuScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "AboutScreen.hpp"
|
||||
#include "FlashScreen.hpp"
|
||||
#include "FlashScreenPicker.hpp"
|
||||
#include "DrcScreenPicker.hpp"
|
||||
#include "InfoScreen.hpp"
|
||||
#include "SetRegionScreen.hpp"
|
||||
#include "EnableDKMenuScreen.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
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_ENABLE_DKMENU, { 0xf188, "Enable DK Menu" }},
|
||||
{ MENU_ID_ABOUT, { 0xf05a, "About DRXUtil" }},
|
||||
// { MENU_ID_EXIT, { 0xf057, "Exit" }},
|
||||
{ MENU_ID_INFO, { 0xf085, "Show DRC/DRH information" }},
|
||||
{ MENU_ID_FLASH, { 0xf019, "Flash..."}},
|
||||
{ MENU_ID_DRCOPS, { 0xf10a, "DRC operations..."}},
|
||||
{ MENU_ID_ABOUT, { 0xf05a, "About DRXUtil" }},
|
||||
// { MENU_ID_EXIT, { 0xf057, "Exit" }},
|
||||
})
|
||||
{
|
||||
|
||||
@ -75,13 +73,10 @@ bool MenuScreen::Update(VPADStatus& input)
|
||||
mSubscreen = std::make_unique<InfoScreen>();
|
||||
break;
|
||||
case MENU_ID_FLASH:
|
||||
mSubscreen = std::make_unique<FlashScreen>();
|
||||
mSubscreen = std::make_unique<FlashScreenPicker>();
|
||||
break;
|
||||
case MENU_ID_SET_REGION:
|
||||
mSubscreen = std::make_unique<SetRegionScreen>();
|
||||
break;
|
||||
case MENU_ID_ENABLE_DKMENU:
|
||||
mSubscreen = std::make_unique<EnableDKMenuScreen>();
|
||||
case MENU_ID_DRCOPS:
|
||||
mSubscreen = std::make_unique<DrcScreenPicker>();
|
||||
break;
|
||||
case MENU_ID_ABOUT:
|
||||
mSubscreen = std::make_unique<AboutScreen>();
|
||||
|
@ -20,8 +20,7 @@ private:
|
||||
enum MenuID {
|
||||
MENU_ID_INFO,
|
||||
MENU_ID_FLASH,
|
||||
MENU_ID_SET_REGION,
|
||||
MENU_ID_ENABLE_DKMENU,
|
||||
MENU_ID_DRCOPS,
|
||||
MENU_ID_ABOUT,
|
||||
|
||||
MENU_ID_MIN = MENU_ID_INFO,
|
||||
|
195
source/screens/PairScreen.cpp
Normal file
195
source/screens/PairScreen.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
#include "PairScreen.hpp"
|
||||
#include "Gfx.hpp"
|
||||
#include "ProcUI.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include <cstdio>
|
||||
|
||||
#include <nsysccr/cdc.h>
|
||||
#include <nsysccr/cfg.h>
|
||||
#include <nn/ccr.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#define TIMEOUT_SECONDS 45
|
||||
namespace {}
|
||||
|
||||
PairScreen::PairScreen():mTargetEntries({{DRC0, {0x31, "Main DRC"}}, {DRC1, {0x32, "Additional DRC"}},}){
|
||||
|
||||
// Initialize IM
|
||||
imHandle = IM_Open();
|
||||
imRequest = (IMRequest*) memalign(0x40, sizeof(IMRequest));
|
||||
// Allocate a separate request for IM_CancelGetEventNotify to avoid conflict with the pending IM_GetEventNotify request
|
||||
imCancelRequest = (IMRequest*) memalign(0x40, sizeof(IMRequest));
|
||||
|
||||
// Init CCRSys
|
||||
CCRSysInit();
|
||||
}
|
||||
PairScreen::~PairScreen(){
|
||||
CCRSysExit();
|
||||
|
||||
// Close IM
|
||||
IM_CancelGetEventNotify(imHandle, imCancelRequest, nullptr, nullptr);
|
||||
IM_Close(imHandle);
|
||||
free(imCancelRequest);
|
||||
free(imRequest);
|
||||
}
|
||||
void PairScreen::Draw()
|
||||
{
|
||||
DrawTopBar("PairScreen");
|
||||
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_SELECT_TARGET: {
|
||||
for (TargetID id = DRC0; id <= DRC1; id = static_cast<TargetID>(id + 1)) {
|
||||
int yOff = 75 + static_cast<int>(id) * 150;
|
||||
Gfx::DrawRectFilled(0, yOff, Gfx::SCREEN_WIDTH, 150, Gfx::COLOR_ALT_BACKGROUND);
|
||||
Gfx::DrawIcon(68, yOff + 150 / 2, 60, Gfx::COLOR_TEXT, mTargetEntries[id].icon);
|
||||
Gfx::Print(128 + 8, yOff + 150 / 2, 60, Gfx::COLOR_TEXT, mTargetEntries[id].name, Gfx::ALIGN_VERTICAL);
|
||||
|
||||
if (id == mTarget) {
|
||||
Gfx::DrawRect(0, yOff, Gfx::SCREEN_WIDTH, 150, 8, Gfx::COLOR_HIGHLIGHTED);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_GETPIN: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT, "Getting pincode...", Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_WAITING: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("Got WPS PIN! \n"
|
||||
"Pincode: %i\n"
|
||||
"GamePad keyboard: 0213", pincodebuffer), Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_TEXT,
|
||||
Utils::sprintf("DRC paired successfully"),
|
||||
Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
Gfx::Print(Gfx::SCREEN_WIDTH / 2, Gfx::SCREEN_HEIGHT / 2, 64, Gfx::COLOR_ERROR, "Error:\n" + mErrorString, Gfx::ALIGN_CENTER);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (mState == STATE_SELECT_TARGET) {
|
||||
DrawBottomBar("\ue07d Navigate", "\ue044 Exit", "\ue000 Confirm / \ue001 Back");
|
||||
} else if (mState == STATE_GETPIN) {
|
||||
DrawBottomBar(nullptr, "Please wait...", nullptr);
|
||||
} else if (mState == STATE_WAITING) {
|
||||
DrawBottomBar(nullptr, "Press SYNC to cancel pairing", nullptr);
|
||||
} else {
|
||||
DrawBottomBar(nullptr, nullptr, "\ue001 Back");
|
||||
}
|
||||
}
|
||||
|
||||
bool PairScreen::Update(VPADStatus& input) // This is the core logic part
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
case STATE_SELECT_TARGET: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_A) {
|
||||
mState = STATE_GETPIN;
|
||||
break;
|
||||
}
|
||||
|
||||
if (input.trigger & VPAD_BUTTON_DOWN) {
|
||||
if (mTarget < DRC1) {
|
||||
mTarget = static_cast<TargetID>(mTarget + 1);
|
||||
}
|
||||
} else if (input.trigger & VPAD_BUTTON_UP) {
|
||||
if (mTarget > DRC0) {
|
||||
mTarget = static_cast<TargetID>(mTarget - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_GETPIN: {
|
||||
cancelPairing = false;
|
||||
imEventMask = IM_EVENT_SYNC;
|
||||
IM_GetEventNotify(imHandle, imRequest, &imEventMask, PairScreen::SyncButtonCallback, &imEventMask);
|
||||
// Get a PIN code to display.
|
||||
if (CCRSysGetPincode(&pincodebuffer) != 0){
|
||||
mErrorString = "Could not obtain the PIN!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
switch (mTarget) {
|
||||
case DRC0: {
|
||||
if (CCRSysStartPairing(0, TIMEOUT_SECONDS) != 0) {
|
||||
mErrorString = "Could not start pairing!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mState = STATE_WAITING;
|
||||
break;
|
||||
}
|
||||
case DRC1: {
|
||||
if (CCRCDCSetMultiDrc(2) != 0) {
|
||||
mErrorString = "Could not enable MultiDRC mode!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
if (CCRSysStartPairing(1, TIMEOUT_SECONDS) != 0) {
|
||||
mErrorString = "Could not start pairing!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
}
|
||||
mState = STATE_WAITING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
case STATE_WAITING: {
|
||||
CCRSysPairingState pairingState = CCRSysGetPairingState();
|
||||
if (pairingState == CCR_SYS_PAIRING_TIMED_OUT || cancelPairing) {
|
||||
// Pairing has timed out or was cancelled
|
||||
CCRSysStopPairing();
|
||||
mErrorString = "Pairing was stopped!";
|
||||
mState = STATE_ERROR;
|
||||
break;
|
||||
} else if (pairingState == CCR_SYS_PAIRING_FINISHED) {
|
||||
// DRC was paired
|
||||
mState = STATE_DONE;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_DONE: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case STATE_ERROR: {
|
||||
if (input.trigger & VPAD_BUTTON_B) {
|
||||
ProcUI::SetHomeButtonMenuEnabled(true);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void PairScreen::SyncButtonCallback(IOSError error, void* arg)
|
||||
{
|
||||
uint32_t event = *(uint32_t*) arg;
|
||||
|
||||
// Cancel pairing if the sync button was pressed
|
||||
if (error == IOS_ERROR_OK && (event & IM_EVENT_SYNC)) {
|
||||
cancelPairing = true;
|
||||
}
|
||||
}
|
||||
|
||||
void PairScreen::OnPairingCompleted()
|
||||
{
|
||||
mPairingComplete = true;
|
||||
}
|
45
source/screens/PairScreen.hpp
Normal file
45
source/screens/PairScreen.hpp
Normal file
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include "Screen.hpp"
|
||||
#include <map>
|
||||
#include <coreinit/im.h>
|
||||
|
||||
class PairScreen : public Screen
|
||||
{
|
||||
public:
|
||||
PairScreen();
|
||||
virtual ~PairScreen();
|
||||
|
||||
void Draw();
|
||||
|
||||
bool Update(VPADStatus& input);
|
||||
|
||||
void OnPairingCompleted();
|
||||
|
||||
private:
|
||||
static void SyncButtonCallback(IOSError error, void* arg);
|
||||
static inline bool cancelPairing;
|
||||
IOSHandle imHandle;
|
||||
IMRequest* imRequest;
|
||||
IMRequest* imCancelRequest;
|
||||
IMEventMask imEventMask;
|
||||
enum State {
|
||||
STATE_SELECT_TARGET,
|
||||
STATE_GETPIN,
|
||||
STATE_WAITING,
|
||||
STATE_DONE,
|
||||
STATE_ERROR,
|
||||
} mState = STATE_SELECT_TARGET;
|
||||
struct TargetEntry {
|
||||
uint16_t icon;
|
||||
const char* name;
|
||||
};
|
||||
enum TargetID {
|
||||
DRC0,
|
||||
DRC1,
|
||||
} mTarget = DRC0;
|
||||
std::map<TargetID, TargetEntry> mTargetEntries;
|
||||
std::string mErrorString;
|
||||
uint32_t pincodebuffer;
|
||||
bool mPairingComplete;
|
||||
};
|
@ -34,4 +34,6 @@ private:
|
||||
REGION_AUSTRALIA = 6,
|
||||
} mRegion = REGION_JAPAN;
|
||||
std::map<Region, std::string> mRegionEntries;
|
||||
|
||||
std::string mErrorText;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user