ショップ処理を関数にまとめる

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:
N2614 2011-04-22 00:13:55 +00:00
parent 08b0b17ee1
commit 19aa839160
6 changed files with 468 additions and 251 deletions

View File

@ -321,6 +321,7 @@ extern "C" void nnMain(void)
bool flip = false; bool flip = false;
InitializeState();
for(;;) for(;;)
{ {

View File

@ -72,18 +72,15 @@ bool s_ExecuteFgNup = false;
u32 s_FgNupRetryCount = 0; u32 s_FgNupRetryCount = 0;
// 時計同期モードかどうか // 時計同期モードかどうか
bool s_IsSyncClock = false; bool s_IsSyncClock = false;
// アカウント削除を開始したかどうか // TWLタイトルのダウンロードを開始したかどうか
bool s_ExecuteDeleteAccount = false; bool s_ExecuteTitleDownload = false;
// アカウント削除を何回リトライしたか // TWLタイトルのダウンロードを何回リトライしたか
u32 s_DeleteAccountRetryCount = 0; u32 s_TitleDownloadRetryCount = 0;
// IVS取得を開始したかどうか
bool s_ExecuteGetIvs = false; // ショップ処理を開始したかどうか
// IVS取得を何回リトライしたか bool s_ShopOperationExecuted[SHOP_OPERATION_NUM_MAX];
u32 s_GetIvsRetryCount = 0; // ショップ処理を何回リトライしたか
// ConnectOnlyを開始したかどうか u32 s_ShopOperationRetryCount[SHOP_OPERATION_NUM_MAX];
bool s_ExecuteConnectOnly = false;
// ConnectOnlyを回リトライしたか
u32 s_ConnectOnlyRetryCount = 0;
void PutAliveMessage(::std::vector<std::string>& operationMessage, const char* str); void PutAliveMessage(::std::vector<std::string>& operationMessage, const char* str);
bool CheckAndReadAPSetting(::std::vector<std::string>& operationMessage); 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 CheckExistsSerialNumber(::std::vector<std::string>& message, bool& goNextStep);
void CheckIvsinSd(::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 CheckRegioinSd(::std::vector<std::string>& message, bool& goNextStep);
void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreState nextState);
// SDカード挿入チェック // SDカード挿入チェック
void CheckSdInserted(::std::vector<std::string>& message, bool& goNextStep) 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アダプタが必要か // ACアダプタが必要か
if (NeedsAcAdater()) 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()) if (ImportCountryLanguageData().IsSuccess())
{ {
StartShopOperationSingle(SHOP_OPERATION_CONNECT_ONLY); StartShopOperationSingle(op);
s_ExecuteConnectOnly = true; s_ShopOperationExecuted[op] = true;
} }
else else
{ {
@ -460,12 +461,12 @@ void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreS
// 動いていることを表示 // 動いていることを表示
{ {
PutAliveMessage(message, "Shop Connect"); PutAliveMessage(message, aliveMessage);
} }
if (IsShopOperationSingleFinished()) if (IsShopOperationSingleFinished())
{ {
FinishShopOperationSingle(); FinalizeShopOperationSingle();
// エラーがあったら表示する // エラーがあったら表示する
if (GetShopOperationSingleResult().IsFailure()) if (GetShopOperationSingleResult().IsFailure())
{ {
@ -478,20 +479,22 @@ void ConnectOnly(::std::vector<std::string>& message, bool& goNextStep, RestoreS
if (GetShopOperationSingleResult().IsSuccess()) if (GetShopOperationSingleResult().IsSuccess())
{ {
COMMON_LOGGER("Shop Connect Finished.\n"); COMMON_LOGGER("%s", logMesasge);
// アカウント削除完了ファイルを作成
CreateDeleteAccountFinishedFile();
s_RestoreState = nextState; s_RestoreState = nextState;
} }
else else
{ {
if (s_ConnectOnlyRetryCount++ < RETRY_MAX) if (s_ShopOperationRetryCount[op]++ < RETRY_MAX)
{ {
// エラーのためやり直す // エラーのためやり直す
COMMON_LOGGER_RESULT_IF_FAILED(GetShopOperationSingleResult()); 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 else
{ {
@ -804,70 +807,8 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
case DOWNLOAD_IVS: case DOWNLOAD_IVS:
{ {
// ACアダプタが必要か ShopOperationSingleTemplate(operationMessage, SHOP_OPERATION_GET_IVS, "Get Ivs",
if (NeedsAcAdater()) "Get Ivs Finished.\n", "Get Ivs Failed. Retrying...", DOWNLOAD_IVS_DONE);
{
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;
}
}
}
} }
break; break;
@ -893,70 +834,8 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
case DELETE_ACCOUNT: case DELETE_ACCOUNT:
{ {
// ACアダプタが必要か ShopOperationSingleTemplate(operationMessage, SHOP_OPERATION_UNREGISTER, "Deleting Account",
if (NeedsAcAdater()) "Delete Account Finished.\n", "Delete Account Failed. Retrying...", DELETE_ACCOUNT_DONE);
{
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;
}
}
}
} }
break; break;
@ -980,12 +859,6 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
} }
break; break;
case SYNC_TICKET:
{
ConnectOnly(operationMessage, nextStep, DOWNLOAD_TWL);
}
break;
case READ_FILELIST: case READ_FILELIST:
{ {
result = SetupFileList(); result = SetupFileList();
@ -1166,13 +1039,20 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
} }
break; 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: case DOWNLOAD_TWL:
{ {
static bool init = true; if (!s_ExecuteTitleDownload)
if (init)
{ {
COMMON_LOGGER("Download Twl Title\n"); COMMON_LOGGER("Download Twl Title\n");
init = false; s_ExecuteTitleDownload = true;
StartTitleDownload();
} }
// 動いていることを表示 // 動いていることを表示
@ -1180,19 +1060,30 @@ void ControlState(::std::vector<std::string>& operationMessage, bool& nextStep)
PutAliveMessage(operationMessage, "Download Twl Title"); PutAliveMessage(operationMessage, "Download Twl Title");
} }
if (TitleDownloader::Finished()) if (DownloadTitleFinished())
{ {
if (TitleDownloader::Succeeded()) if (DownloadTitleSucceeded())
{ {
s_IsSyncClock = true; s_IsSyncClock = true;
s_RestoreState = READ_FILELIST; s_RestoreState = READ_FILELIST;
} }
else 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; s_RestoreState = FAIL;
} }
} }
} }
}
break; break;
// TWL NAND領域の書き込み中 // TWL NAND領域の書き込み中
@ -1371,6 +1262,12 @@ void InitializeState()
s_RestoreState = STARTUP; s_RestoreState = STARTUP;
s_RestoreMode = RESTORE_MODE_RESTORE; 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(); common::InitializeFileCheck();
s_ExistAPSettingAnnotation = false; s_ExistAPSettingAnnotation = false;

View File

@ -20,6 +20,8 @@
#include <nn/ac/private/ac.h> #include <nn/ac/private/ac.h>
#include <nn/ac/CTR/private/ac_InternalApi.h> #include <nn/ac/CTR/private/ac_InternalApi.h>
#include <nn/nim/CTR/private/nim_ShopPrivateApi.h> #include <nn/nim/CTR/private/nim_ShopPrivateApi.h>
#include <nn/CTR/CTR_ProgramId.h>
#include <nn/am.h>
#include "Shop.h" #include "Shop.h"
#include "CommonLogger.h" #include "CommonLogger.h"
@ -27,23 +29,23 @@
using namespace ES_NAMESPACE; using namespace ES_NAMESPACE;
using namespace EC_NAMESPACE; using namespace EC_NAMESPACE;
#define NIM_UNREGISTER_RESULT_CHECK(result) \ #define NIM_SHOP_RESULT_CHECK(result) \
do { \ do { \
if (result.IsFailure()) \ if (result.IsFailure()) \
{ \ { \
ECCustomerSupportCode csc; \ ECCustomerSupportCode csc; \
NN_UTIL_PANIC_IF_FAILED( \ nn::nim::Shop::GetCustomerSupportCode(&csc); \
nn::nim::Shop::GetCustomerSupportCode(&csc)); \
COMMON_LOGGER("CSCode: %d\n", csc); \ COMMON_LOGGER("CSCode: %d\n", csc); \
nn::dbg::PrintResult(result); \ nn::dbg::PrintResult(result); \
s_ShopResult = result; \ s_ShopResult = result; \
ShopOperationFinalize(); \
return; \ return; \
} \ } \
} while(0) } while(0)
namespace namespace
{ {
const char* const TIGER_PROGRAM_ID_STR = "0004001000020900";
nn::Result s_ShopResult = nn::ResultSuccess(); nn::Result s_ShopResult = nn::ResultSuccess();
const size_t UNREGISTER_THREAD_STACK_SIZE = 0x1000; 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 const size_t EC_BUFFER_SIZE = 128 * 1024;
static u8 s_EcBufffer[EC_BUFFER_SIZE]; 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 として返す // 空文字列と NULL ポインタをそれぞれ <empty> と NULL として返す
const char* Cstr(const char* p) const char* Cstr(const char* p)
{ {
@ -202,7 +257,7 @@ void ShopOperationConnect();
void ShopOperationFinalize(); void ShopOperationFinalize();
void ShopOperationConnect() void ShopOperationConnect(ECAccountInfo* pAccountInfo)
{ {
nn::Result result = nn::ResultSuccess(); nn::Result result = nn::ResultSuccess();
@ -210,14 +265,44 @@ void ShopOperationConnect()
Connect Connect
-------------------------------------------------------------------- */ -------------------------------------------------------------------- */
NN_LOG("nim::Shop::Connect\n"); NN_LOG("nim::Shop::Connect\n");
ECAccountInfo* pAccountInfo;
result = nn::nim::Shop::Connect(&pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE); result = nn::nim::Shop::Connect(&pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE);
NIM_UNREGISTER_RESULT_CHECK(result); NIM_SHOP_RESULT_CHECK(result);
PrintECAccountInfo(*pAccountInfo); PrintECAccountInfo(*pAccountInfo);
NN_LOG("\n"); 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() void ShopOperationFinalize()
{ {
nn::Result result = nn::ResultSuccess(); nn::Result result = nn::ResultSuccess();
@ -227,16 +312,22 @@ void ShopOperationFinalize()
-------------------------------------------------------------------- */ -------------------------------------------------------------------- */
NN_LOG("nim::FinalizeForShop\n"); NN_LOG("nim::FinalizeForShop\n");
result = nn::nim::FinalizeForShop(); result = nn::nim::FinalizeForShop();
NIM_UNREGISTER_RESULT_CHECK(result); NIM_SHOP_RESULT_CHECK(result);
NN_LOG("util::ac::Initialize\n"); NN_LOG("util::ac::Finalize\n");
FinalizeInternal(); result = FinalizeInternal();
NIM_SHOP_RESULT_CHECK(result);
} }
// メイン関数 namespace
void ShopOperationSingleThreadFunc(ShopOperation op)
{ {
if(op == SHOP_OPERATION_CLOSE_WITHOUT_CONNECT)
// メイン関数
void ShopOperationSingleThreadFunc(ShopThreadParam param)
{
s_ShopResult = nn::ResultSuccess();
if(param.op == SHOP_OPERATION_CLOSE_WITHOUT_CONNECT)
{ {
ShopOperationFinalize(); ShopOperationFinalize();
return; return;
@ -247,21 +338,7 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
nn::Result result = nn::ResultSuccess(); nn::Result result = nn::ResultSuccess();
/* ------------------------------------------------------------------- switch(param.op)
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)
{ {
case SHOP_OPERATION_CONNECT_WITHOUT_CLOSE: case SHOP_OPERATION_CONNECT_WITHOUT_CLOSE:
{ {
@ -271,17 +348,7 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
case SHOP_OPERATION_CONNECT_ONLY: case SHOP_OPERATION_CONNECT_ONLY:
{ {
// Connectするのみ 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);
PrintECAccountInfo(*pAccountInfo);
NN_LOG("\n");
} }
break; break;
@ -289,22 +356,14 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
{ {
// IVSを取得する // IVSを取得する
result = nn::nim::Shop::ImportIvsFromInfrastructure(); result = nn::nim::Shop::ImportIvsFromInfrastructure();
NIM_UNREGISTER_RESULT_CHECK(result); NIM_SHOP_RESULT_CHECK(result);
} }
break; break;
case SHOP_OPERATION_UNREGISTER: case SHOP_OPERATION_UNREGISTER:
{ {
/* -------------------------------------------------------------------
Connect
-------------------------------------------------------------------- */
NN_LOG("nim::Shop::Connect\n");
ECAccountInfo* pAccountInfo; ECAccountInfo* pAccountInfo;
result = nn::nim::Shop::Connect(&pAccountInfo, s_EcBufffer, EC_BUFFER_SIZE); ShopOperationConnect(pAccountInfo);
NIM_UNREGISTER_RESULT_CHECK(result);
PrintECAccountInfo(*pAccountInfo);
NN_LOG("\n");
if (pAccountInfo->accountStatus && pAccountInfo->accountStatus[0] == 'R') if (pAccountInfo->accountStatus && pAccountInfo->accountStatus[0] == 'R')
{ {
/* --------------------------------------------------------------- /* ---------------------------------------------------------------
@ -312,7 +371,7 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
---------------------------------------------------------------- */ ---------------------------------------------------------------- */
NN_LOG("nim::Shop::Unregister\n"); NN_LOG("nim::Shop::Unregister\n");
result = nn::nim::Shop::Unregister(); result = nn::nim::Shop::Unregister();
NIM_UNREGISTER_RESULT_CHECK(result); NIM_SHOP_RESULT_CHECK(result);
} }
else else
{ {
@ -320,19 +379,93 @@ void ShopOperationSingleThreadFunc(ShopOperation op)
} }
} }
break; 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(); 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"); NN_LOG("Finalize ShopOperationSingle\n");
s_UnregisterThread.Join(); s_UnregisterThread.Join();

View File

@ -17,6 +17,7 @@
#define SHOP_H_ #define SHOP_H_
#include <nn.h> #include <nn.h>
#include <nn/nim.h>
#define NIM_TIN "56789" #define NIM_TIN "56789"
@ -29,11 +30,15 @@ typedef enum SHOP_OPERATION
SHOP_OPERATION_GET_IVS, // Shop::ImportIvsFromInfrastructureを実行 SHOP_OPERATION_GET_IVS, // Shop::ImportIvsFromInfrastructureを実行
SHOP_OPERATION_UNREGISTER, // Shop::Unregisterを実行 SHOP_OPERATION_UNREGISTER, // Shop::Unregisterを実行
SHOP_OPERATION_CONNECT_WITHOUT_CLOSE, // Shop::ConnectしてCloseしない 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; } ShopOperation;
void StartShopOperationSingle(ShopOperation op, nn::nim::TitleConfig config);
void StartShopOperationSingle(ShopOperation op); void StartShopOperationSingle(ShopOperation op);
void FinishShopOperationSingle(); void FinalizeShopOperationSingle();
bool IsShopOperationSingleFinished(); bool IsShopOperationSingleFinished();
nn::Result GetShopOperationSingleResult(); nn::Result GetShopOperationSingleResult();

View File

@ -13,15 +13,125 @@
$Rev$ $Rev$
*---------------------------------------------------------------------------*/ *---------------------------------------------------------------------------*/
#include "TitleDownloader.h" #include <nn.h>
#include <nn/am.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 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 自動生成されたコンストラクター・スタブ // 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; 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();
}
}
} }
nn::Result TitleDownloader::ListUp()
bool TitleDownloader::Succeeded()
{ {
return true; const u32 AM_TICKET_MAX = 8192;
}
bool TitleDownloader::Finished() s32 personalizedTicketNum;
{
return true; 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;
} }

View File

@ -21,19 +21,30 @@
namespace ConsoleRestore namespace ConsoleRestore
{ {
void StartTitleDownload();
bool DownloadTitleFinished();
bool DownloadTitleSucceeded();
class TitleDownloader class TitleDownloader
{ {
public: public:
TitleDownloader(); TitleDownloader();
virtual ~TitleDownloader(); virtual ~TitleDownloader();
void Start(nn::ProgramID* programIdList, size_t listNum); void Start();
static bool Succeeded(); NN_PADDING4;
static bool Finished(); static nn::Result m_Result;
private: 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;
}; };