mirror of
https://github.com/rvtr/ctr_Repair.git
synced 2025-10-31 13:51:08 -04:00
ショップ処理を関数にまとめる
TWLタイトルをダウンロードできるように git-svn-id: file:///Volumes/Transfer/gigaleak_20231201/2020-05-23%20-%20ctr.7z%20+%20svn_v1.068.zip/ctr/svn/ctr_Repair@213 385bec56-5757-e545-9c3a-d8741f4650f1
This commit is contained in:
parent
08b0b17ee1
commit
19aa839160
@ -321,6 +321,7 @@ extern "C" void nnMain(void)
|
||||
|
||||
|
||||
bool flip = false;
|
||||
InitializeState();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
|
||||
@ -72,18 +72,15 @@ bool s_ExecuteFgNup = false;
|
||||
u32 s_FgNupRetryCount = 0;
|
||||
// 時計同期モードかどうか
|
||||
bool s_IsSyncClock = false;
|
||||
// アカウント削除を開始したかどうか
|
||||
bool s_ExecuteDeleteAccount = false;
|
||||
// アカウント削除を何回リトライしたか
|
||||
u32 s_DeleteAccountRetryCount = 0;
|
||||
// IVS取得を開始したかどうか
|
||||
bool s_ExecuteGetIvs = false;
|
||||
// IVS取得を何回リトライしたか
|
||||
u32 s_GetIvsRetryCount = 0;
|
||||
// ConnectOnlyを開始したかどうか
|
||||
bool s_ExecuteConnectOnly = false;
|
||||
// ConnectOnlyを回リトライしたか
|
||||
u32 s_ConnectOnlyRetryCount = 0;
|
||||
// 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);
|
||||
@ -150,7 +147,6 @@ void CheckConsoleInitialized(::std::vector<std::string>& message, bool& goNextSt
|
||||
void CheckExistsSerialNumber(::std::vector<std::string>& message, bool& goNextStep);
|
||||
void CheckIvsinSd(::std::vector<std::string>& message, bool& goNextStep);
|
||||
void CheckRegioinSd(::std::vector<std::string>& message, bool& goNextStep);
|
||||
void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreState nextState);
|
||||
|
||||
// SDカード挿入チェック
|
||||
void CheckSdInserted(::std::vector<std::string>& message, bool& goNextStep)
|
||||
@ -434,10 +430,15 @@ void CheckRegioinSd(::std::vector<std::string>& message, bool& goNextStep)
|
||||
}
|
||||
}
|
||||
|
||||
void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreState nextState)
|
||||
void ShopOperationSingleTemplate(
|
||||
std::vector<std::string>& message,
|
||||
ShopOperation op,
|
||||
const char* aliveMessage,
|
||||
const char* logMesasge,
|
||||
const char* retryLogMessage,
|
||||
RestoreState nextState
|
||||
)
|
||||
{
|
||||
NN_UNUSED_VAR(goNextStep);
|
||||
|
||||
// ACアダプタが必要か?
|
||||
if (NeedsAcAdater())
|
||||
{
|
||||
@ -445,12 +446,12 @@ void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreS
|
||||
}
|
||||
|
||||
// アップデートを行う
|
||||
if (!s_ExecuteConnectOnly)
|
||||
if (!s_ShopOperationExecuted[op])
|
||||
{
|
||||
if (ImportCountryLanguageData().IsSuccess())
|
||||
{
|
||||
StartShopOperationSingle(SHOP_OPERATION_CONNECT_ONLY);
|
||||
s_ExecuteConnectOnly = true;
|
||||
StartShopOperationSingle(op);
|
||||
s_ShopOperationExecuted[op] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -460,12 +461,12 @@ void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreS
|
||||
|
||||
// 動いていることを表示
|
||||
{
|
||||
PutAliveMessage(message, "Shop Connect");
|
||||
PutAliveMessage(message, aliveMessage);
|
||||
}
|
||||
|
||||
if (IsShopOperationSingleFinished())
|
||||
{
|
||||
FinishShopOperationSingle();
|
||||
FinalizeShopOperationSingle();
|
||||
// エラーがあったら表示する
|
||||
if (GetShopOperationSingleResult().IsFailure())
|
||||
{
|
||||
@ -478,20 +479,22 @@ void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreS
|
||||
|
||||
if (GetShopOperationSingleResult().IsSuccess())
|
||||
{
|
||||
COMMON_LOGGER("Shop Connect Finished.\n");
|
||||
COMMON_LOGGER("%s", logMesasge);
|
||||
// アカウント削除完了ファイルを作成
|
||||
CreateDeleteAccountFinishedFile();
|
||||
|
||||
s_RestoreState = nextState;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_ConnectOnlyRetryCount++ < RETRY_MAX)
|
||||
if (s_ShopOperationRetryCount[op]++ < RETRY_MAX)
|
||||
{
|
||||
// エラーのためやり直す
|
||||
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult());
|
||||
COMMON_LOGGER("Shop Connect Failed. Retrying... %d\n", s_ConnectOnlyRetryCount);
|
||||
COMMON_LOGGER("%s %d\n", retryLogMessage, s_ShopOperationRetryCount[op]);
|
||||
|
||||
// Unregister用のスレッドを作るとこからやり直し
|
||||
s_ExecuteConnectOnly = false;
|
||||
// スレッドを作るとこからやり直し
|
||||
s_ShopOperationExecuted[op] = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -804,70 +807,8 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
|
||||
|
||||
case DOWNLOAD_IVS:
|
||||
{
|
||||
// ACアダプタが必要か?
|
||||
if (NeedsAcAdater())
|
||||
{
|
||||
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
|
||||
}
|
||||
|
||||
// アップデートを行う
|
||||
if (!s_ExecuteGetIvs)
|
||||
{
|
||||
if (ImportCountryLanguageData().IsSuccess())
|
||||
{
|
||||
StartShopOperationSingle(SHOP_OPERATION_GET_IVS);
|
||||
s_ExecuteGetIvs = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_RestoreState = FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// 動いていることを表示
|
||||
{
|
||||
PutAliveMessage(operationMessage, "Get Ivs");
|
||||
}
|
||||
|
||||
if (IsShopOperationSingleFinished())
|
||||
{
|
||||
FinishShopOperationSingle();
|
||||
// エラーがあったら表示する
|
||||
if (GetShopOperationSingleResult().IsFailure())
|
||||
{
|
||||
// APが見つからない
|
||||
if (GetUpdateResult() == nn::ac::ResultNotFoundAccessPoint())
|
||||
{
|
||||
COMMON_LOGGER("No Access Point Found!");
|
||||
}
|
||||
}
|
||||
|
||||
if (GetShopOperationSingleResult().IsSuccess())
|
||||
{
|
||||
COMMON_LOGGER("Get Ivs Finished.\n");
|
||||
// IVS取得完了ファイルを作成
|
||||
CreateDownloadIvsFinishedFile();
|
||||
|
||||
s_RestoreState = DOWNLOAD_IVS_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_GetIvsRetryCount++ < RETRY_MAX)
|
||||
{
|
||||
// エラーのためやり直す
|
||||
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult());
|
||||
COMMON_LOGGER("Get Ivs Failed. Retrying... %d\n", s_GetIvsRetryCount);
|
||||
|
||||
// Unregister用のスレッドを作るとこからやり直し
|
||||
s_ExecuteGetIvs = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_RestoreState = FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ShopOperationSingleTemplate(operationMessage, SHOP_OPERATION_GET_IVS, "Get Ivs",
|
||||
"Get Ivs Finished.\n", "Get Ivs Failed. Retrying...", DOWNLOAD_IVS_DONE);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -893,70 +834,8 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
|
||||
|
||||
case DELETE_ACCOUNT:
|
||||
{
|
||||
// ACアダプタが必要か?
|
||||
if (NeedsAcAdater())
|
||||
{
|
||||
operationMessage.push_back(::std::string("Connect AC Adapter!!"));
|
||||
}
|
||||
|
||||
// アップデートを行う
|
||||
if (!s_ExecuteDeleteAccount)
|
||||
{
|
||||
if (ImportCountryLanguageData().IsSuccess())
|
||||
{
|
||||
StartShopOperationSingle(SHOP_OPERATION_UNREGISTER);
|
||||
s_ExecuteDeleteAccount = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_RestoreState = FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
// 動いていることを表示
|
||||
{
|
||||
PutAliveMessage(operationMessage, "Deleting Account");
|
||||
}
|
||||
|
||||
if (IsShopOperationSingleFinished())
|
||||
{
|
||||
FinishShopOperationSingle();
|
||||
// エラーがあったら表示する
|
||||
if (GetShopOperationSingleResult().IsFailure())
|
||||
{
|
||||
// APが見つからない
|
||||
if (GetUpdateResult() == nn::ac::ResultNotFoundAccessPoint())
|
||||
{
|
||||
COMMON_LOGGER("No Access Point Found!");
|
||||
}
|
||||
}
|
||||
|
||||
if (GetShopOperationSingleResult().IsSuccess())
|
||||
{
|
||||
COMMON_LOGGER("Delete Account Finished.\n");
|
||||
// アカウント削除完了ファイルを作成
|
||||
CreateDeleteAccountFinishedFile();
|
||||
|
||||
s_RestoreState = DELETE_ACCOUNT_DONE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (s_DeleteAccountRetryCount++ < RETRY_MAX)
|
||||
{
|
||||
// エラーのためやり直す
|
||||
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult());
|
||||
COMMON_LOGGER("Delete Account Failed. Retrying... %d\n", s_DeleteAccountRetryCount);
|
||||
|
||||
// Unregister用のスレッドを作るとこからやり直し
|
||||
s_ExecuteDeleteAccount = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_RestoreState = FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ShopOperationSingleTemplate(operationMessage, SHOP_OPERATION_UNREGISTER, "Deleting Account",
|
||||
"Delete Account Finished.\n", "Delete Account Failed. Retrying...", DELETE_ACCOUNT_DONE);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -980,12 +859,6 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
|
||||
}
|
||||
break;
|
||||
|
||||
case SYNC_TICKET:
|
||||
{
|
||||
ConnectOnly(operationMessage, nextStep, DOWNLOAD_TWL);
|
||||
}
|
||||
break;
|
||||
|
||||
case READ_FILELIST:
|
||||
{
|
||||
result = SetupFileList();
|
||||
@ -1166,13 +1039,20 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
|
||||
}
|
||||
break;
|
||||
|
||||
case SYNC_TICKET:
|
||||
{
|
||||
ShopOperationSingleTemplate(operationMessage, SHOP_OPERATION_CONNECT_ONLY, "Shop Connect",
|
||||
"Shop Connect Finished.\n", "Shop Connect Failed. Retrying...", DOWNLOAD_TWL);
|
||||
}
|
||||
break;
|
||||
|
||||
case DOWNLOAD_TWL:
|
||||
{
|
||||
static bool init = true;
|
||||
if (init)
|
||||
if (!s_ExecuteTitleDownload)
|
||||
{
|
||||
COMMON_LOGGER("Download Twl Title\n");
|
||||
init = false;
|
||||
s_ExecuteTitleDownload = true;
|
||||
StartTitleDownload();
|
||||
}
|
||||
|
||||
// 動いていることを表示
|
||||
@ -1180,16 +1060,27 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
|
||||
PutAliveMessage(operationMessage, "Download Twl Title");
|
||||
}
|
||||
|
||||
if (TitleDownloader::Finished())
|
||||
if (DownloadTitleFinished())
|
||||
{
|
||||
if (TitleDownloader::Succeeded())
|
||||
if (DownloadTitleSucceeded())
|
||||
{
|
||||
s_IsSyncClock = true;
|
||||
s_RestoreState = READ_FILELIST;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_RestoreState = FAIL;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1371,6 +1262,12 @@ 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;
|
||||
|
||||
@ -20,6 +20,8 @@
|
||||
#include <nn/ac/private/ac.h>
|
||||
#include <nn/ac/CTR/private/ac_InternalApi.h>
|
||||
#include <nn/nim/CTR/private/nim_ShopPrivateApi.h>
|
||||
#include <nn/CTR/CTR_ProgramId.h>
|
||||
#include <nn/am.h>
|
||||
|
||||
#include "Shop.h"
|
||||
#include "CommonLogger.h"
|
||||
@ -27,23 +29,23 @@
|
||||
using namespace ES_NAMESPACE;
|
||||
using namespace EC_NAMESPACE;
|
||||
|
||||
#define NIM_UNREGISTER_RESULT_CHECK(result) \
|
||||
#define NIM_SHOP_RESULT_CHECK(result) \
|
||||
do { \
|
||||
if (result.IsFailure()) \
|
||||
{ \
|
||||
ECCustomerSupportCode csc; \
|
||||
NN_UTIL_PANIC_IF_FAILED( \
|
||||
nn::nim::Shop::GetCustomerSupportCode(&csc)); \
|
||||
nn::nim::Shop::GetCustomerSupportCode(&csc); \
|
||||
COMMON_LOGGER("CSCode: %d\n", csc); \
|
||||
nn::dbg::PrintResult(result); \
|
||||
s_ShopResult = result; \
|
||||
ShopOperationFinalize(); \
|
||||
return; \
|
||||
} \
|
||||
} while(0)
|
||||
namespace
|
||||
{
|
||||
|
||||
const char* const TIGER_PROGRAM_ID_STR = "0004001000020900";
|
||||
|
||||
nn::Result s_ShopResult = nn::ResultSuccess();
|
||||
|
||||
const size_t UNREGISTER_THREAD_STACK_SIZE = 0x1000;
|
||||
@ -53,6 +55,59 @@ nn::os::StackBuffer<UNREGISTER_THREAD_STACK_SIZE> s_UnregisterThreadStack;
|
||||
static const size_t EC_BUFFER_SIZE = 128 * 1024;
|
||||
static u8 s_EcBufffer[EC_BUFFER_SIZE];
|
||||
|
||||
struct ShopThreadParam
|
||||
{
|
||||
ConsoleRestore::ShopOperation op;
|
||||
nn::nim::TitleConfig config;
|
||||
};
|
||||
|
||||
// TitleProgress の ==, != を定義
|
||||
bool operator==(
|
||||
nn::nim::TitleProgress& lhs,
|
||||
nn::nim::TitleProgress& rhs)
|
||||
{
|
||||
return (lhs.state == rhs.state &&
|
||||
lhs.lastResult == rhs.lastResult &&
|
||||
lhs.downloadedSize == rhs.downloadedSize &&
|
||||
lhs.totalSize == rhs.totalSize);
|
||||
}
|
||||
|
||||
bool operator!=(
|
||||
nn::nim::TitleProgress& lhs,
|
||||
nn::nim::TitleProgress& rhs)
|
||||
{
|
||||
return (! (lhs == rhs));
|
||||
}
|
||||
|
||||
// TitleState の文字列を取得
|
||||
const char* GetTitleStateString(nn::nim::TitleState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case nn::nim::TITLE_STATE_NOT_INITIALIZED:
|
||||
return "NOT_INITIALIZED";
|
||||
case nn::nim::TITLE_STATE_INITIALIZED:
|
||||
return "INITIALIZED";
|
||||
case nn::nim::TITLE_STATE_DOWNLOAD_TMD:
|
||||
return "DOWNLOAD_TMD";
|
||||
case nn::nim::TITLE_STATE_PREPARE_SAVE_DATA:
|
||||
return "PREPARE_SAVE_DATA";
|
||||
case nn::nim::TITLE_STATE_DOWNLOAD_CONTENTS:
|
||||
return "DOWNLOAD_CONTENTS";
|
||||
case nn::nim::TITLE_STATE_WAIT_COMMIT:
|
||||
return "WAIT_COMMIT";
|
||||
case nn::nim::TITLE_STATE_COMMITTING:
|
||||
return "COMMITTING";
|
||||
case nn::nim::TITLE_STATE_FINISHED:
|
||||
return "FINISHED";
|
||||
case nn::nim::TITLE_STATE_VERSION_MISMATCH:
|
||||
return "VERSION_MISMATCH";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 空文字列と NULL ポインタをそれぞれ <empty> と NULL として返す
|
||||
const char* Cstr(const char* p)
|
||||
{
|
||||
@ -202,7 +257,7 @@ void ShopOperationConnect();
|
||||
void ShopOperationFinalize();
|
||||
|
||||
|
||||
void ShopOperationConnect()
|
||||
void ShopOperationConnect(ECAccountInfo* pAccountInfo)
|
||||
{
|
||||
nn::Result result = nn::ResultSuccess();
|
||||
|
||||
@ -210,14 +265,44 @@ void ShopOperationConnect()
|
||||
Connect
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::Shop::Connect\n");
|
||||
ECAccountInfo* pAccountInfo;
|
||||
result = nn::nim::Shop::Connect(&pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE);
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
|
||||
PrintECAccountInfo(*pAccountInfo);
|
||||
NN_LOG("\n");
|
||||
}
|
||||
|
||||
void ShopOperationConnect()
|
||||
{
|
||||
nn::Result result = nn::ResultSuccess();
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
Initialize
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::InitializeForShop\n");
|
||||
result = nn::nim::InitializeForShop();
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
SetParameter
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::Shop::SetApplication Id\n");
|
||||
|
||||
nn::nim::Shop::SetParameter(EC_APP_ID, TIGER_PROGRAM_ID_STR);
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
|
||||
NN_LOG("nim::Shop::SetTIN\n");
|
||||
result = nn::nim::Shop::SetTin(NIM_TIN);
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
Connect
|
||||
-------------------------------------------------------------------- */
|
||||
ECAccountInfo* pAccountInfo;
|
||||
ShopOperationConnect(pAccountInfo);
|
||||
}
|
||||
|
||||
void ShopOperationFinalize()
|
||||
{
|
||||
nn::Result result = nn::ResultSuccess();
|
||||
@ -227,16 +312,22 @@ void ShopOperationFinalize()
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::FinalizeForShop\n");
|
||||
result = nn::nim::FinalizeForShop();
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
|
||||
NN_LOG("util::ac::Initialize\n");
|
||||
FinalizeInternal();
|
||||
NN_LOG("util::ac::Finalize\n");
|
||||
result = FinalizeInternal();
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
}
|
||||
|
||||
// メイン関数
|
||||
void ShopOperationSingleThreadFunc(ShopOperation op)
|
||||
namespace
|
||||
{
|
||||
if(op == SHOP_OPERATION_CLOSE_WITHOUT_CONNECT)
|
||||
|
||||
// メイン関数
|
||||
void ShopOperationSingleThreadFunc(ShopThreadParam param)
|
||||
{
|
||||
s_ShopResult = nn::ResultSuccess();
|
||||
|
||||
if(param.op == SHOP_OPERATION_CLOSE_WITHOUT_CONNECT)
|
||||
{
|
||||
ShopOperationFinalize();
|
||||
return;
|
||||
@ -247,21 +338,7 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
|
||||
|
||||
nn::Result result = nn::ResultSuccess();
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
Initialize
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::InitializeForShop\n");
|
||||
result = nn::nim::InitializeForShop();
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
SetParameter
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::Shop::SetTIN\n");
|
||||
result = nn::nim::Shop::SetTin(NIM_TIN);
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
|
||||
switch(op)
|
||||
switch(param.op)
|
||||
{
|
||||
case SHOP_OPERATION_CONNECT_WITHOUT_CLOSE:
|
||||
{
|
||||
@ -271,17 +348,7 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
|
||||
|
||||
case SHOP_OPERATION_CONNECT_ONLY:
|
||||
{
|
||||
// Connectするのみ
|
||||
/* -------------------------------------------------------------------
|
||||
Connect
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::Shop::Connect\n");
|
||||
ECAccountInfo* pAccountInfo;
|
||||
result = nn::nim::Shop::Connect(&pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE);
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
|
||||
PrintECAccountInfo(*pAccountInfo);
|
||||
NN_LOG("\n");
|
||||
ShopOperationConnect();
|
||||
}
|
||||
break;
|
||||
|
||||
@ -289,22 +356,14 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
|
||||
{
|
||||
// IVSを取得する
|
||||
result = nn::nim::Shop::ImportIvsFromInfrastructure();
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
}
|
||||
break;
|
||||
|
||||
case SHOP_OPERATION_UNREGISTER:
|
||||
{
|
||||
/* -------------------------------------------------------------------
|
||||
Connect
|
||||
-------------------------------------------------------------------- */
|
||||
NN_LOG("nim::Shop::Connect\n");
|
||||
ECAccountInfo* pAccountInfo;
|
||||
result = nn::nim::Shop::Connect(&pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE);
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
|
||||
PrintECAccountInfo(*pAccountInfo);
|
||||
NN_LOG("\n");
|
||||
ShopOperationConnect(pAccountInfo);
|
||||
if (pAccountInfo->accountStatus && pAccountInfo->accountStatus[0] == 'R')
|
||||
{
|
||||
/* ---------------------------------------------------------------
|
||||
@ -312,7 +371,7 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
|
||||
---------------------------------------------------------------- */
|
||||
NN_LOG("nim::Shop::Unregister\n");
|
||||
result = nn::nim::Shop::Unregister();
|
||||
NIM_UNREGISTER_RESULT_CHECK(result);
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -320,19 +379,93 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SHOP_OPERATION_DOWNLOAD_TITLE:
|
||||
{
|
||||
NN_LOG("Try Download %016llx\n", param.config.titleId);
|
||||
result = nn::nim::Shop::StartDownload(param.config);
|
||||
|
||||
if (result == nn::nim::ResultBusy() || result == nn::nim::ResultAlreadyDone())
|
||||
{
|
||||
COMMON_LOGGER("Download Content -> Nim is busy\n");
|
||||
}
|
||||
else if (result == nn::nim::ResultInvalidTitle())
|
||||
{
|
||||
COMMON_LOGGER("Download Content -> Invalid Title\n");
|
||||
}
|
||||
else if (result.IsFailure())
|
||||
{
|
||||
COMMON_LOGGER("Download Content -> Failure %x\n", result.GetPrintableBits());
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------
|
||||
GetProgress
|
||||
-------------------------------------------------------------------- */NN_LOG("nim::Shop::GetProgress()\n");
|
||||
nn::nim::TitleProgress before;
|
||||
nn::nim::TitleProgress latest;
|
||||
while (true)
|
||||
{
|
||||
result = nn::nim::Shop::GetProgress(&latest);
|
||||
// 既にインポート済み
|
||||
if (result == nn::am::ResultAlreadyExists())
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
NIM_SHOP_RESULT_CHECK(result);
|
||||
|
||||
// Print progress
|
||||
if (latest != before)
|
||||
{
|
||||
NN_LOG("%8lld / %8lld (%d:%s)\n",
|
||||
latest.downloadedSize,
|
||||
latest.totalSize,
|
||||
latest.state.Get(),
|
||||
GetTitleStateString(latest.state));
|
||||
|
||||
if (latest.state == nn::nim::TITLE_STATE_FINISHED)
|
||||
{
|
||||
NN_LOG("Finished Download\n");
|
||||
break;
|
||||
}
|
||||
|
||||
before = latest;
|
||||
}
|
||||
|
||||
// あまりにも頻繁に GetProgress を呼ぶと、ダウンロード処理の速度に
|
||||
// 影響が出てしまいます。少なくとも数フレーム以上の間隔をあけて
|
||||
// GetProgress することを推奨します。
|
||||
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(50));
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ShopOperationFinalize();
|
||||
}
|
||||
|
||||
void StartShopOperationSingle(ShopOperation op)
|
||||
{
|
||||
NN_LOG("Start ShopOperationSingle\n");
|
||||
s_ShopResult = nn::ResultSuccess();
|
||||
s_UnregisterThread.Start(ShopOperationSingleThreadFunc, op, s_UnregisterThreadStack);
|
||||
}
|
||||
|
||||
void FinishShopOperationSingle()
|
||||
void StartShopOperationSingle(ShopOperation op, nn::nim::TitleConfig config)
|
||||
{
|
||||
NN_LOG("Start ShopOperationSingle\n");
|
||||
|
||||
ShopThreadParam param;
|
||||
param.op = op;
|
||||
param.config = config;
|
||||
s_UnregisterThread.Start(ShopOperationSingleThreadFunc, param, s_UnregisterThreadStack);
|
||||
}
|
||||
|
||||
void StartShopOperationSingle(ShopOperation op)
|
||||
{
|
||||
ShopThreadParam param;
|
||||
param.op = op;
|
||||
|
||||
NN_LOG("Start ShopOperationSingle\n");
|
||||
s_UnregisterThread.Start(ShopOperationSingleThreadFunc, param, s_UnregisterThreadStack);
|
||||
}
|
||||
|
||||
void FinalizeShopOperationSingle()
|
||||
{
|
||||
NN_LOG("Finalize ShopOperationSingle\n");
|
||||
s_UnregisterThread.Join();
|
||||
|
||||
@ -17,6 +17,7 @@
|
||||
#define SHOP_H_
|
||||
|
||||
#include <nn.h>
|
||||
#include <nn/nim.h>
|
||||
|
||||
#define NIM_TIN "56789"
|
||||
|
||||
@ -29,11 +30,15 @@ typedef enum SHOP_OPERATION
|
||||
SHOP_OPERATION_GET_IVS, // Shop::ImportIvsFromInfrastructureを実行
|
||||
SHOP_OPERATION_UNREGISTER, // Shop::Unregisterを実行
|
||||
SHOP_OPERATION_CONNECT_WITHOUT_CLOSE, // Shop::ConnectしてCloseしない
|
||||
SHOP_OPERATION_CLOSE_WITHOUT_CONNECT // Shop::ConnectせずいきなりCloseする
|
||||
SHOP_OPERATION_CLOSE_WITHOUT_CONNECT, // Shop::ConnectせずいきなりCloseする
|
||||
SHOP_OPERATION_DOWNLOAD_TITLE, // Titleをダウンロードする
|
||||
SHOP_OPERATION_NUM_MAX
|
||||
|
||||
} ShopOperation;
|
||||
|
||||
void StartShopOperationSingle(ShopOperation op, nn::nim::TitleConfig config);
|
||||
void StartShopOperationSingle(ShopOperation op);
|
||||
void FinishShopOperationSingle();
|
||||
void FinalizeShopOperationSingle();
|
||||
bool IsShopOperationSingleFinished();
|
||||
nn::Result GetShopOperationSingleResult();
|
||||
|
||||
|
||||
@ -1,27 +1,137 @@
|
||||
/*---------------------------------------------------------------------------*
|
||||
Project: Horizon
|
||||
File: TitleDownloader.cpp
|
||||
Project: Horizon
|
||||
File: TitleDownloader.cpp
|
||||
|
||||
Copyright 2009 Nintendo. All rights reserved.
|
||||
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.
|
||||
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$
|
||||
$Rev$
|
||||
*---------------------------------------------------------------------------*/
|
||||
|
||||
#include "TitleDownloader.h"
|
||||
#include <nn.h>
|
||||
#include <nn/am.h>
|
||||
#include <nn/nim.h>
|
||||
#include <nn/CTR/CTR_ProgramId.h>
|
||||
|
||||
#include "CommonLogger.h"
|
||||
#include "HeapManager.h"
|
||||
#include "TitleDownloader.h"
|
||||
#include "Shop.h"
|
||||
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
bit8 s_buffer1[400 * 1024];
|
||||
|
||||
const size_t TITLE_DOWNLOADER_STACK_SIZE = 0x1000;
|
||||
nn::os::Thread s_TitleDownloaderThread;
|
||||
nn::os::StackBuffer<TITLE_DOWNLOADER_STACK_SIZE> s_TitleDownloaderThreadStack;
|
||||
|
||||
nn::fs::MediaType GetMediaType(const ES_NAMESPACE::ESTitleId titleId)
|
||||
{
|
||||
return (nn::CTR::IsTwlApp(titleId)) ?
|
||||
nn::fs::MEDIA_TYPE_NAND : nn::fs::MEDIA_TYPE_SDMC;
|
||||
}
|
||||
|
||||
const char *GetAttribute(EC_NAMESPACE::ECNameValuePair *attributes, u32 nAttributes, const char *attributeName)
|
||||
{
|
||||
for(int i=0; i<nAttributes; i++)
|
||||
{
|
||||
if(std::strcmp(attributes[i].name, attributeName)==0)
|
||||
{
|
||||
return attributes[i].value;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
nn::Result GetEntry(ES_NAMESPACE::ESTitleId titleId, EC_NAMESPACE::ECTitleCatalogEntry **entry)
|
||||
{
|
||||
nn::nim::AttributeName returnAttribute[] =
|
||||
{"Version", "TitleName", "TitleType", "TitleDescription", "Category", "Publisher", "MaxUserFileSize", "ReleaseDate"};
|
||||
nn::nim::AttributeFilter attributeFilter[] = {
|
||||
{"==", "string", "PricingSelection", "RELEASED"}
|
||||
};
|
||||
|
||||
NN_LOG("ID: %016llx\n", titleId);
|
||||
|
||||
EC_NAMESPACE::ECTitleCatalog *titleCatalog;
|
||||
nn::Result result = nn::nim::Shop::ListTitles(0, 1,
|
||||
returnAttribute, sizeof(returnAttribute)/sizeof(returnAttribute[0]),
|
||||
attributeFilter, sizeof(attributeFilter)/sizeof(attributeFilter[0]),
|
||||
&(titleId), 1,
|
||||
NULL, 0,
|
||||
&titleCatalog, s_buffer1, sizeof(s_buffer1));
|
||||
|
||||
*entry = &(titleCatalog->entries[0]);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
nn::Result GetTitleConfig(const ES_NAMESPACE::ESTitleId titleId, nn::nim::TitleConfig *titleConfig)
|
||||
{
|
||||
EC_NAMESPACE::ECTitleCatalogEntry *entry;
|
||||
NN_UTIL_RETURN_IF_FAILED(GetEntry(titleId, &entry));
|
||||
|
||||
titleConfig->titleId=titleId;
|
||||
titleConfig->version=std::strtoull(GetAttribute(entry->attributes, entry->nAttributes, "Version"), NULL, 10);
|
||||
titleConfig->ratingAge=0;
|
||||
titleConfig->media=GetMediaType(titleId);
|
||||
|
||||
NN_LOG("titleId : 0x%016llx\n", titleConfig->titleId);
|
||||
NN_LOG("version : %lld\n" , titleConfig->version);
|
||||
NN_LOG("ratingAge : %d\n" , titleConfig->ratingAge);
|
||||
NN_LOG("media : %d\n" , titleConfig->media);
|
||||
|
||||
|
||||
return nn::ResultSuccess();
|
||||
}
|
||||
|
||||
|
||||
} // namespace <unnamed>
|
||||
|
||||
namespace ConsoleRestore
|
||||
{
|
||||
|
||||
TitleDownloader::TitleDownloader() : m_Executing(false)
|
||||
nn::Result TitleDownloader::m_Result = nn::ResultSuccess();
|
||||
|
||||
void TitleDownloaderThreadFunc()
|
||||
{
|
||||
TitleDownloader TwlTitleDownloader;
|
||||
|
||||
TwlTitleDownloader.Start();
|
||||
}
|
||||
|
||||
void StartTitleDownload()
|
||||
{
|
||||
s_TitleDownloaderThread.Start(TitleDownloaderThreadFunc, s_TitleDownloaderThreadStack);
|
||||
}
|
||||
|
||||
bool DownloadTitleFinished()
|
||||
{
|
||||
return s_TitleDownloaderThread.IsValid() && !s_TitleDownloaderThread.IsAlive();
|
||||
}
|
||||
|
||||
bool DownloadTitleSucceeded()
|
||||
{
|
||||
return TitleDownloader::m_Result.IsSuccess() && GetShopOperationSingleResult().IsSuccess();
|
||||
}
|
||||
|
||||
|
||||
|
||||
TitleDownloader::TitleDownloader() : m_TwlTiteNum(0)
|
||||
{
|
||||
// TODO 自動生成されたコンストラクター・スタブ
|
||||
for(u32 i = 0; i < TWL_IMPORTABLE_TITLE_MAX; i++)
|
||||
{
|
||||
m_ProgramIdList[i] = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -31,28 +141,88 @@ TitleDownloader::~TitleDownloader()
|
||||
}
|
||||
|
||||
|
||||
void TitleDownloader::Start(nn::ProgramID* programIdList, size_t listNum)
|
||||
nn::Result WaitCancelled()
|
||||
{
|
||||
if(m_Executing)
|
||||
nn::nim::TitleProgress progress;
|
||||
while(true)
|
||||
{
|
||||
// キャンセルがResultとして返ってくる / ダウンロード終了まで待つ
|
||||
NN_UTIL_RETURN_IF_FAILED(nn::nim::Shop::GetProgress(&progress));
|
||||
if(progress.lastResult==nn::nim::ResultCancelRequested() || progress.state==nn::nim::TITLE_STATE_FINISHED)
|
||||
{
|
||||
break;
|
||||
}
|
||||
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
|
||||
}
|
||||
return nn::ResultSuccess();
|
||||
}
|
||||
|
||||
void WaitShopOperationAndFinalize()
|
||||
{
|
||||
while (!IsShopOperationSingleFinished())
|
||||
{
|
||||
nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(100));
|
||||
}
|
||||
|
||||
FinalizeShopOperationSingle();
|
||||
}
|
||||
|
||||
void TitleDownloader::Start()
|
||||
{
|
||||
nn::Result result;
|
||||
|
||||
result = ListUp();
|
||||
if(result.IsFailure())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_Executing = true;
|
||||
|
||||
|
||||
for(u8 i = 0; i < m_TwlTiteNum; i++)
|
||||
{
|
||||
StartShopOperationSingle(SHOP_OPERATION_CONNECT_WITHOUT_CLOSE);
|
||||
WaitShopOperationAndFinalize();
|
||||
|
||||
nn::nim::TitleConfig config;
|
||||
result = GetTitleConfig(m_ProgramIdList[i], &config);
|
||||
if (result.IsSuccess())
|
||||
{
|
||||
StartShopOperationSingle(SHOP_OPERATION_DOWNLOAD_TITLE, config);
|
||||
WaitShopOperationAndFinalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool TitleDownloader::Succeeded()
|
||||
nn::Result TitleDownloader::ListUp()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
const u32 AM_TICKET_MAX = 8192;
|
||||
|
||||
bool TitleDownloader::Finished()
|
||||
{
|
||||
return true;
|
||||
s32 personalizedTicketNum;
|
||||
|
||||
nn::am::TicketInfo *ticketInfoBuffer =
|
||||
reinterpret_cast<nn::am::TicketInfo*> (common::HeapManager::GetHeap()->Allocate(
|
||||
sizeof(nn::am::TicketInfo) * AM_TICKET_MAX));
|
||||
if(ticketInfoBuffer == NULL)
|
||||
{
|
||||
COMMON_LOGGER("Failed Allocate Heap!!\n");
|
||||
m_Result = nn::Result(nn::Result::LEVEL_FATAL, nn::Result::SUMMARY_OUT_OF_RESOURCE, nn::Result::MODULE_COMMON,
|
||||
nn::Result::DESCRIPTION_OUT_OF_MEMORY);
|
||||
return m_Result;
|
||||
}
|
||||
|
||||
m_Result=nn::am::GetPersonalizedTicketInfoList(&personalizedTicketNum, ticketInfoBuffer, AM_TICKET_MAX); // 全部
|
||||
COMMON_LOGGER_RESULT_IF_FAILED_WITH_LINE(m_Result);
|
||||
|
||||
for (u32 i = 0; i < personalizedTicketNum; i++)
|
||||
{
|
||||
if (nn::CTR::IsTwlApp(ticketInfoBuffer[i].titleId))
|
||||
{
|
||||
m_ProgramIdList[m_TwlTiteNum] = ticketInfoBuffer[i].titleId;
|
||||
m_TwlTiteNum++;
|
||||
NN_LOG("%016llx\n", m_ProgramIdList[m_TwlTiteNum - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
return m_Result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -21,19 +21,30 @@
|
||||
namespace ConsoleRestore
|
||||
{
|
||||
|
||||
void StartTitleDownload();
|
||||
bool DownloadTitleFinished();
|
||||
bool DownloadTitleSucceeded();
|
||||
|
||||
|
||||
class TitleDownloader
|
||||
{
|
||||
public:
|
||||
TitleDownloader();
|
||||
virtual ~TitleDownloader();
|
||||
|
||||
void Start(nn::ProgramID* programIdList, size_t listNum);
|
||||
void Start();
|
||||
|
||||
static bool Succeeded();
|
||||
static bool Finished();
|
||||
NN_PADDING4;
|
||||
static nn::Result m_Result;
|
||||
|
||||
private:
|
||||
bool m_Executing;
|
||||
nn::Result ListUp();
|
||||
|
||||
static const size_t TWL_IMPORTABLE_TITLE_MAX = 30;
|
||||
|
||||
nn::ProgramID m_ProgramIdList[TWL_IMPORTABLE_TITLE_MAX];
|
||||
u32 m_TwlTiteNum;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user