/*---------------------------------------------------------------------------* Project: Horizon File: main.cpp Copyright (C)2009 Nintendo Co., Ltd. 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "demo.h" #include "scrollBuffer.h" #include "VersionDetect.h" #include "HeapManager.h" namespace { const s32 s_GxHeapSize = 0x800000; uptr s_GxHeap; demo::RenderSystemDrawing s_RenderSystem; ScrollBuffer s_scrollBufferInstance; ScrollBuffer *s_scrollBuffer; char s_updaterBuffer[1 << 20] NN_ATTRIBUTE_ALIGN(4096); const u8 CUP_MAJOR_VER_3ND_NUP = 4; bool IsOver3rdNup(u8 cupMajor) { return CUP_MAJOR_VER_3ND_NUP <= cupMajor; } nn::ProgramId GetHomeMenuProgramId(nn::cfg::CTR::CfgRegionCode region) { nn::ProgramId pid; bit32 uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_HOMEMENU; bit8 ver = nn::CTR::PROGRAM_ID_VERSION_HOMEMENU; switch( region ) { case nn::cfg::CTR::CFG_REGION_AMERICA: uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_US; ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_US; break; case nn::cfg::CTR::CFG_REGION_EUROPE: case nn::cfg::CTR::CFG_REGION_AUSTRALIA: uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_EU; ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_EU; break; case nn::cfg::CTR::CFG_REGION_CHINA: uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_CN; ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_CN; break; case nn::cfg::CTR::CFG_REGION_KOREA: uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_KR; ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_KR; break; case nn::cfg::CTR::CFG_REGION_TAIWAN: uid = nn::CTR::PROGRAM_ID_UNIQUE_ID_SYSMENU_TW; ver = nn::CTR::PROGRAM_ID_VERSION_SYSMENU_TW; break; } pid = nn::CTR::MakeProgramId( nn::CTR::PROGRAM_ID_CATEGORY_APPLET, uid, ver ); // プログラムID return pid; } // デモの初期化 void Initialize() { // NuiShellの初期化 (CUPに必須) NN_UTIL_PANIC_IF_FAILED(nn::ns::CTR::InitializeForShell()); // ndmの初期化 nn::ndm::Initialize(); // 全デーモンの自律動作をacの自動接続も含めて止める nn::ndm::SuspendScheduler(); // amの初期化 nn::am::InitializeForSystemMenu(); // fsの初期化 (カード確認用) nn::fs::Initialize(); // appletの初期化 //nn::applet::InitializeForSystem( nn::applet::PHOME_MENU_APPLET_ID, nn::applet::TYPE_SYS ); //nn::applet::Initialize( nn::applet::TEST2_APPLET_ID); //nn::applet::SetAppletMode(); nn::applet::Enable(); nn::cfg::Initialize(); // デバイスメモリの設定 const s32 DEVICE_MEMORY_SIZE = 32 * 1024 * 1024; NN_UTIL_PANIC_IF_FAILED(nn::os::SetDeviceMemorySize(DEVICE_MEMORY_SIZE)); // ヒープの初期化 InitializeHeap(); // 描画インスタンスの初期化 s_GxHeap = reinterpret_cast(ForceAllocate(s_GxHeapSize)); s_RenderSystem.Initialize(s_GxHeap, s_GxHeapSize); // 描画インスタンスの初期化 s_scrollBufferInstance.Initialize(&s_RenderSystem); s_scrollBuffer = &s_scrollBufferInstance; s_RenderSystem.SetColor(1, 1, 1); // GPU利用宣言 nn::applet::AssignGpuRight(); } // 消費時間取得用関数群 s64 s_StartTick; void SetTick() { s_StartTick = nn::os::Tick::GetSystemCurrent(); } s64 GetConsumedMillisec() { s64 endTick = nn::os::Tick::GetSystemCurrent(); nn::os::Tick consumed(endTick - s_StartTick); return ((nn::fnd::TimeSpan) consumed).GetMilliSeconds(); } // 動いていることを知らせるための、くるくる画面表示取得用メソッド const char s_progress[] = "-\\|/"; s32 s_progressIndex = 0; char GetProgressChar() { s_progressIndex = (s_progressIndex + 1) % (sizeof(s_progress) - 1); return s_progress[s_progressIndex]; } nn::Result UpdateCore() { nn::Result result; nn::cup::ProgressInfo info; /********************** アップデート*******************/ SetTick(); s_scrollBuffer->AppendText("Start Card Update")->Render(); NN_UTIL_RETURN_IF_FAILED(nn::cup::CTR::DoUpdate()); // ステータスがStartedになるまで、プログレスは取得できない s_scrollBuffer->AppendText(""); do { s_scrollBuffer->ReplaceText(" %c Initializing", GetProgressChar())->Render(); result = nn::cup::CTR::GetProgressInfo(&info); NN_UTIL_RETURN_IF_FAILED(result); nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(40)); } while (info.state == nn::cup::CTR::UPDATE_STATE_INITIALIZING); // 抜けた際のstateがFAILEDかどうか確認 if (info.state == nn::cup::CTR::UPDATE_STATE_FAILED) { NN_UTIL_RETURN_IF_FAILED(info.lastResult); } s_scrollBuffer->ReplaceText(" - Initialized (%lldmsec)", GetConsumedMillisec()); /********************* アップデート中 ******************/ SetTick(); s_scrollBuffer->AppendText("")->Render(); do { result = nn::cup::CTR::GetProgressInfo(&info); NN_UTIL_RETURN_IF_FAILED(result); s_scrollBuffer->ReplaceText(" %c Title %d/%d, size %lld/%lld", GetProgressChar(), info.numImportedTitles, info.numTotalTitles, info.importedSize, info.totalSize)->Render(); nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(40)); } while (info.state == nn::cup::CTR::UPDATE_STATE_STARTED); // 抜けた際のstateがFAILEDかどうか確認 if (info.state == nn::cup::CTR::UPDATE_STATE_FAILED) { NN_UTIL_RETURN_IF_FAILED(info.lastResult); } s_scrollBuffer->AppendText(" - Imported (%lldmsec)", GetConsumedMillisec())->Render(); /***************** アップデート終了中 ******************/ SetTick(); s_scrollBuffer->AppendText("")->Render(); do { result = nn::cup::CTR::GetProgressInfo(&info); NN_UTIL_RETURN_IF_FAILED(result); s_scrollBuffer->ReplaceText(" %c Update Finalizing", GetProgressChar())->Render(); nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromMilliSeconds(40)); } while (info.state == nn::cup::CTR::UPDATE_STATE_FINALIZING); // 抜けた際のstateがFAILEDかどうか確認 if (info.state == nn::cup::CTR::UPDATE_STATE_FAILED) { NN_UTIL_RETURN_IF_FAILED(info.lastResult); } /******************* アップデート終了 *******************/ s_scrollBuffer->AppendText(" - Finalized (%lldmsec)", GetConsumedMillisec())->Render(); s_scrollBuffer->AppendText(""); return nn::ResultSuccess(); } nn::Result UpdateSequence(bool *isHandledError) { nn::Result result; nn::Result lastResult = nn::ResultSuccess(); /********************* CUPの初期化 *******************/ s_scrollBuffer->AppendText("Initializing Cup Library")->Render(); SetTick(); // 初期化開始前の時間をセット result = nn::cup::CTR::Initialize(s_updaterBuffer, sizeof(s_updaterBuffer)); if (result == nn::cup::CTR::ResultUpdatePartitionNotFound()) { s_scrollBuffer->AppendText(" - Update Partition Not Found (%lldmsec)", GetConsumedMillisec())->Render(); s_scrollBuffer->AppendText("")->Render(); *isHandledError = true; return result; } if (result == nn::cup::CTR::ResultUpdateNotRequired()) { s_scrollBuffer->AppendText(" - Already Updated (%lldmsec)", GetConsumedMillisec())->Render(); s_scrollBuffer->AppendText("")->Render(); *isHandledError = true; return result; } if (result == nn::cup::CTR::ResultInvalidUpdatePartitionFormat()) { s_scrollBuffer->AppendText(" - Invalid Update Partition (%lldmsec)", GetConsumedMillisec())->Render(); s_scrollBuffer->AppendText("")->Render(); *isHandledError = true; return result; }NN_UTIL_RETURN_IF_FAILED(result); s_scrollBuffer->AppendText(" - Need Update (%lldmsec)", GetConsumedMillisec())->Render(); s_scrollBuffer->AppendText("")->Render(); lastResult = UpdateCore(); // Initializeに成功した場合のみ、再びInitializeするためにFinalizeが必要 SetTick(); s_scrollBuffer->AppendText("Finalizing Cup Library")->Render(); NN_UTIL_RETURN_IF_FAILED(nn::cup::CTR::Finalize()); s_scrollBuffer->AppendText(" - Complete (%lldmsec)", GetConsumedMillisec())->Render(); s_scrollBuffer->AppendText("")->Render(); return lastResult; } } nn::Result ExecuteCup(ScrollBuffer* scrollBuf) { nn::Result result; bool isHandledError = false; result = UpdateSequence(&isHandledError); if (isHandledError == false && result.IsFailure()) { { // それ以外の場合は、Resultを表示 scrollBuf->AppendText(" - Unhandled Error: 0x%08x", result.GetPrintableBits()); scrollBuf->AppendText("")->Render(); } } return result; } void ShowError(const char* str) { s_scrollBuffer->AppendText(str); for (;;) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 1, 1, 0, 1); s_RenderSystem.SetColor(0, 0, 0); s_RenderSystem.Clear(); s_RenderSystem.SwapBuffers(); s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 1, 1, 0, 1); s_RenderSystem.Clear(); s_RenderSystem.SetColor(0, 0, 0); s_scrollBuffer->Render(); s_RenderSystem.SwapBuffers(); if (nn::applet::IsExpectedToCloseApplication()) { nn::applet::PrepareToCloseApplication(); nn::applet::CloseApplication(); } } } extern "C" void nnMain() { NN_LOG("Start Self Cup\n"); nn::Result result; Initialize(); VerDef versionData; nn::cfg::CfgRegionCode region = nn::cfg::GetRegion(); nn::ProgramId MMEN_PROGRAM_ID = GetHomeMenuProgramId(region); GetSystemVersion(&versionData, region); s_scrollBuffer->AppendText("Version: %d.%d.%d-%d%c", versionData.cup.majorVersion, versionData.cup.minorVersion, versionData.cup.microVersion, versionData.nup.majorVersion, nn::cfg::GetRegionCodeA3(region)[0]); if(IsOver3rdNup(versionData.cup.majorVersion)) { ShowError("Cannot Update"); } nn::am::ProgramInfo outInfos; result = nn::am::GetProgramInfos(&outInfos, nn::fs::MEDIA_TYPE_NAND, &MMEN_PROGRAM_ID, 1); if (result.IsSuccess()) { result = ExecuteCup(s_scrollBuffer); } else if (result == nn::am::ResultNotFound()) { s_scrollBuffer->AppendText("Cannot find Home Menu"); } s_scrollBuffer->AppendText("")->Render(); GetSystemVersion(&versionData, region); s_scrollBuffer->AppendText("Version: %d.%d.%d-%d%c", versionData.cup.majorVersion, versionData.cup.minorVersion, versionData.cup.microVersion, versionData.nup.majorVersion, nn::cfg::GetRegionCodeA3(region)[0]); s_scrollBuffer->AppendText("")->Render(); for (;;) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); if (result.IsSuccess() || result == nn::cup::CTR::ResultUpdateNotRequired()) { s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 0, 1, 0, 1); } else { s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 1, 0, 0, 1); } s_RenderSystem.Clear(); s_RenderSystem.SwapBuffers(); s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); if (result.IsSuccess() || result == nn::cup::CTR::ResultUpdateNotRequired()) { s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 0, 1, 0, 1); } else { s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 1, 0, 0, 1); } s_scrollBuffer->ReplaceText("%c Finished", GetProgressChar())->Render(); if (nn::applet::IsExpectedToCloseApplication()) { nn::applet::PrepareToCloseApplication(); nn::applet::CloseApplication(); } } }