ctr_Repair/trunk/ConsoleDataMigration/sources/ConsoleRestore/Controller.cpp
N2614 542139a92b アカウント移行時にConnectせずにImportIvsFromInfrastructureを呼ぶように
git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@461 385bec56-5757-e545-9c3a-d8741f4650f1
2011-10-25 07:26:28 +00:00

1679 lines
51 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 <nn/cfg/CTR/cfg_ApiSys.h>
#include <nn/nwm.h>
#include "Controller.h"
#include "FileChecker.h"
#include "SimplePlayer.h"
#include "CommonLogger.h"
#include "Importer.h"
#include "Updater.h"
#include "NtpClient.h"
#include "TitleDownloader.h"
#include "Shop.h"
#include "Util.h"
namespace ConsoleRestore
{
namespace
{
// ネットワーク設定ファイルを読んだかどうか
bool s_ReadSettingDone = false;
// インターネット設定を読んだ結果
bool s_ReadSettingIsSuccess = false;
// NUP専用モードかどうか
bool s_NupOnlyMode = false;
// IVS取得専用モードかどうか
bool s_GetIvsOnlyMode = false;
// SDカード確認専用モード
bool s_CheckSdOnlyMode = false;
// NUPスキップモードかどうか
bool s_SkipNupMode = 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;
// SDに書き込みできない警告サウンドを鳴らしたかどうか
bool s_SdWriteProetctAnnotation = false;
// WiFiがOFFである警告サウンドを鳴らしたかどうか
bool s_WifiStatusOffAnnotation = false;
// ネットワークアップデートを開始したかどうか
bool s_ExecuteFgNup = false;
// FGNUPを何回リトライしたか
u32 s_FgNupRetryCount = 0;
// 時計同期モードかどうか
bool s_IsSyncClock = false;
// TWLタイトルのダウンロードを開始したかどうか
bool s_ExecuteTitleDownload = false;
// TWLタイトルのダウンロードを何回リトライしたか
u32 s_TitleDownloadRetryCount = 0;
// ショップ処理を開始したかどうか
bool s_ShopOperationExecuted[SHOP_OPERATION_NUM_MAX];
// ショップ処理を何回リトライしたか
u32 s_ShopOperationRetryCount[SHOP_OPERATION_NUM_MAX];
void PutAliveMessage(::std::vector<std::string>& operationMessage, const char* str);
bool CheckAndReadAPSetting(::std::vector<std::string>& operationMessage);
bool NeedsAcAdater(common::HardwareStateManager& manager)
{
return manager.IsBatteryLower() && !manager.IsAdapterConnected();
}
bool HasValidRtcData()
{
return !s_CheckSdOnlyMode && !s_NupOnlyMode && !s_GetIvsOnlyMode;
}
typedef enum RestoreState
{
STARTUP, // 初期値
INITIALIZE_CONSOLE, // セーブデータ領域のNAND初期化を行う
SERIAL_IS_NOT_IN_SD, // シリアルナンバーファイルがSDカードにないことを表示
WAIT_START_UPDATE, // アップデート開始入力待ち
WAIT_START_IMPORT, // 書き込み開始入力待ち
WAIT_START_SYNC_CLOCK, // 時計合わせ開始入力待ち
IMPORT_RTC, // RTC同期
UPDATE_IN_PROGRESS, // アップデート中
UPDATE_DONE, // アップデート完了
NUP_ONLY_WAIT_SD_EJECT, // NUP_ONLYモードでSDカード抜き待ち
NUP_ONLY_WAIT_NEXT, // NUP_ONLYモードでキー入力待ち
WAIT_START_TRANSFER_ACCOUNT, // アカウント転送開始入力まち
TRANSFER_ACCOUNT, // アカウント転送を完了させる
TRANSFER_ACCOUNT_DONE, // アカウント転送完了
DOWNLOAD_IVS, // インフラからIVSを取得する
DOWNLOAD_IVS_DONE, // インフラからIVSを取得完了
DOWNLOAD_IVS_WAIT_NEXT, // IVS取得モードでキー入力待ち
CHECK_IVS, // IVSとSDカードのセーブデータディレクトリの一致を確認
CHECK_SD_DIRECTORY, // SDカードのIVS依存ディレクトリを探す
CHECK_SD_DIRECTORY_SUCCESS, // SDカードのIVS依存ディレクトリチェック完了
CHECK_SD_DIRECTORY_FAIL, // SDカードのIVS依存ディレクトリが見つからなかった
WAIT_START_DELETE_ACCOUNT, // ショップアカウント削除開始入力待ち,
DELETE_ACCOUNT, // ショップアカウントを削除する
DELETE_ACCOUNT_DONE, // ショップアカウント削除完了
SYNC_TICKET, // eTicketを同期する
READ_FILELIST, // ファイル一覧の読み込み
RESTORE_TWL_NAND, // TWL NANDの書き込み中
RESTORE_TWL_SOUND, // TWLサウンドの書き込み中
RESTORE_TWL_PHOTO, // TWL写真の書き込み中
RESTORE_IN_PROGRESS, // 書き込み中
POST_RESTORE, // 書き込み後の処理
RESTORE_DONE, // 書き込み完了
REBOOTING, // 再起動を行う
ERASE, // 削除処理を行う
RESTORE_CAL, // cfgの一部をcal値で上書きする
TIME_ADJUST, // 時計あわせを行う
DOWNLOAD_TWL, // TWLアプリ本体をダウンロードする
WAIT_SD_EJECT, // SDカードぬき待ち
ALL_DONE, // すべて完了
INITIALIZE_AND_SHUTDOWN, // 本体初期化後にシャットダウン中
FAIL // 失敗
} RestoreState;
// Restore状態管理
RestoreState s_RestoreState = STARTUP;
// Restoreモード管理
RestoreMode s_RestoreMode = RESTORE_MODE_RESTORE;
void CheckSdInserted(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckAcAdapter(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckSdWritable(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckApSetting(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckNupExecuted(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckDownloadIvs(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckAccountDeleted(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckAccountTransfered(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckWriteFinished(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckReadIvs(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckConsoleInitialized(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckExistsSerialNumber(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckIvsinSd(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
void CheckRegioinSd(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep);
// SDカード挿入チェック
void CheckSdInserted(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
if (nn::fs::IsSdmcInserted())
{
CheckAcAdapter(manager, message, goNextStep);
}
else
{
message.push_back(::std::string("Insert SD Card!!"));
s_RestoreState = STARTUP;
}
}
// ACアダプタが必要かどうかチェック
void CheckAcAdapter(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
// ACアダプタが必要か
if (NeedsAcAdater(manager))
{
message.push_back(::std::string("Connect AC Adapter!!"));
s_RestoreState = STARTUP;
}
else
{
CheckSdWritable(manager, message, goNextStep);
}
}
// SDカード書き込みチェック
void CheckSdWritable(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
// SDカードに書き込みできるか
if (nn::fs::IsSdmcWritable())
{
CheckApSetting(manager, message, goNextStep);
}
else
{
if (!s_SdWriteProetctAnnotation)
{
s_SdWriteProetctAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
message.push_back(::std::string("Can't Write SD Card!!\n"));
s_RestoreState = STARTUP;
}
}
// 設定ファイル書式チェック
void CheckApSetting(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
NN_UNUSED_VAR(manager);
NN_UNUSED_VAR(goNextStep);
if (CheckAndReadAPSetting(message))
{
s_RestoreState = IMPORT_RTC;
}
else
{
s_RestoreState = STARTUP;
}
}
// NUP済みかどうかチェック
void CheckNupExecuted(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
if (common::ExistsUpdateCheckedFile())
{
if (s_NupOnlyMode)
{
s_RestoreState = WAIT_START_DELETE_ACCOUNT;
}
else
{
CheckAccountDeleted(manager, message, goNextStep);
}
}
else
{
// NUPを実行
if (CheckAndReadAPSetting(message))
{
if (nn::nwm::CTR::IsWifiOn())
{
// ネットワークアップデートを行う
s_RestoreState = WAIT_START_UPDATE;
}
else
{
if (!s_WifiStatusOffAnnotation)
{
s_WifiStatusOffAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
message.push_back(::std::string("Wireless is Off\n"));
s_RestoreState = STARTUP;
}
}
}
}
// インフラからIVS取得済みかチェック
void CheckDownloadIvs(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
NN_UNUSED_VAR(message);
NN_UNUSED_VAR(goNextStep);
// IVS取得確認ファイルがあるか
if (common::ExistsDownloadIvsCheckedFile())
{
if(s_GetIvsOnlyMode)
{
s_RestoreState = DOWNLOAD_IVS_WAIT_NEXT;
}
else
{
CheckWriteFinished(manager, message, goNextStep);
}
}
else
{
COMMON_LOGGER("Download SDCI\n");
s_RestoreState = DOWNLOAD_IVS;
}
}
// アカウント削除済みかチェック
void CheckAccountDeleted(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
// アカウント削除確認ファイルがあるか?
if (common::ExistsDeleteAccountChecked())
{
CheckAccountTransfered(manager, message, goNextStep);
}
else
{
// 同一本体下記書き戻しの場合はアカウント削除しない
if(EqualsDeviceIdFileandDeviceId(manager).IsSuccess())
{
// IVS専用モードならばIVSを取得させる
if(s_GetIvsOnlyMode)
{
CheckDownloadIvs(manager, message, goNextStep);
}
else
{
CheckAccountTransfered(manager, message, goNextStep);
}
}
else
{
s_RestoreState = WAIT_START_DELETE_ACCOUNT;
}
}
}
// アカウント移行済みかチェック
void CheckAccountTransfered(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
// アカウント移行確認ファイルがあるか?
if (common::ExistsTransferAccountChecked())
{
CheckDownloadIvs(manager, message, goNextStep);
}
else
{
s_RestoreState = WAIT_START_TRANSFER_ACCOUNT;
}
}
// 書き込み完了かどうかチェック
void CheckWriteFinished(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
NN_UNUSED_VAR(goNextStep);
// SDカードに書き込み完了ファイルがあるか
if (common::ExistsWriteFinishedFile())
{
if (CheckAndReadAPSetting(message))
{
if (nn::nwm::CTR::IsWifiOn())
{
// 削除処理を行う
s_RestoreState = WAIT_START_SYNC_CLOCK;
}
else
{
if (!s_WifiStatusOffAnnotation)
{
s_WifiStatusOffAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
message.push_back(::std::string("Wireless is Off\n"));
}
}
}
else
{
CheckReadIvs(manager, message, goNextStep);
}
}
// IVSを読めるかどうかチェック
void CheckReadIvs(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
// IVSを読めるか
if (manager.CanReadIvs())
{
CheckConsoleInitialized(manager, message, goNextStep);
}
else
{
s_RestoreState = FAIL;
COMMON_LOGGER("Can't Read SDCI!!");
}
}
// 本体初期化済みかどうかチェック
void CheckConsoleInitialized(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
// 本体初期化完了ファイルがあるか?
if (common::ExistsConsoleInitializedFile())
{
CheckRegioinSd(manager, message, goNextStep);
}
else
{
CheckIvsinSd(manager, message, goNextStep);
}
}
// シリアルナンバーがあるかどうかチェック
void CheckExistsSerialNumber(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
NN_UNUSED_VAR(manager);
NN_UNUSED_VAR(message);
NN_UNUSED_VAR(goNextStep);
// SDカードにシリアルナンバーがあるか
if (common::ExistsSerialNumberFile())
{
u8 serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN];
nn::Result result = ReadSerialNumber(serial);
if (result.IsSuccess())
{
s_RestoreState = WAIT_START_IMPORT;
}
else
{
s_RestoreState = FAIL;
}
}
else
{
COMMON_LOGGER("Can't Read Serial Number in SD Card!!\n");
s_RestoreState = SERIAL_IS_NOT_IN_SD;
}
}
// SDカードにIVSがあるかどうかチェック
void CheckIvsinSd(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
NN_UNUSED_VAR(manager);
NN_UNUSED_VAR(message);
NN_UNUSED_VAR(goNextStep);
if (common::ExistsIVSFile())
{
s_RestoreState = INITIALIZE_CONSOLE;
}
else
{
// 移行不能なのでFAIL
COMMON_LOGGER("Can't Read SDCI in SD Card!!\n");
s_RestoreState = FAIL;
}
}
// SDカードにリージョンデータがあるかどうかチェック
void CheckRegioinSd(common::HardwareStateManager& manager, ::std::vector<std::string>& message, bool& goNextStep)
{
NN_UNUSED_VAR(message);
NN_UNUSED_VAR(goNextStep);
// SDカードにリージョンデータがあるか
if (common::ExistsRegionData())
{
// リージョンデータは一致しているか?
if (EqualsRegionDataandRegion().IsFailure())
{
COMMON_LOGGER("Current Region and Region in SD differ!!\n");
s_RestoreState = FAIL;
}
else
{
CheckExistsSerialNumber(manager, message, goNextStep);
}
}
else
{
// 移行不能なのでFAIL
COMMON_LOGGER("Can't Read Region in SD Card!!\n");
s_RestoreState = FAIL;
}
}
void ShopOperationSuccess(ShopOperation op, const char* logMessage, RestoreState nextState)
{
COMMON_LOGGER("%s", logMessage);
if (op == SHOP_OPERATION_UNREGISTER || op == SHOP_OPERATION_FORCE_UNREGISTER)
{
CreateDeleteAccountFinishedFile();
}
else if (op == SHOP_OPERATION_GET_IVS)
{
CreateTransferAccountFinishedFile();
CreateDownloadIvsFinishedFile();
}
s_RestoreState = nextState;
}
void ShopOperationSingleTemplate(
common::HardwareStateManager& manager,
std::vector<std::string>& message,
ShopOperation op,
const char* aliveMessage,
const char* logMessage,
const char* retryLogMessage,
RestoreState nextState
)
{
// ACアダプタが必要か
if (NeedsAcAdater(manager))
{
message.push_back(::std::string("Connect AC Adapter!!"));
}
// アップデートを行う
if (!s_ShopOperationExecuted[op])
{
if (ImportCountryLanguageData().IsSuccess())
{
StartShopOperationSingle(op);
s_ShopOperationExecuted[op] = true;
}
else
{
s_RestoreState = FAIL;
}
}
// 動いていることを表示
{
PutAliveMessage(message, aliveMessage);
}
if (IsShopOperationSingleFinished())
{
FinalizeShopOperationSingle();
// エラーがあったら表示する
if (GetShopOperationSingleResult().IsSuccess())
{
ShopOperationSuccess(op, logMessage, nextState);
}
// IVSがアップロードされていない場合もあるため
// IVSを取得できない状況も成功として扱う
// IVSサイズが違う場合も成功として扱う
else if(op == SHOP_OPERATION_GET_IVS && ( GetShopOperationSingleResult() == nn::nim::ResultCannotGetIvs() ||
GetShopOperationSingleResult() == nn::nim::ResultInvalidData()
))
{
ShopOperationSuccess(op, logMessage, nextState);
}
else if(op == SHOP_OPERATION_CONNECT && nextState == TRANSFER_ACCOUNT_DONE &&
GetShopOperationSingleResult() == nn::nim::ResultNeedGetIvs())
{
NN_LOG("ResultNeedGetIvs\n");
ShopOperationSuccess(op, logMessage, nextState);
}
else
{
if (GetShopOperationSingleResult().IsFailure())
{
if (GetShopOperationSingleResult() == nn::ac::ResultFailedConnectAp())
{
COMMON_LOGGER("Failed Connect AccesPoint.");
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromSeconds(5));
}
// APが見つからない
if (GetUpdateResult() == nn::ac::ResultNotFoundAccessPoint())
{
COMMON_LOGGER("No Access Point Found!");
}
}
if (s_ShopOperationRetryCount[op]++ < RETRY_MAX)
{
// エラーのためやり直す
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult());
COMMON_LOGGER("%s %d\n", retryLogMessage, s_ShopOperationRetryCount[op]);
// スレッドを作るとこからやり直し
s_ShopOperationExecuted[op] = false;
}
else
{
s_RestoreState = FAIL;
}
}
}
}
void UpdateOperation(common::HardwareStateManager& manager, ::std::vector<std::string>& message, RestoreState nextState)
{
// ACアダプタが必要か
if (NeedsAcAdater(manager))
{
message.push_back(::std::string("Connect AC Adapter!!"));
}
// アップデートを行う
if (!s_ExecuteFgNup)
{
if (ImportCountryLanguageData().IsSuccess())
{
StartFGNetworkUpdate();
s_ExecuteFgNup = true;
}
else
{
s_RestoreState = FAIL;
}
}
// 動いていることを表示
{
PutAliveMessage(message, "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");
if(nextState == UPDATE_DONE)
{
// アップデート完了ファイルを作成
CreateUpdateFinishedFile();
}
s_RestoreState = nextState;
}
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;
}
}
}
}
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_ReadSettingIsSuccess = ReadSetting(&s_NupOnlyMode, &s_GetIvsOnlyMode, &s_CheckSdOnlyMode, &s_SkipNupMode);
}
if (s_NupOnlyMode && s_GetIvsOnlyMode
|| s_GetIvsOnlyMode && s_CheckSdOnlyMode
|| s_CheckSdOnlyMode && s_NupOnlyMode)
{
operationMessage.push_back("Only one special mode setting is valid!!");
s_ReadSettingIsSuccess = false;
}
else if(s_NupOnlyMode && s_SkipNupMode)
{
operationMessage.push_back("Both NUP_ONLY and SKIP_NUP are described!!");
s_ReadSettingIsSuccess = false;
}
else
{
if (s_NupOnlyMode)
{
s_RestoreMode = RESTORE_MODE_NUP_ONLY;
}
if (s_GetIvsOnlyMode)
{
s_RestoreMode = RESTORE_MODE_GET_IVS;
}
if(s_CheckSdOnlyMode)
{
s_RestoreMode = RESTORE_MODE_CHECK_SD;
}
}
if (!s_ReadSettingIsSuccess)
{
operationMessage.push_back(::std::string("Invalid Accsess_Point_Setting format!"));
if(!s_APSettingAnnotation)
{
s_APSettingAnnotation = true;
common::PlaySound(common::SOUND_ANNOTATION);
}
}
return s_ReadSettingIsSuccess;
}
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;
}
nn::Result ExecSyncMcuRtc(common::HardwareStateManager& manager)
{
nn::Result result = nn::ResultSuccess();
if(!common::ExistsRtcSyncFinishedFile())
{
result = ImportMcuRtc(manager);
if(result.IsSuccess())
{
// RTCを同期完了ファイルを作る
CreateRtcSyncFinishedFile();
}
}
return result;
}
} // namespace <unnamed>
void ControlState(common::HardwareStateManager& manager, ::std::vector<std::string>& operationMessage, bool& nextStep)
{
using namespace common;
nn::Result result;
// 状態遷移Controller
switch (s_RestoreState)
{
// 起動時
case STARTUP:
{
CheckSdInserted(manager, operationMessage, nextStep);
}
break;
case INITIALIZE_CONSOLE:
{
COMMON_LOGGER("Initialize Console\n");
// 本体初期化完了ファイルを作る
CreateConsoleInitializedFile();
// ファイルシステムの初期化を行う
if(InitializeFileSystem())
{
s_RestoreState = REBOOTING;
}
else
{
s_RestoreState = FAIL;
}
}
break;
case WAIT_START_UPDATE:
{
operationMessage.push_back(::std::string("Push A or START Button"));
operationMessage.push_back(::std::string("Network Update Mode"));
if (!s_PlayedStartCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedStartCursor = true;
}
if (nextStep)
{
COMMON_LOGGER("Start Network Update\n");
s_RestoreState = UPDATE_IN_PROGRESS;
}
}
break;
case WAIT_START_IMPORT:
{
u8 serial[nn::cfg::CTR::CFG_SECURE_INFO_SERIAL_NO_LEN];
result = ReadSerialNumber(serial);
if (result.IsSuccess())
{
::std::string serialStr(reinterpret_cast<char*> (serial));
operationMessage.push_back(::std::string("Serial Number in SD : ") + serialStr);
}
else
{
s_RestoreState = FAIL;
}
operationMessage.push_back(::std::string("Push A or START Button"));
operationMessage.push_back(::std::string("Import Data Mode"));
if (!s_PlayedStartCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedStartCursor = true;
}
if (nextStep)
{
s_RestoreState = READ_FILELIST;
}
}
break;
case WAIT_START_SYNC_CLOCK:
{
operationMessage.push_back(::std::string("Push A or START Button"));
operationMessage.push_back(::std::string("DownLoad Twl Title and Clock Sync Mode"));
if (!s_PlayedStartCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedStartCursor = true;
}
if (nextStep)
{
COMMON_LOGGER("Erase Trash\n");
s_RestoreState = ERASE;
}
}
break;
case IMPORT_RTC:
{
result = nn::ResultSuccess();
if (HasValidRtcData())
{
result = ExecSyncMcuRtc(manager);
if (result <= nn::fs::ResultVerificationFailed())
{
s_RestoreState = FAIL;
}
else
{
if (s_SkipNupMode)
{
CheckAccountTransfered(manager, operationMessage, nextStep);
}
else
{
CheckNupExecuted(manager, operationMessage, nextStep);
}
}
}
else
{
if (s_CheckSdOnlyMode)
{
s_RestoreState = CHECK_IVS;
}
else
{
CheckNupExecuted(manager, operationMessage, nextStep);
}
}
}
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 = READ_FILELIST;
}
}
break;
// アップデート中
case UPDATE_IN_PROGRESS:
{
UpdateOperation(manager, operationMessage, UPDATE_DONE);
}
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;
case DOWNLOAD_IVS:
{
ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_GET_IVS, "Get SDCI",
"Get SDCI Finished.\n", "Get SDCI Failed. Retrying...", DOWNLOAD_IVS_DONE);
}
break;
case DOWNLOAD_IVS_DONE:
{
operationMessage.push_back(::std::string("Get SDCI 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 CHECK_IVS:
{
operationMessage.push_back(::std::string("Insert User's SD Card"));
}
break;
case CHECK_SD_DIRECTORY:
{
if (nn::fs::IsSdmcInserted())
{
NN_LOG("Check User's SD Card\n");
// ユーザのSDカードにはAP設定ファイルは無いはず
if (ExistsAPSetting())
{
NN_LOG("AP Setting Exists. Retry\n");
s_RestoreState = CHECK_IVS;
}
else
{
NN_LOG("Read User's SD Card\n");
std::string sysSaveRoot;
common::Util::GetSaveDataDirectoryRoot(sysSaveRoot);
if (ExistsIvsDirectory(sysSaveRoot))
{
s_RestoreState = CHECK_SD_DIRECTORY_SUCCESS;
}
else
{
s_RestoreState = CHECK_SD_DIRECTORY_FAIL;
}
}
}
}
break;
case CHECK_SD_DIRECTORY_SUCCESS:
{
operationMessage.push_back(::std::string("Check User's SD Card Succeeded."));
operationMessage.push_back(::std::string("Pull Out SD Card"));
}
break;
case CHECK_SD_DIRECTORY_FAIL:
{
operationMessage.push_back(::std::string("Check User's SD Card Failed."));
operationMessage.push_back(::std::string("Pull Out SD Card"));
}
break;
case WAIT_START_TRANSFER_ACCOUNT:
{
if(s_SkipNupMode)
{
operationMessage.push_back(::std::string("After Operating BMS Account Transfer,"));
}
operationMessage.push_back(::std::string("Push A or START Button"));
operationMessage.push_back(::std::string("Transfer Account Mode"));
if (!s_PlayedStartCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedStartCursor = true;
}
if (nextStep)
{
COMMON_LOGGER("Transfer Account\n");
s_RestoreState = TRANSFER_ACCOUNT;
}
}
break;
case TRANSFER_ACCOUNT:
{
ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_GET_IVS, "Transfer Account",
"Transfer Account Finished.\n", "Transfer Account Failed. Retrying...", DOWNLOAD_IVS_DONE);
}
break;
case WAIT_START_DELETE_ACCOUNT:
{
operationMessage.push_back(::std::string("Push A or START Button"));
operationMessage.push_back(::std::string("Delete Account Mode"));
if (!s_PlayedStartCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedStartCursor = true;
}
if (nextStep)
{
COMMON_LOGGER("Delete Account\n");
s_RestoreState = DELETE_ACCOUNT;
}
}
break;
case DELETE_ACCOUNT:
{
if(s_NupOnlyMode)
{
ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_FORCE_UNREGISTER, "Deleting Account",
"Delete Account Finished.\n", "Delete Account Failed. Retrying...", DELETE_ACCOUNT_DONE);
}
else
{
ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_UNREGISTER, "Deleting Account",
"Delete Account Finished.\n", "Delete Account Failed. Retrying...", DELETE_ACCOUNT_DONE);
}
}
break;
case DELETE_ACCOUNT_DONE:
{
if(s_NupOnlyMode)
{
s_RestoreState = NUP_ONLY_WAIT_SD_EJECT;
// リストア状態チェックファイルをすべて削除
DeleteAllCheckFiles();
}
else
{
operationMessage.push_back(::std::string("Delete Account Done."));
operationMessage.push_back(::std::string("Operate BMS."));
operationMessage.push_back(::std::string(""));
operationMessage.push_back(::std::string("Press A or START Button to Continue"));
if (!s_PlayedRebootCursor)
{
PlaySound(SOUND_CURSOR);
s_PlayedRebootCursor = true;
}
if (nextStep)
{
s_RestoreState = STARTUP;
}
}
}
break;
case READ_FILELIST:
{
result = SetupFileList();
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(result);
if (result.IsSuccess())
{
if (s_IsSyncClock)
{
s_RestoreState = RESTORE_TWL_NAND;
}
else
{
s_RestoreState = RESTORE_TWL_SOUND;
}
}
else
{
s_RestoreState = FAIL;
}
}
break;
// TWLサウンド領域の書き込み中
case RESTORE_TWL_SOUND:
{
static bool init = true;
if (init)
{
// データを書き込む
ImportTwlSoundData();
init = false;
}
PutAliveMessage(operationMessage, "Importing TWL Sound Data");
// 処理が完了した
if (IsImportThreadFinished())
{
FinalizeImportThread();
if(IsImportSucceeded())
{
s_RestoreState = RESTORE_TWL_PHOTO;
}
else
{
s_RestoreState = FAIL;
}
}
}
break;
// TWL写真領域の書き込み
case RESTORE_TWL_PHOTO:
{
static bool init = true;
if (init)
{
// データを書き込む
ImportTwlPhotoData();
init = false;
}
PutAliveMessage(operationMessage, "Importing TWL Photo Data");
// 処理が完了した
if (IsImportThreadFinished())
{
FinalizeImportThread();
if(IsImportSucceeded())
{
s_RestoreState = RESTORE_IN_PROGRESS;
}
else
{
s_RestoreState = FAIL;
}
}
}
break;
// 書き込み中
case RESTORE_IN_PROGRESS:
{
// ACアダプタが必要か
if (NeedsAcAdater(manager))
{
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
}
// データを読み込む
if (ImportData().IsFailure())
{
s_RestoreState = FAIL;
}
else
{
PutAliveMessage(operationMessage, "Importing Nand Data");
// 処理が完了した
if (!NeedsAcAdater(manager) && IsImportThreadFinished())
{
if (IsImportSucceeded())
{
COMMON_LOGGER("Import NAND Data Finished.\n");
if (GetProgress() > 99)
{
s_RestoreState = POST_RESTORE;
}
else
{
s_RestoreState = FAIL;
}
}
else
{
s_RestoreState = FAIL;
}
}
}
}
break;
// リブート中
case REBOOTING:
{
static bool init = true;
if (init)
{
// ErrDispから引用
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..."));
// SDカードのIVSファイルを書き込む
if(ImportIvsData())
{
// 書き込み完了ファイルを作成
CreateWriteFinishedFile();
s_RestoreState = RESTORE_DONE;
}
else
{
s_RestoreState = FAIL;
}
}
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 = RESTORE_CAL;
}
break;
// 削除処理
case RESTORE_CAL:
{
// ptmのセーブデータ移行後に時計を無効化する
nn::ptm::CTR::InvalidateSystemTime();
// cfgの本体固有値をcal値で初期化する
result = InitializeHardwareDependentSetting();
if (result.IsFailure())
{
s_RestoreState = FAIL;
}
COMMON_LOGGER("Sync eTicket\n");
s_RestoreState = SYNC_TICKET;
}
break;
case SYNC_TICKET:
{
if(s_GetIvsOnlyMode)
{
ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_CONNECT, "Shop Connect",
"Shop Connect Finished.\n", "Shop Connect Failed. Retrying...", WAIT_SD_EJECT);
}
else
{
ShopOperationSingleTemplate(manager, operationMessage, SHOP_OPERATION_CONNECT, "Shop Connect",
"Shop Connect Finished.\n", "Shop Connect Failed. Retrying...", DOWNLOAD_TWL);
}
}
break;
case DOWNLOAD_TWL:
{
// ファイルリストがなければ次へ
if( !ExistsTwlTitleListFile())
{
s_IsSyncClock = true;
s_RestoreState = READ_FILELIST;
}
else
{
if (!s_ExecuteTitleDownload)
{
COMMON_LOGGER("Download Twl Title\n");
s_ExecuteTitleDownload = true;
StartTitleDownload();
}
// 動いていることを表示
{
PutAliveMessage(operationMessage, "Download Twl Title");
}
if (IsDownloadTitleFinished())
{
FinalizeTitleDownload();
if (DownloadTitleSucceeded())
{
s_IsSyncClock = true;
s_RestoreState = READ_FILELIST;
}
else
{
if (s_TitleDownloadRetryCount++ < RETRY_MAX)
{
// エラーのためやり直す
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult());
COMMON_LOGGER("Download Twl Title Failed. Retrying... %d\n", s_TitleDownloadRetryCount);
s_ExecuteTitleDownload = false;
}
else
{
s_RestoreState = FAIL;
}
}
}
}
}
break;
// TWL NAND領域の書き込み中
case RESTORE_TWL_NAND:
{
static bool init = true;
if (init)
{
// データを書き込む
ImportTwlSaveData();
init = false;
}
PutAliveMessage(operationMessage, "Importing TWL SaveData");
// 処理が完了した
if (IsImportThreadFinished())
{
FinalizeImportThread();
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;
}
// リストア状態チェックファイルをすべて削除
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:
{
static bool init = true;
if (init)
{
// 状態初期化
DeleteAllCheckFiles();
init = false;
}
operationMessage.push_back(::std::string("Failed."));
if (!s_PlayedFailSound)
{
PlaySound(SOUND_NG);
s_PlayedFailSound = true;
}
}
break;
case NUP_ONLY_WAIT_SD_EJECT:
{
operationMessage.push_back(::std::string("Update Done. Pull Out SD Card."));
// SDカード抜けのみで次の状態に遷移する
if (!s_PlayedSdPullOutCursor)
{
common::PlaySound(common::SOUND_CURSOR);
s_PlayedSdPullOutCursor = true;
}
}
break;
case DOWNLOAD_IVS_WAIT_NEXT:
{
operationMessage.push_back(::std::string("Press A or START Button to Continue."));
if(nextStep)
{
s_RestoreState = SYNC_TICKET;
DeleteAllCheckFiles();
}
}
break;
case NUP_ONLY_WAIT_NEXT:
{
operationMessage.push_back(::std::string("Press A or START Button to Shutdown."));
if (nextStep)
{
s_RestoreState = INITIALIZE_AND_SHUTDOWN;
}
}
break;
case INITIALIZE_AND_SHUTDOWN:
{
// 本体初期化を行う
if(!InitializeFileSystem())
{
s_RestoreState = FAIL;
}
// シャットダウンする
nn::ptm::CTR::ShutdownAsync(0, nn::fnd::TimeSpan::FromSeconds(0));
}
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 == CHECK_SD_DIRECTORY_SUCCESS)
{
s_RestoreState = ALL_DONE;
}
else if (s_RestoreState == NUP_ONLY_WAIT_SD_EJECT || s_RestoreState == NUP_ONLY_WAIT_NEXT)
{
s_RestoreState = NUP_ONLY_WAIT_NEXT;
}
// ユーザのSDが抜かれてからFAILにする
else if (s_RestoreState == CHECK_SD_DIRECTORY_FAIL)
{
s_RestoreState = FAIL;
}
// FAILのときは一旦電源を切らないと動かないようにしておく
// IVSチェック時はユーザのSDカードを挿入してもらうため
else if (s_RestoreState != FAIL && s_RestoreState != CHECK_IVS)
{
InitializeState();
ClearFileReadResult();
}
}
void OnSdInserted()
{
if(s_RestoreState == CHECK_IVS)
{
// SDカードが変わるのでファイルチェックは初期化する
common::InitializeFileCheck();
s_RestoreState = CHECK_SD_DIRECTORY;
}
}
void InitializeState()
{
s_RestoreState = STARTUP;
s_RestoreMode = RESTORE_MODE_RESTORE;
for(u32 i = 0; i < SHOP_OPERATION_NUM_MAX; i++)
{
s_ShopOperationExecuted[i] = false;
s_ShopOperationRetryCount[i] = 0;
}
common::InitializeFileCheck();
s_ExistAPSettingAnnotation = false;
s_ReadSettingDone = false;
s_ReadSettingIsSuccess = 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;
s_NupOnlyMode = false;
s_GetIvsOnlyMode = false;
s_SdWriteProetctAnnotation = false;
s_WifiStatusOffAnnotation = false;
s_CheckSdOnlyMode = false;
s_SkipNupMode = false;
}
u32 GetProgress()
{
if(s_RestoreState == RESTORE_TWL_SOUND ||
s_RestoreState == RESTORE_TWL_PHOTO ||
s_RestoreState == RESTORE_TWL_NAND ||
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 if(s_RestoreState == DOWNLOAD_TWL)
{
return GetTitleDownloadProgress();
}
else
{
return 0;
}
}
RestoreMode GetRestoreMode()
{
return s_RestoreMode;
}
} // namespace ConsoleRestore