ctr_Repair/trunk/ConsoleDataMigration/ConsoleRestore/Controller.cpp
N2614 45fee26050 ネットワークアップデート完了後の再起動前にボタン操作を待つように
操作の前にカーソル音を鳴らすように

git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@42 385bec56-5757-e545-9c3a-d8741f4650f1
2011-02-10 00:58:05 +00:00

755 lines
23 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 "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, // すべて完了
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 APSetting.txt 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)
{
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カードのIVSと本体のIVSは異なるか
if (EqualsIVSFileandIVS())
{
COMMON_LOGGER("Restore data to the same Console. Initialize.\n");
// 本体初期化を行う
InitializeFileSystem();
error = true;
s_RestoreState = REBOOTING;
}
// 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");
// 本体初期化完了ファイルを作る
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 (nextStep && !error)
{
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 (nextStep)
{
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();
// 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;
}
}
}
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;
}
}
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;
}
else
{
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)
{
return GetUpdateProgress();
}
else
{
return 0;
}
}
} // namespace ConsoleRestore