ctr_Repair/trunk/ConsoleDataMigration/ConsoleRestore/Controller.cpp
N2614 89b4c7fdba RTCデータを移行するように
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@14 385bec56-5757-e545-9c3a-d8741f4650f1
2011-02-04 04:16:00 +00:00

628 lines
19 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 "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, // アップデート中
RESTORE_IN_PROGRESS, // 書き込み中
POST_RESTORE, // 書き込み後の処理
RESTORE_DONE, // 書き込み完了
REBOOTING, // 再起動を行う
ERASE, // 削除処理を行う
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_ExecuteFgNup = false;
// FGNUPを何回リトライしたか
u32 s_FgNupRetryCount = 0;
} // namespace <unnamed>
bool NeedsAcAdater()
{
return IsBatteryLower() && !IsAdapterConnected();
}
bool CheckAndReadAPSetting(::std::vector<std::string>& operationMessage)
{
if (!ExistsAPSetting())
{
if(!s_ExistAPSettingAnnotation)
{
s_ExistAPSettingAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
operationMessage.push_back(::std::string("APSetting.txt 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(!ExistsRtcSyncFinishedFile())
{
ImportMcuRtc();
// 時計を無効化する
nn::ptm::CTR::InvalidateSystemTime();
CreateRtcSyncFinishedFile();
}
}
void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep, bool& continueRestore)
{
// 状態遷移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;
common::PlaySound(common::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 (nextStep && !error)
{
if (needsUpdate)
{
COMMON_LOGGER("Start Network Update\n");
s_RestoreState = UPDATE_IN_PROGRESS;
common::PlaySound(common::SOUND_CURSOR);
}
else if(needsErase)
{
COMMON_LOGGER("Erase Trash\n");
s_RestoreState = ERASE;
common::PlaySound(common::SOUND_CURSOR);
}
else
{
COMMON_LOGGER("Start Import Data\n");
s_RestoreState = RESTORE_IN_PROGRESS;
common::PlaySound(common::SOUND_CURSOR);
}
}
}
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;
common::PlaySound(common::SOUND_ANNOTATION);
}
if (nextStep)
{
s_RestoreState = RESTORE_IN_PROGRESS;
}
}
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().IsSuccess())
{
COMMON_LOGGER("Network Update Finished.\n");
// アップデート完了ファイルを作成
CreateUpdateFinishedFile();
// リブートする
s_RestoreState = REBOOTING;
}
else
{
if (s_FgNupRetryCount++ < RETRY_MAX)
{
// エラーのためやり直す
COMMON_LOGGER_RESULT(GetUpdateResult());
COMMON_LOGGER("Network Update Failed. Retrying... %d\n", s_FgNupRetryCount);
// FGNUP用のスレッドを作るとこからやり直し
s_ExecuteFgNup = false;
}
else
{
s_RestoreState = FAIL;
}
}
}
}
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 (nextStep)
{
// RTC同期を行う
// RTC書き込み後できるだけ早いタイミングで再起動したいのでここで同期
ExecSyncMcuRtc();
s_RestoreState = REBOOTING;
}
}
break;
// 削除処理
case ERASE:
{
Cleanup();
s_RestoreState = TIME_ADJUST;
}
break;
// 時計あわせ
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カード抜けのみで次の状態に遷移する
}
break;
// すべて完了
case ALL_DONE:
{
operationMessage.push_back(::std::string("Restore Succeeded!!"));
static bool init = true;
if (init)
{
common::PlaySound(common::SOUND_OK);
init = false;
}
}
break;
// 書き込み失敗
case FAIL:
{
operationMessage.push_back(::std::string("Failed."));
if (!s_PlayedFailSound)
{
common::PlaySound(common::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();
}
}
void InitializeState()
{
s_RestoreState = STARTUP;
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;
}
u32 GetProgress()
{
if(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