diff --git a/trunk/ConsoleDataMigration/ConsoleRestore/ConsoleRestore.cpp b/trunk/ConsoleDataMigration/ConsoleRestore/ConsoleRestore.cpp index 1bae2a3..ef666a7 100644 --- a/trunk/ConsoleDataMigration/ConsoleRestore/ConsoleRestore.cpp +++ b/trunk/ConsoleDataMigration/ConsoleRestore/ConsoleRestore.cpp @@ -321,6 +321,7 @@ extern "C" void nnMain(void) bool flip = false; + InitializeState(); for(;;) { diff --git a/trunk/ConsoleDataMigration/ConsoleRestore/Controller.cpp b/trunk/ConsoleDataMigration/ConsoleRestore/Controller.cpp index 55596b5..f6bee6e 100644 --- a/trunk/ConsoleDataMigration/ConsoleRestore/Controller.cpp +++ b/trunk/ConsoleDataMigration/ConsoleRestore/Controller.cpp @@ -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& operationMessage, const char* str); bool CheckAndReadAPSetting(::std::vector& operationMessage); @@ -150,7 +147,6 @@ void CheckConsoleInitialized(::std::vector& message, bool& goNextSt void CheckExistsSerialNumber(::std::vector& message, bool& goNextStep); void CheckIvsinSd(::std::vector& message, bool& goNextStep); void CheckRegioinSd(::std::vector& message, bool& goNextStep); -void ConnectOnly(::std::vector& message, bool& goNextStep, RestoreState nextState); // SDカード挿入チェック void CheckSdInserted(::std::vector& message, bool& goNextStep) @@ -434,10 +430,15 @@ void CheckRegioinSd(::std::vector& message, bool& goNextStep) } } -void ConnectOnly(::std::vector& message, bool& goNextStep, RestoreState nextState) +void ShopOperationSingleTemplate( + std::vector& 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& 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& 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& 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& 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& 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& 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& 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& 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; diff --git a/trunk/ConsoleDataMigration/ConsoleRestore/Shop.cpp b/trunk/ConsoleDataMigration/ConsoleRestore/Shop.cpp index 8b63337..f5b6cc4 100644 --- a/trunk/ConsoleDataMigration/ConsoleRestore/Shop.cpp +++ b/trunk/ConsoleDataMigration/ConsoleRestore/Shop.cpp @@ -20,6 +20,8 @@ #include #include #include +#include +#include #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 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 ポインタをそれぞれ と 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(); diff --git a/trunk/ConsoleDataMigration/ConsoleRestore/Shop.h b/trunk/ConsoleDataMigration/ConsoleRestore/Shop.h index 9c20d71..6bc7f59 100644 --- a/trunk/ConsoleDataMigration/ConsoleRestore/Shop.h +++ b/trunk/ConsoleDataMigration/ConsoleRestore/Shop.h @@ -17,6 +17,7 @@ #define SHOP_H_ #include +#include #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(); diff --git a/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.cpp b/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.cpp index a58b874..5c3bf2d 100644 --- a/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.cpp +++ b/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.cpp @@ -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 #include +#include +#include + +#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 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; ientries[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 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 (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; } diff --git a/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.h b/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.h index 11bcac6..453c1dd 100644 --- a/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.h +++ b/trunk/ConsoleDataMigration/ConsoleRestore/TitleDownloader.h @@ -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; + };