ctr_Repair/trunk/ConsoleDataMigration/ConsoleRestore/Controller.cpp
N2614 9f0e693e94 同一本体への書き戻しを区別するように
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@62 385bec56-5757-e545-9c3a-d8741f4650f1
2011-02-16 09:02:41 +00:00

790 lines
24 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*---------------------------------------------------------------------------*
Project: Horizon
File: Controller.cpp
Copyright 2009 Nintendo. All rights reserved.
These coded instructions, statements, and computer programs contain
proprietary information of Nintendo of America Inc. and/or Nintendo
Company Ltd., and are protected by Federal copyright law. They may
not be disclosed to third parties or copied or duplicated in any form,
in whole or in part, without the prior written consent of Nintendo.
$Rev$
*---------------------------------------------------------------------------*/
#include <nn.h>
#include <nn/ns.h>
#include <nn/CTR/CTR_DeliverArg.h>
#include <nn/fs/CTR/MPCore/fs_FileSystemBasePrivate.h>
#include <nn/ptm/CTR/ptm_ApiSysmenu.h>
#include <nn/ptm/CTR/ptm_ApiSystem.h>
#include <nn/pl/CTR/pl_PlayHistoryApiSysmenu.h>
#include "Controller.h"
#include "FileChecker.h"
#include "ConsoleRestore.h"
#include "SimplePlayer.h"
#include "CommonLogger.h"
#include "Importer.h"
#include "Updater.h"
#include "NtpClient.h"
namespace ConsoleRestore
{
namespace
{
typedef enum RestoreState
{
STARTUP, // 初期値
SERIAL_IS_NOT_IN_SD, // シリアルナンバーファイルがSDカードにないことを表示
SERIAL_IN_SD, // シリアルナンバーの情報を表示
UPDATE_IN_PROGRESS, // アップデート中
UPDATE_DONE, // アップデート完了
RESTORE_TWL_SOUND, // TWLサウンドの書き込み中
RESTORE_TWL_PHOTO, // TWL写真の書き込み中
RESTORE_IN_PROGRESS, // 書き込み中
POST_RESTORE, // 書き込み後の処理
RESTORE_DONE, // 書き込み完了
REBOOTING, // 再起動を行う
ERASE, // 削除処理を行う
HISTORY_RECOVER, // プレイ履歴の書き戻しを行う
TIME_ADJUST, // 時計あわせを行う
WAIT_SD_EJECT, // SDカードぬき待ち
ALL_DONE, // すべて完了
SHUTDOWN, // シャットダウン中
FAIL // 失敗
} RestoreState;
// Restore状態管理
RestoreState s_RestoreState = STARTUP;
// インターネット設定を読んだかどうか
bool s_ReadSettingDone = false;
// インターネット設定を読んだ結果
bool s_ReadSettingSuccess = false;
// APSettingの書式が無い警告サウンドを鳴らしたかどうか
bool s_ExistAPSettingAnnotation = false;
// APSettingの書式が違っている警告サウンドを鳴らしたかどうか
bool s_APSettingAnnotation = false;
// シリアルナンバーがない警告サウンドを鳴らしたかどうか
bool s_SerialNumberAnnotation = false;
// 失敗サウンドを鳴らしたかどうか
bool s_PlayedFailSound = false;
// 操作開始サウンドを鳴らしたかどうか
bool s_PlayedStartCursor = false;
// リブート開始前サウンドを鳴らしたかどうか
bool s_PlayedRebootCursor = false;
// SD抜き出し前サウンドを鳴らしたかどうか
bool s_PlayedSdPullOutCursor = false;
// ネットワークアップデートを開始したかどうか
bool s_ExecuteFgNup = false;
// FGNUPを何回リトライしたか
u32 s_FgNupRetryCount = 0;
} // namespace <unnamed>
bool NeedsAcAdater()
{
return IsBatteryLower() && !IsAdapterConnected();
}
bool CheckAndReadAPSetting(::std::vector<std::string>& operationMessage)
{
using namespace common;
if (!ExistsAPSetting())
{
if(!s_ExistAPSettingAnnotation)
{
s_ExistAPSettingAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
operationMessage.push_back(::std::string("Accsess_Point_Setting does not exist!"));
return false;
}
// 設定ファイルからAP設定を読み込む
if (!s_ReadSettingDone)
{
s_ReadSettingDone = true;
s_ReadSettingSuccess = ReadSetting();
}
if (!s_ReadSettingSuccess)
{
operationMessage.push_back(::std::string("Invalid Accsess_Point_Setting format!"));
if(!s_APSettingAnnotation)
{
s_APSettingAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
}
return s_ReadSettingSuccess;
}
void PutAliveMessage(::std::vector<std::string>& operationMessage, const char* str)
{
std::string message = std::string(str);
static u8 i = 0;
if (i < 0xff / 4)
{
operationMessage.push_back(message + std::string(" /"));
}
else if (i < 0xff * 2 / 4)
{
operationMessage.push_back(message + std::string(" |"));
}
else if (i < 0xff * 3 / 4)
{
operationMessage.push_back(message + std::string(" \\"));
}
else
{
operationMessage.push_back(message + std::string(" -"));
}
i += 4;
}
void ExecSyncMcuRtc()
{
if(!common::ExistsRtcSyncFinishedFile())
{
ImportMcuRtc();
// 時計を無効化する
CreateRtcSyncFinishedFile();
}
}
void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep, bool& continueRestore, bool specialKey)
{
using namespace common;
// 状態遷移Controller
switch (s_RestoreState)
{
// 起動時
case STARTUP:
{
bool error = false;
bool needsUpdate = false;
bool needsErase = false;
// SDカードが挿入されているか
if (nn::fs::IsSdmcInserted())
{
// SDカードにアップデート完了ファイルがあるか
if (ExistsUpdateCheckedFile())
{
// SDカードに書き込み完了ファイルがあるか
if (!ExistsWriteFinishedFile())
{
// IVSを読めるか
if (CanReadIVS())
{
// 本体初期化完了ファイルがあるか?
if (ExistsConsoleInitializedFile())
{
// SDカードにシリアルナンバーがあるか
if (!ExistsSerialNumberFile())
{
COMMON_LOGGER("Can't Read Serial Number in SD Card!!\n");
error = true;
s_RestoreState = SERIAL_IS_NOT_IN_SD;
}
else
{
::std::string serial(reinterpret_cast<char*> (ReadSerialNumber()));
operationMessage.push_back(::std::string("Serial Number in SD : ") + serial);
}
// SDカードにIVSがあるか
if (!ExistsIVSFile())
{
// 移行不能なのでFAIL
COMMON_LOGGER("Can't Read IVS in SD Card!!\n");
error = true;
s_RestoreState = FAIL;
}
else
{
// SDカードに書き込みできるか
if (nextStep && !nn::fs::IsSdmcWritable())
{
error = true;
PlaySound(SOUND_ANNOTATION);
COMMON_LOGGER("Can't Write SD Card!!\n");
}
}
}
else
{
COMMON_LOGGER("Initialize Console\n");
// SDカードのIVSと本体のIVSは異なるか
if (EqualsIVSFileandIVS())
{
// 同一本体に書き戻そうとしたファイルを作る
COMMON_LOGGER("Restore to the same console. Initialize.\n");
CreateTryRestoreSameConsoleFile();
}
else
{
// 本体初期化完了ファイルを作る
CreateConsoleInitializedFile();
}
// ファイルシステムの初期化を行う
InitializeFileSystem();
error = true;
s_RestoreState = REBOOTING;
}
}
else
{
error = true;
operationMessage.push_back(::std::string("Can't Read IVS!!"));
}
}
else
{
if(CheckAndReadAPSetting(operationMessage))
{
// 削除処理を行う
needsErase = true;
}
else
{
error = true;
}
}
}
else
{
if (CheckAndReadAPSetting(operationMessage))
{
// ネットワークアップデートを行う
needsUpdate = true;
}
else
{
error = true;
}
}
}
else
{
error = true;
operationMessage.push_back(::std::string("Insert SD Card!!"));
}
// ACアダプタが必要か
if (NeedsAcAdater())
{
error = true;
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
}
// エラーが無ければ進行用メッセージ表示
if (!error)
{
operationMessage.push_back(::std::string("Push A or START Button"));
if(needsUpdate)
{
operationMessage.push_back(::std::string("Network Update Mode"));
}
else if(needsErase)
{
operationMessage.push_back(::std::string("Clock Sync Mode"));
}
else
{
operationMessage.push_back(::std::string("Import Data Mode"));
}
if(!s_PlayedStartCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedStartCursor = true;
}
}
if(specialKey)
{
s_RestoreState = SHUTDOWN;
}
if (nextStep && !error && !specialKey)
{
if (needsUpdate)
{
COMMON_LOGGER("Start Network Update\n");
// RTC同期を行う
// でいるだけ早いタイミングで同期したいがフラグ用ファイルの存在確認に
// 失敗するのでここで同期する
ExecSyncMcuRtc();
s_RestoreState = UPDATE_IN_PROGRESS;
}
else if(needsErase)
{
COMMON_LOGGER("Erase Trash\n");
s_RestoreState = ERASE;
}
else
{
COMMON_LOGGER("Start Import Data\n");
s_RestoreState = RESTORE_TWL_SOUND;
}
}
}
break;
// シリアルナンバーがSDカードにないこと警告
case SERIAL_IS_NOT_IN_SD:
{
operationMessage.push_back(::std::string("Serial Number Is Not In SD Card"));
operationMessage.push_back(::std::string("Push A or START Button"));
operationMessage.push_back(::std::string("Import Data Mode"));
if (!s_SerialNumberAnnotation)
{
s_SerialNumberAnnotation = true;
PlaySound(SOUND_ANNOTATION);
}
if(specialKey)
{
s_RestoreState = SHUTDOWN;
}
if (nextStep && !specialKey)
{
s_RestoreState = RESTORE_TWL_SOUND;
}
}
break;
// アップデート中
case UPDATE_IN_PROGRESS:
{
continueRestore = true;
// ACアダプタが必要か
if (NeedsAcAdater())
{
continueRestore = false;
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
}
// アップデートを行う
if(!s_ExecuteFgNup)
{
ImportCountryLanguageData();
StartFGNetworkUpdate();
s_ExecuteFgNup = true;
}
// 動いていることを表示
{
PutAliveMessage(operationMessage, "Updating");
}
if (IsNetworkUpdateFinished())
{
FinishFGNetworkUpdate();
// エラーがあったら表示する
if(GetUpdateResult().IsFailure())
{
// APが見つからない
if(GetUpdateResult() == nn::ac::ResultNotFoundAccessPoint())
{
COMMON_LOGGER("No Access Point Found!");
}
}
if (GetUpdateResult().IsSuccess())
{
COMMON_LOGGER("Network Update Finished.\n");
// アップデート完了ファイルを作成
CreateUpdateFinishedFile();
s_RestoreState = UPDATE_DONE;
}
else
{
if (s_FgNupRetryCount++ < RETRY_MAX)
{
// エラーのためやり直す
COMMON_LOGGER_RESULT_IF_FAILED(GetUpdateResult());
COMMON_LOGGER("Network Update Failed. Retrying... %d\n", s_FgNupRetryCount);
// FGNUP用のスレッドを作るとこからやり直し
s_ExecuteFgNup = false;
}
else
{
s_RestoreState = FAIL;
}
}
}
}
break;
// アップデート完了
case UPDATE_DONE:
{
operationMessage.push_back(::std::string("Network Update Done."));
operationMessage.push_back(::std::string("Press A or START Button to Reboot"));
if(!s_PlayedRebootCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedRebootCursor = true;
}
if (nextStep)
{
s_RestoreState = REBOOTING;
}
}
break;
// TWLサウンド領域の書き込み中
case RESTORE_TWL_SOUND:
{
static bool init = true;
if (init)
{
// データを書き込む
ImportTwlSoundData();
init = false;
}
// 処理が完了した
if (IsImportFinished())
{
FinalizeImportThread();
s_RestoreState = RESTORE_TWL_PHOTO;
}
}
break;
// TWL写真領域の書き込み
case RESTORE_TWL_PHOTO:
{
static bool init = true;
if (init)
{
// データを書き込む
ImportTwlPhotoData();
init = false;
}
// 処理が完了した
if (IsImportFinished())
{
FinalizeImportThread();
s_RestoreState = RESTORE_IN_PROGRESS;
}
}
break;
// 書き込み中
case RESTORE_IN_PROGRESS:
{
continueRestore = true;
// ACアダプタが必要か
if (NeedsAcAdater())
{
continueRestore = false;
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
}
// データを読み込む
ImportData();
// 処理が完了した
if (continueRestore && IsImportFinished())
{
COMMON_LOGGER("Import NAND Data Finished.\n");
if (GetProgress() > 99)
{
s_RestoreState = POST_RESTORE;
}
else
{
s_RestoreState = FAIL;
}
}
}
break;
// リブート中
case REBOOTING:
{
static bool init = true;
if (init)
{
// ErrDispから引用
// 権限をもらえば成功するはず
nn::Result result = nn::ns::CTR::InitializeForShell();
if (result.IsSuccess())
{
COMMON_LOGGER("System Reboot.\n");
nn::ns::CTR::HardwareResetAsync(nn::CTR::MEMORY_ARRANGE_NORMAL);
while (!nn::applet::IsExpectedToCloseApplication())
{
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(5));
}
nn::ns::CTR::FinalizeForShell();
// INFO: リブートは非同期のため処理は継続
}
init = false;
}
}
break;
// 書き込み後の処理
case POST_RESTORE:
{
operationMessage.push_back(::std::string("Post Process..."));
// 書き込み完了ファイルを作成
CreateWriteFinishedFile();
s_RestoreState = RESTORE_DONE;
}
break;
// 書き込み完了
case RESTORE_DONE:
{
operationMessage.push_back(::std::string("Restore Done."));
operationMessage.push_back(::std::string("Press A or START Button to Reboot"));
if(!s_PlayedRebootCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedRebootCursor = true;
}
if (nextStep)
{
s_RestoreState = REBOOTING;
}
}
break;
// 削除処理
case ERASE:
{
Cleanup();
s_RestoreState = HISTORY_RECOVER;
}
break;
// 削除処理
case HISTORY_RECOVER:
{
static bool init = true;
if (init)
{
// ptmのセーブデータ移行後に時計を無効化する
nn::ptm::CTR::InvalidateSystemTime();
// 同じ本体に書き戻す場合は初期化しない
if (!ExistsTryRestoreSameConsoleFile())
{
// cfgのハードウェア固有情報をcal値で初期化する
InitializeHardwareDependentSetting();
}
init = false;
}
s_RestoreState = TIME_ADJUST;
}
// 時計あわせ
case TIME_ADJUST:
{
static bool init = true;
if(init)
{
COMMON_LOGGER("Adjust Time\n");
AdjustTime();
init = false;
}
// 動いていることを表示
{
PutAliveMessage(operationMessage, "Sync Clock");
}
if(IsTimeAdjustFinished())
{
if(IsTimeAdjustSuccessed())
{
s_RestoreState = WAIT_SD_EJECT;
}
else
{
s_RestoreState = FAIL;
}
// リストア状態チェックファイルをすべて削除
DeleteAllCheckFiles();
}
}
break;
// すべて完了
case WAIT_SD_EJECT:
{
operationMessage.push_back(::std::string("ALL Done. Pull Out SD Card."));
// SDカード抜けのみで次の状態に遷移する
if (!s_PlayedSdPullOutCursor)
{
common::PlaySound(common::SOUND_CURSOR);
s_PlayedSdPullOutCursor = true;
}
}
break;
// すべて完了
case ALL_DONE:
{
operationMessage.push_back(::std::string("Restore Succeeded!!"));
static bool init = true;
if (init)
{
PlaySound(SOUND_OK);
init = false;
}
}
break;
// 書き込み失敗
case FAIL:
{
operationMessage.push_back(::std::string("Failed."));
if (!s_PlayedFailSound)
{
PlaySound(SOUND_NG);
s_PlayedFailSound = true;
}
}
break;
case SHUTDOWN:
{
// リストア状態チェックファイルをすべて削除
DeleteAllCheckFiles();
// 本体初期化を行う
InitializeFileSystem();
// シャットダウンする
nn::ptm::CTR::ShutdownAsync(0, nn::fnd::TimeSpan::FromSeconds(0));
}
}
}
bool InProgress()
{
return s_RestoreState == RESTORE_IN_PROGRESS;
}
bool IsRestoreSucceeded()
{
return s_RestoreState == ALL_DONE;
}
bool IsRestoreFailed()
{
return s_RestoreState == FAIL;
}
void OnSdEjected()
{
if(s_RestoreState == WAIT_SD_EJECT || s_RestoreState == ALL_DONE)
{
s_RestoreState = ALL_DONE;
}
// FAILのときは一旦電源を切らないと動かないようにしておく
else if(s_RestoreState != FAIL)
{
InitializeState();
ClearFileReadResult();
}
}
void InitializeState()
{
s_RestoreState = STARTUP;
common::InitializeFileCheck();
s_ExistAPSettingAnnotation = false;
s_ReadSettingDone = false;
s_ReadSettingSuccess = false;
s_APSettingAnnotation = false;
s_SerialNumberAnnotation = false;
s_PlayedFailSound = false;
s_ExecuteFgNup = false;
s_FgNupRetryCount = 0;
s_PlayedStartCursor = false;
s_PlayedRebootCursor = false;
s_PlayedSdPullOutCursor = false;
}
u32 GetProgress()
{
if(s_RestoreState == RESTORE_TWL_SOUND ||
s_RestoreState == RESTORE_TWL_PHOTO ||
s_RestoreState == RESTORE_IN_PROGRESS ||
s_RestoreState == POST_RESTORE ||
s_RestoreState == RESTORE_DONE)
{
return GetImportProgress();
}
else if(s_RestoreState == UPDATE_IN_PROGRESS ||
s_RestoreState == UPDATE_DONE)
{
return GetUpdateProgress();
}
else
{
return 0;
}
}
} // namespace ConsoleRestore