/*---------------------------------------------------------------------------* Project: Horizon File: FakeClient.cpp Copyright (C)2009-2012 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: 47228 $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include "demo.h" #include "dlpDemo.h" #include #include "../Child_0/Child.h" #include "nn/dlp/CTR/dlp_FakeClientWithName.h" #include #include #include namespace { static bool s_IsSessionDone = false; static nn::os::Event s_DlpClientEvent; static void* s_pWorkBuffer; static void* s_pAlignedWorkBuffer; size_t s_DlpClientWorkBufferSize; static int s_TitleNum = 0; static int s_Selected = 0; static nn::dlp::ServerInfo s_ServerInfo; static GLuint s_IconTextureId = 0; static u8 s_ServerMac[6]; static char s_Passphrase[nn::dlp::MAX_CHILD_UDS_PASSPHRASE_LENGTH]; static nn::cfg::UserName s_UserName; static nn::os::LightEvent s_AwakeEvent; // Wake events nn::applet::AppletQueryReply mySleepQueryCallback( uptr arg ) { NN_UNUSED_VAR(arg); DLP_DEBUG_POINT; return nn::applet::CTR::REPLY_LATER; } void myAwakeCallback( uptr arg ) { NN_UNUSED_VAR(arg); DLP_DEBUG_POINT; s_AwakeEvent.Signal(); } } /*!--------------------------------------------------------------------------* Display Cube *---------------------------------------------------------------------------*/ void DisplayCube(demo::RenderSystemDrawing* pRenderSystem, u16 x, u16 y) { struct Position { u16 x; u16 y; }; const Position cubePos[8] = { {0, 0}, {5, 0}, {10, 0}, {10, 5}, {10, 10}, {5, 10}, {0, 10}, {0, 5} }; static u16 startPos = 0; static u16 count = 0; if(count == 4) { startPos = (startPos + 1) % 8; count = 0; } for(int i = 0; i < 5; i++) { u16 curPos = (startPos + i) % 8; pRenderSystem->FillRectangle(x + cubePos[curPos].x, y + cubePos[curPos].y, 4, 4); } pRenderSystem->FillRectangle(x + 5, y + 5, 4, 4); count++; } /*!--------------------------------------------------------------------------* Display child device program list *---------------------------------------------------------------------------*/ void DisplayTitleList(const nn::dlp::TitleInfo titleList[], int titleNum, int selected, demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 2; char buffer[29]; // Specify white in font color pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * (x + 3), FONT_SIZE * y, "TITLE NAME"); pRenderSystem->DrawText(FONT_SIZE * (x + 33), FONT_SIZE * y, "SERVER NAME"); y += 2; // Display child device program list for(int i = 0; i < titleNum; i++) { if(i == selected) { // Specify green in font color pRenderSystem->SetColor(GREEN_COLOR); } else { // Specify white in font color pRenderSystem->SetColor(WHITE_COLOR); } pRenderSystem->DrawText(FONT_SIZE * x , FONT_SIZE * y, "%02d", i + 1); wcstombs(buffer, titleList[i].shortTitleName, 28); pRenderSystem->DrawText(FONT_SIZE * (x + 3), FONT_SIZE * y, "%s", buffer); buffer[28] = NULL; // Get server information nn::dlp::ServerInfo serverInfo; nn::dlp::FakeClient::GetServerInfo(&serverInfo, titleList[i].mac); wcstombs(buffer, serverInfo.nodeInfo[0].userName.userName, 11); pRenderSystem->DrawText(FONT_SIZE * (x + 33), FONT_SIZE * y, "%s", buffer); y++; } // Use --- to fill in blanks where there is no child device program for(int i = titleNum; i < SCAN_NUM; i++) { if(i == selected) { // Specify green in font color pRenderSystem->SetColor(GREEN_COLOR); } else { // Specify white in font color pRenderSystem->SetColor(WHITE_COLOR); } pRenderSystem->DrawText(FONT_SIZE * x , FONT_SIZE * y, "%02d", i + 1); pRenderSystem->DrawText(FONT_SIZE * (x + 3), FONT_SIZE * y, "----------------------------"); pRenderSystem->DrawText(FONT_SIZE * (x + 33), FONT_SIZE * y, "----------"); y++; } } /*!--------------------------------------------------------------------------* Display icon *---------------------------------------------------------------------------*/ void DeleteIconTexture(GLuint* pIconTextureId, demo::RenderSystemDrawing* pRenderSystem) { if ( *pIconTextureId != 0 ) { bool flag = pRenderSystem->DeleteTexture(*pIconTextureId); if ( flag ) { *pIconTextureId = 0; } } } void CreateIconTexture(GLuint* pIconTextureId, const bit16* iconImage, demo::RenderSystemDrawing* pRenderSystem) { if ( *pIconTextureId != 0 ) { DeleteIconTexture(pIconTextureId, pRenderSystem); } const u16 BLOCK_WIDTH = 8; const u16 BLOCK_HEIGHT = 8; const u16 BLOCK_LENGTH = BLOCK_WIDTH * BLOCK_HEIGHT; const u16 BLOCK_SIZE = BLOCK_LENGTH * sizeof(u16); const u16 ICON_BLOCK_WIDTH = 6; const u16 ICON_BLOCK_HEIGHT = 6; const u16 TEXTURE_BLOCK_WIDTH = 8; const u16 TEXTURE_BLOCK_HEIGHT = 8; static bit16 textureBuffer[TEXTURE_BLOCK_WIDTH * BLOCK_WIDTH * TEXTURE_BLOCK_HEIGHT * BLOCK_HEIGHT]; GLenum target = GL_TEXTURE_2D; GLenum internalFormat = GL_RGB_NATIVE_DMP; GLenum format = GL_RGB_NATIVE_DMP; GLenum type = GL_UNSIGNED_SHORT_5_6_5; GLuint textureId = 0; memset(textureBuffer, 0xff, sizeof(textureBuffer)); // Convert to texture format; native format has an reverse field y for (size_t i = 0; i < ICON_BLOCK_HEIGHT; i++) { nn::nstd::MemCpy( &textureBuffer[(i + TEXTURE_BLOCK_HEIGHT - ICON_BLOCK_HEIGHT)* BLOCK_LENGTH * TEXTURE_BLOCK_WIDTH], &iconImage[i * BLOCK_LENGTH * ICON_BLOCK_WIDTH], BLOCK_SIZE * ICON_BLOCK_WIDTH); } pRenderSystem->GenerateTexture(target, internalFormat, TEXTURE_BLOCK_WIDTH * BLOCK_WIDTH, TEXTURE_BLOCK_HEIGHT * BLOCK_HEIGHT, format, type, textureBuffer, textureId); if ( textureId != 0 ) { *pIconTextureId = textureId; } } void DisplayIcon(const nn::dlp::IconInfo icon, f32 x, f32 y, bool update, demo::RenderSystemDrawing* pRenderSystem) { const u16 TEXTURE_WIDTH = 64; const u16 TEXTURE_HEIGHT = 64; if(update) { CreateIconTexture(&s_IconTextureId, icon.image, pRenderSystem); } if(s_IconTextureId != 0) { pRenderSystem->FillTexturedRectangle(s_IconTextureId, x, y, nn::dlp::ICON_WIDTH_PIXEL, nn::dlp::ICON_HEIGHT_PIXEL, nn::dlp::ICON_WIDTH_PIXEL, nn::dlp::ICON_HEIGHT_PIXEL, TEXTURE_WIDTH, TEXTURE_HEIGHT); } } /*!--------------------------------------------------------------------------* Display child device program information *---------------------------------------------------------------------------*/ void DisplayTitleInfo(const nn::dlp::TitleInfo titleInfo, demo::RenderSystemDrawing* pRenderSystem) { u16 x = 8; u16 y = 2; char buffer[128]; // Update selection bool update = true; // Display icon DisplayIcon(titleInfo.icon, FONT_SIZE, 2 * FONT_SIZE, update, pRenderSystem); // Specify white in font color pRenderSystem->SetColor(WHITE_COLOR); // Display child device program information pRenderSystem->DrawText(0, 0, "TITLE INFO"); wcstombs(buffer, titleInfo.shortTitleName, 64); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "SHORT TITLE NAME : %s", buffer); wcstombs(buffer, titleInfo.longTitleName, 128); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "LONG TITLE NAME : %s", buffer); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "SIZE : %d BYTES", titleInfo.importSize); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ID/IDX/Ver : %05x/%d/%04x", titleInfo.uniqueId, titleInfo.childIndex, titleInfo.programVersion); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "REGION : %08x", titleInfo.region.Get()); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "RATING : %02x%02x%02x%02x%02x%02x%02x%02x", titleInfo.ratingInfo[0],titleInfo.ratingInfo[1],titleInfo.ratingInfo[2],titleInfo.ratingInfo[3], titleInfo.ratingInfo[4],titleInfo.ratingInfo[5],titleInfo.ratingInfo[6],titleInfo.ratingInfo[7]); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, " %02x%02x%02x%02x%02x%02x%02x%02x", titleInfo.ratingInfo[8],titleInfo.ratingInfo[9],titleInfo.ratingInfo[10],titleInfo.ratingInfo[11], titleInfo.ratingInfo[12],titleInfo.ratingInfo[13],titleInfo.ratingInfo[14],titleInfo.ratingInfo[15]); } /*!--------------------------------------------------------------------------* Display server information *---------------------------------------------------------------------------*/ void DisplayServerInfo(const nn::dlp::ServerInfo serverInfo, demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 9; // Display server information pRenderSystem->DrawText(0, FONT_SIZE * y++, "[ SERVER INFO ]"); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "MAC : %02X:%02X:%02X:%02X:%02X:%02X", serverInfo.mac[0], serverInfo.mac[1], serverInfo.mac[2], serverInfo.mac[3], serverInfo.mac[4], serverInfo.mac[5]); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "CH : %2d, LEVEL : %d, NODE : %2d/%2d", serverInfo.channel, serverInfo.linkLevel.Get(), serverInfo.nodeNum, serverInfo.maxNodeNum); } /*!--------------------------------------------------------------------------* Display node information *---------------------------------------------------------------------------*/ void DisplayNodeInfo(const nn::dlp::NodeInfo nodeInfo[], int nodeNum, demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 13; char buffer[16]; // Display node information pRenderSystem->DrawText(0, FONT_SIZE * y++, "[ NODE INFO ]"); for(int i = 0; i < nodeNum; i++) { wcstombs(buffer, nodeInfo[i].userName.userName, 11); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "%02d", i + 1); pRenderSystem->DrawText(FONT_SIZE * (x + 3), FONT_SIZE * y++, "%s", buffer); } } /*!--------------------------------------------------------------------------* Display download information *---------------------------------------------------------------------------*/ void DisplayDownloadInfo(nn::dlp::ClientStatus status, demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 2; // Specify white in font color pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y , "DOWNLOADING..."); y++; pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "NODE ID : %d\n", status.nodeId); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "STATE : %d\n", status.state.Get()); } /*!--------------------------------------------------------------------------* Display server dynamic information after connecting to server *---------------------------------------------------------------------------*/ void UpdateVariableServerInfo(nn::dlp::ServerInfo* pServerInfo) { u16 nodeIds[nn::dlp::MAX_NODE_NUM]; pServerInfo->linkLevel = nn::uds::LINK_LEVEL_0; pServerInfo->nodeNum = 0; nn::uds::LinkLevel linkLevel; nn::dlp::FakeClient::GetLinkLevel(&linkLevel); pServerInfo->linkLevel = static_cast< nn::util::SizedEnum1 >(linkLevel); nn::dlp::FakeClient::GetConnectingNodes(&pServerInfo->nodeNum, nodeIds, nn::dlp::MAX_NODE_NUM); for (size_t i = 0; i < pServerInfo->nodeNum; i++) { nn::dlp::FakeClient::GetNodeInfo(&pServerInfo->nodeInfo[i], nodeIds[i]); } } /*!--------------------------------------------------------------------------* Initialization state *---------------------------------------------------------------------------*/ void DisplayInitialize(demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 2; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "FAKE CLIENT SAMPLE"); y++; pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "NOW INITIALIZING..."); pRenderSystem->SwapBuffers(); pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SwapBuffers(); } /*!--------------------------------------------------------------------------* Start state *---------------------------------------------------------------------------*/ void UpdateStart(int* pTitleNum, int* pSelected, const nn::hid::PadStatus padStatus) { if(padStatus.trigger & nn::hid::BUTTON_A) { DLP_DEBUG_POINT; // Start scan nn::dlp::FakeClient::StartScan(); (*pTitleNum) = 0; (*pSelected) = 0; } else if(padStatus.trigger & nn::hid::BUTTON_Y) { // Initialize using the user name specified with the code std::memcpy( s_UserName.userName, L"FAKE", sizeof(L"FAKE")); nn::dlp::FakeClient::Finalize(); nn::dlp::FakeClientWithName::Initialize(SCAN_NUM, s_DlpClientEvent.GetHandle(), s_pAlignedWorkBuffer, s_DlpClientWorkBufferSize, &s_UserName ); // Start scan nn::dlp::FakeClient::StartScan(); (*pTitleNum) = 0; (*pSelected) = 0; } } void DisplayStart(demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 2; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "FAKE CLIENT SAMPLE"); y++; pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS A TO START"); pRenderSystem->SwapBuffers(); pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SwapBuffers(); } /*!--------------------------------------------------------------------------* Scan state *---------------------------------------------------------------------------*/ void UpdateScan(nn::dlp::TitleInfo* titleList, int* pTitleNum, int* pSelected, const nn::hid::PadStatus padStatus) { nn::Result result; if(padStatus.trigger & nn::hid::BUTTON_A) { DLP_DEBUG_POINT; if(*pSelected < *pTitleNum) { DLP_DEBUG_POINT; // Stop scanning nn::dlp::FakeClient::StopScan(); // Start session participation result = nn::dlp::FakeClient::StartFakeSession(titleList[*pSelected].mac, titleList[*pSelected].uniqueId, titleList[*pSelected].childIndex); memcpy(s_ServerMac, titleList[*pSelected].mac, sizeof(s_ServerMac)); if(result.IsFailure()) { DLP_DEBUG_PRINT("failed to StartFakeSession\n"); NN_DBG_PRINT_RESULT(result); } } } else if(padStatus.trigger & nn::hid::BUTTON_B) { DLP_DEBUG_POINT; // Stop scanning nn::dlp::FakeClient::StopScan(); return; } else if(padStatus.trigger & nn::hid::BUTTON_UP) { DLP_DEBUG_POINT; // Move the selection (*pSelected) = ((*pSelected) - 1 + SCAN_NUM) % SCAN_NUM; } else if(padStatus.trigger & nn::hid::BUTTON_DOWN) { DLP_DEBUG_POINT; // Move the selection (*pSelected) = ((*pSelected) + 1) % SCAN_NUM; } // Update child device program list if(*pTitleNum < SCAN_NUM) { if(nn::dlp::FakeClient::GetTitleInfo(&titleList[*pTitleNum], false).IsSuccess()) { NN_LOG("Get new title : %s:%d\n", __FILE__, __LINE__); (*pTitleNum) += 1; } } } void DisplayScan(const nn::dlp::TitleInfo* titleList, int titleNum, int selected, demo::RenderSystemDrawing* pRenderSystem) { pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); DLP_DEBUG_POINT; // Display child device program list DisplayTitleList(titleList, titleNum, selected, pRenderSystem); // Display Cube DisplayCube(pRenderSystem, 385, 225); pRenderSystem->SwapBuffers(); // Display child device program details if(0 != titleNum && selected < titleNum) { pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); DisplayTitleInfo(titleList[selected], pRenderSystem); // Get server information nn::dlp::FakeClient::GetServerInfo(&s_ServerInfo, titleList[selected].mac); // Display server information DisplayServerInfo(s_ServerInfo, pRenderSystem); // Display node information DisplayNodeInfo(s_ServerInfo.nodeInfo, s_ServerInfo.nodeNum, pRenderSystem); pRenderSystem->SwapBuffers(); } else { pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SwapBuffers(); } } /*!--------------------------------------------------------------------------* Waiting for connection state *---------------------------------------------------------------------------*/ void DisplayWaitingConnect(demo::RenderSystemDrawing* pRenderSystem) { pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); DLP_DEBUG_POINT; u16 x = 1; u16 y = 2; pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "WAITING CONNECT..."); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS B TO CANCEL"); pRenderSystem->SwapBuffers(); } void UpdateWaitingConnect(const nn::hid::PadStatus padStatus) { if(padStatus.trigger & nn::hid::BUTTON_B) { DLP_DEBUG_POINT; nn::Result result; // Cancel download nn::dlp::FakeClient::StopFakeSession(); } } /*!--------------------------------------------------------------------------* Waiting for download state *---------------------------------------------------------------------------*/ void UpdateWaitingDownload(const nn::hid::PadStatus padStatus) { if(padStatus.trigger & nn::hid::BUTTON_B) { DLP_DEBUG_POINT; nn::Result result; // Cancel download nn::dlp::FakeClient::StopFakeSession(); } } void DisplayWaitingDownload(const nn::dlp::TitleInfo& titleInfo, demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 2; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "WAITING DOWNLOAD..."); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS B TO CANCEL"); pRenderSystem->SwapBuffers(); // Display child device program details pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); DisplayTitleInfo(titleInfo, pRenderSystem); // Display server information UpdateVariableServerInfo(&s_ServerInfo); DisplayServerInfo(s_ServerInfo, pRenderSystem); // Display node information DisplayNodeInfo(s_ServerInfo.nodeInfo, s_ServerInfo.nodeNum, pRenderSystem); pRenderSystem->SwapBuffers(); } /*!--------------------------------------------------------------------------* Download state *---------------------------------------------------------------------------*/ void UpdateDownload(const nn::hid::PadStatus padStatus) { if(padStatus.trigger & nn::hid::BUTTON_B) { DLP_DEBUG_POINT; // Cancel download nn::dlp::FakeClient::StopFakeSession(); } } void DisplayDownload(nn::dlp::ClientStatus& status, const nn::dlp::TitleInfo& titleInfo, demo::RenderSystemDrawing* pRenderSystem) { pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); // Download information display DisplayDownloadInfo(status, pRenderSystem); // Display Cube DisplayCube(pRenderSystem, 385, 225); pRenderSystem->SwapBuffers(); pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); // Display child device program details DisplayTitleInfo(titleInfo, pRenderSystem); // Display server information UpdateVariableServerInfo(&s_ServerInfo); DisplayServerInfo(s_ServerInfo, pRenderSystem); // Display node information DisplayNodeInfo(s_ServerInfo.nodeInfo, s_ServerInfo.nodeNum, pRenderSystem); pRenderSystem->SwapBuffers(); } /*!--------------------------------------------------------------------------* Reboot state *---------------------------------------------------------------------------*/ void UpdateReboot() { DLP_DEBUG_POINT; // Stop download NN_UTIL_PANIC_IF_FAILED(nn::dlp::FakeClient::GetPassphrase(s_Passphrase)); DLP_DEBUG_PRINT("PASSPHRASE : %s\n", s_Passphrase); nn::dlp::FakeClient::Finalize(); s_IsSessionDone = true; } void DisplayReboot(demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 2; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "STARTING FAKE CHILD"); pRenderSystem->SwapBuffers(); pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SwapBuffers(); } /*!--------------------------------------------------------------------------* Error state *---------------------------------------------------------------------------*/ void UpdateError(const nn::hid::PadStatus padStatus) { nn::dlp::FakeClient::Finalize(); if(padStatus.trigger & nn::hid::BUTTON_A) { DLP_DEBUG_POINT; // Restart nn::dlp::FakeClient::Initialize(SCAN_NUM, s_DlpClientEvent.GetHandle(), s_pAlignedWorkBuffer, s_DlpClientWorkBufferSize); s_TitleNum = 0; s_Selected = 0; } } void DisplayError(demo::RenderSystemDrawing* pRenderSystem) { u16 x = 1; u16 y = 2; pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0); pRenderSystem->Clear(); pRenderSystem->SetColor(WHITE_COLOR); pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "ERROR"); y++; pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS A TO RESTART"); pRenderSystem->SwapBuffers(); pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1); pRenderSystem->Clear(); pRenderSystem->SwapBuffers(); } void DisplayBlackBack(demo::RenderSystemDrawing& renderSystem) { renderSystem.SetRenderTarget(NN_GX_DISPLAY0); renderSystem.Clear(); renderSystem.SwapBuffers(); renderSystem.SetRenderTarget(NN_GX_DISPLAY1); renderSystem.Clear(); renderSystem.SwapBuffers(); } /*!--------------------------------------------------------------------------* Update/display state functions *---------------------------------------------------------------------------*/ void Update(nn::dlp::ClientStatus clientStatus, nn::dlp::TitleInfo* titleList, int* pTitleNum, int* pSelected, const nn::hid::PadStatus padStatus) { switch(clientStatus.state) { case nn::dlp::CLIENT_STATE_DISCONNECTED_NETWORK: UpdateStart(pTitleNum, pSelected, padStatus); break; case nn::dlp::CLIENT_STATE_SCANNING: UpdateScan(titleList, pTitleNum, pSelected, padStatus); break; case nn::dlp::CLIENT_STATE_WAITING_CONNECT: UpdateWaitingConnect(padStatus); break; case nn::dlp::CLIENT_STATE_WAITING_INVITE: case nn::dlp::CLIENT_STATE_JOINED_SESSION: UpdateWaitingDownload(padStatus); break; case nn::dlp::CLIENT_STATE_DOWNLOADING: UpdateDownload(padStatus); break; case nn::dlp::CLIENT_STATE_REBOOTING: UpdateReboot(); break; case nn::dlp::CLIENT_STATE_ERROR: case nn::dlp::CLIENT_STATE_INVALID: UpdateError(padStatus); break; default: break; } } void Display(nn::dlp::ClientStatus clientStatus, const nn::dlp::TitleInfo* titleList, int titleNum, int selected, demo::RenderSystemDrawing* pRenderSystem) { switch(clientStatus.state) { case nn::dlp::CLIENT_STATE_DISCONNECTED_NETWORK: DisplayStart(pRenderSystem); break; case nn::dlp::CLIENT_STATE_SCANNING: DisplayScan(titleList, titleNum, selected, pRenderSystem); break; case nn::dlp::CLIENT_STATE_WAITING_CONNECT: DisplayWaitingConnect(pRenderSystem); break; case nn::dlp::CLIENT_STATE_WAITING_INVITE: case nn::dlp::CLIENT_STATE_JOINED_SESSION: DisplayWaitingDownload(titleList[selected], pRenderSystem); break; case nn::dlp::CLIENT_STATE_DOWNLOADING: case nn::dlp::CLIENT_STATE_DOWNLOAD_COMPLETE: DisplayDownload(clientStatus, titleList[selected], pRenderSystem); break; case nn::dlp::CLIENT_STATE_RECONNECTING_NETWORK: break; case nn::dlp::CLIENT_STATE_REBOOTING: DisplayReboot(pRenderSystem); break; case nn::dlp::CLIENT_STATE_ERROR: case nn::dlp::CLIENT_STATE_INVALID: DisplayError(pRenderSystem); break; default: break; } } /*!--------------------------------------------------------------------------* Main function *---------------------------------------------------------------------------*/ extern "C" void nnMain(void) { //Set sleep callback, sleep recovery callback nn::applet::SetSleepQueryCallback( mySleepQueryCallback, 0 ); nn::applet::SetAwakeCallback( myAwakeCallback, 0 ); nn::applet::Enable(); s_AwakeEvent.Initialize(false); // Initialize hid NN_UTIL_PANIC_IF_FAILED(nn::hid::Initialize()); // Prepare pad input nn::hid::PadReader padReader; nn::hid::PadStatus padStatus; // Allocate heap nn::fnd::ExpHeap appHeap; appHeap.Initialize( nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); // Prepare RenderSystem uptr heapForGx = reinterpret_cast(appHeap.Allocate(0x800000)); demo::RenderSystemDrawing renderSystem; renderSystem.Initialize(heapForGx, 0x800000); renderSystem.SetClearColor(NN_GX_DISPLAY_BOTH, 0.f, 0.f, 0.f, 0.f); renderSystem.SetFontSize(FONT_SIZE); renderSystem.SetLineWidth(LINE_WIDTH); // Initialize event used by DLP client s_DlpClientEvent.Initialize(false); // Get work buffer size necessary to initialize DLP client s_DlpClientWorkBufferSize = nn::dlp::FakeClient::GetBufferSize(SCAN_NUM); DLP_DEBUG_PRINT("dlpClientWorkBufferSize %d\n", s_DlpClientWorkBufferSize); // Get DLP client work buffer s_pWorkBuffer = new u8[s_DlpClientWorkBufferSize + 4096]; s_pAlignedWorkBuffer = reinterpret_cast(DLP_ROUNDUP(reinterpret_cast(s_pWorkBuffer), 4096UL)); DisplayInitialize(&renderSystem); // Initialize DLP client nn::dlp::FakeClient::Initialize(SCAN_NUM, s_DlpClientEvent.GetHandle(), s_pAlignedWorkBuffer, s_DlpClientWorkBufferSize); // Child device program list nn::dlp::TitleInfo* titleList = reinterpret_cast(appHeap.Allocate(sizeof(nn::dlp::TitleInfo) * SCAN_NUM)); NN_NULL_ASSERT(titleList); s_TitleNum = 0; s_Selected = 0; nn::dlp::ClientStatus clientStatus; // Main loop while(!s_IsSessionDone) { // Get pad input padReader.ReadLatest(&padStatus); // Get DLP client state nn::dlp::FakeClient::GetMyStatus(&clientStatus); // Render Display(clientStatus, titleList, s_TitleNum, s_Selected, &renderSystem); // Update Update(clientStatus, titleList, &s_TitleNum, &s_Selected, padStatus); //Sleep support if ( nn::applet::IsExpectedToReplySleepQuery() ) { DLP_DEBUG_POINT; nn::dlp::FakeClient::Finalize(); // Finalize before sleep. nn::applet::ReplySleepQuery( nn::applet::REPLY_ACCEPT ); DLP_DEBUG_POINT; s_AwakeEvent.Wait(); DLP_DEBUG_POINT; // Processing after restart nn::gx::StartLcdDisplay(); DLP_DEBUG_POINT; } //HOME Button support if (nn::applet::IsExpectedToProcessHomeButton()) { DLP_DEBUG_POINT; nn::dlp::FakeClient::Finalize(); nn::applet::ProcessHomeButton(); nn::applet::WaitForStarting(); DLP_DEBUG_POINT; // Recover the GPU register settings nngxUpdateState(NN_GX_STATE_ALL); nngxValidateState(NN_GX_STATE_ALL,GL_TRUE); if ( nn::applet::IsExpectedToCloseApplication() ) { DLP_DEBUG_POINT; break; } } //POWER Button support if ( nn::applet::IsExpectedToProcessPowerButton() ) { DLP_DEBUG_POINT; nn::dlp::FakeClient::Finalize(); nn::applet::ProcessPowerButton(); nn::applet::WaitForStarting(); DLP_DEBUG_POINT; // Recover the GPU register settings nngxUpdateState(NN_GX_STATE_ALL); nngxValidateState(NN_GX_STATE_ALL,GL_TRUE); if ( nn::applet::IsExpectedToCloseApplication() ) { DLP_DEBUG_POINT; break; } } // Support for termination request if (nn::applet::IsExpectedToCloseApplication()) { DLP_DEBUG_POINT; DisplayBlackBack(renderSystem); break; } } // Discard child device program list appHeap.Free(titleList); nn::dlp::FakeClient::Finalize(); delete[] s_pWorkBuffer; s_DlpClientEvent.Finalize(); renderSystem.Finalize(); appHeap.Free(reinterpret_cast(heapForGx)); appHeap.Finalize(); nn::hid::Finalize(); nn::applet::SetSleepQueryCallback(NULL, 0); nn::applet::SetAwakeCallback(NULL, 0); s_AwakeEvent.Finalize(); if (s_IsSessionDone) { DLP_DEBUG_POINT; // Because this is a provisional implementation, the SLEEP, HOME, and POWER Buttons do not work after this DoChild(s_ServerMac, s_Passphrase); } // Discard events used by DLP client s_DlpClientEvent.Finalize(); // Discard work buffer used by the DLP client delete s_pWorkBuffer; while(1) { nn::os::Thread::Sleep(nn::fnd::TimeSpan::FromSeconds(60)); } }