/*---------------------------------------------------------------------------* Project: Horizon File: Child.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 "Child.h" #include #include #include #include #include #include #include #include "child.h" #include "dlpDemo.h" #include "demo.h" const int GL_MEMORY_SIZE = 0x800000; enum ChildState { NOT_INITIALIZED, // Uninitialized state SCANNING, // Scanning CONNECTING, // Connecting to parent device CLIENT, // Communicating as Client ERROR // Entered sleep or Wi-Fi OFF mode }; #ifndef NN_CTR_SAMPLEDEMOS_FAKE_CHILD nn::os::LightEvent s_AwakeEvent; // Wake events nn::applet::AppletQueryReply mySleepQueryCallback(uptr arg) { NN_UNUSED_VAR(arg); DLP_DEBUG_PRINT("SLEEP QUERY\n"); return nn::applet::CTR::REPLY_LATER; } void myAwakeCallback(uptr arg) { NN_UNUSED_VAR(arg); DLP_DEBUG_PRINT("AWAKE\n"); s_AwakeEvent.Signal(); } void nnMain(void) { //Sleep support nn::applet::SetSleepQueryCallback( mySleepQueryCallback, 0 ); nn::applet::SetAwakeCallback( myAwakeCallback, 0 ); nn::applet::Enable(); s_AwakeEvent.Initialize(false); DLP_DEBUG_PRINT("Child Start\n"); nn::dlp::RebootInfo rebootInfo; nn::dlp::CTR::GetRebootInfo(&rebootInfo); const u8* pBssid = rebootInfo.bssid; char* pPassphrase = rebootInfo.passphrase; NN_ASSERT(nn::dlp::IsChild()); #else void DoChild(const u8 serverMac[], const char passphrase[]) { DLP_DEBUG_PRINT("Fake Child Start\n"); const u8* pBssid = serverMac; char pPassphrase[nn::dlp::MAX_CHILD_UDS_PASSPHRASE_LENGTH]; nn::nstd::MemCpy(pPassphrase, passphrase, sizeof(pPassphrase)); #endif nn::Result result; size_t connectCount; nn::uds::EndpointDescriptor ed; u32 receiveCount; nn::uds::NetworkDescription netDesc; ChildState state = NOT_INITIALIZED; uptr heapForGx; nn::os::Timer retryTimer; nn::os::Event statusUpdateEvent; static demo::RenderSystemDrawing s_RenderSystem; static nn::fnd::ExpHeap s_AppHeap; static bit8 s_UdsReceiveBuffer[4096*20] NN_ATTRIBUTE_ALIGN(4096); // Initialize hid result = nn::hid::Initialize(); NN_UTIL_PANIC_IF_FAILED(result); // Create heap s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(), nn::os::GetDeviceMemorySize() ); heapForGx = reinterpret_cast(s_AppHeap.Allocate(GL_MEMORY_SIZE)); // Allocates 8 MB memory in FCRAM for graphics s_RenderSystem.Initialize(heapForGx, GL_MEMORY_SIZE); s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 0.0f, 0.0f, 0.0f, 0.0f); s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 0.0f, 0.0f, 0.0f, 0.0f); nn::hid::PadReader padReader; nn::hid::PadStatus padStatus; retryTimer.Initialize(false); while(true) { s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1); s_RenderSystem.Clear(); s_RenderSystem.SetFontSize(FONT_SIZE); s_RenderSystem.SetColor(1.0f, 1.0f, 1.0f); padReader.ReadLatest(&padStatus); switch( state ) { case NOT_INITIALIZED: { s_RenderSystem.DrawText(0, 0, "Press A to start"); if( padStatus.trigger & nn::hid::BUTTON_A ) { if( nn::uds::Initialize( &statusUpdateEvent, s_UdsReceiveBuffer, sizeof(s_UdsReceiveBuffer)).IsFailure()) { state = ERROR; } else { DLP_DEBUG_POINT; connectCount = MAX_RETRY_COUNT; receiveCount = 0; state = SCANNING; } } }break; case SCANNING: { s_RenderSystem.DrawText(0, 0, "Searching Parent : %02x%02x%02x%02x%02x%02x", pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5]); static bit8 s_ScanBuffer[16384]; size_t foundNetworkNum; if (nn::uds::Scan(s_ScanBuffer, sizeof(s_ScanBuffer), SUB_ID, nn::uds::CreateLocalCommunicationId(UNIQUE_ID_SAMPLEDEMOS_DLP)).IsSuccess()) { nn::uds::ScanResultReader networkList(s_ScanBuffer); foundNetworkNum = networkList.GetCount(); if( foundNetworkNum > SCAN_NUM ) { foundNetworkNum = SCAN_NUM; } for( int i= 0;i < foundNetworkNum; i++ ) { nn::uds::NetworkDescriptionReader netDescReader = networkList.GetNextDescription(); if (netDescReader.GetNetworkDescription(&netDesc).IsSuccess()) { if (!::std::memcmp(netDesc.GetBssid(), pBssid, 6)) { DLP_DEBUG_POINT; state = CONNECTING; retryTimer.StartOneShot(nn::fnd::TimeSpan::FromSeconds(0)); break; } } } } else { state = ERROR; } } break; case CONNECTING: { s_RenderSystem.DrawText(0, 0, "Connecting Parent : %02x%02x%02x%02x%02x%02x", pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5]); if (retryTimer.WaitOne(nn::fnd::TimeSpan::FromSeconds(0))) { DLP_DEBUG_POINT; -- connectCount; pPassphrase[nn::dlp::MAX_CHILD_UDS_PASSPHRASE_LENGTH - 1] = '\0'; DLP_DEBUG_PRINT("Passphrase : %s \n", pPassphrase); result = nn::uds::ConnectNetwork(netDesc, nn::uds::CONNECT_AS_CLIENT, pPassphrase, strlen(pPassphrase)); if ( result.IsFailure() ) { if( result == nn::uds::CTR::ResultNotFoundNetwork() // Communication environment is bad -> Retry || result == nn::uds::CTR::ResultDeniedFromMaster() // Connection refused by parent device (It may have been refused because the parent device is still performing DLP processing) -> Retry || result == nn::uds::CTR::ResultConnectionTimeout() // Communication environment is bad -> Retry ) { DLP_DEBUG_PRINT("ConnectNetwork Retry (result = 0x%08x)\n", result.GetValue()); } else { DLP_DEBUG_PRINT("ConnectNetwork Error (result = 0x%08x)\n", result.GetValue()); state = ERROR; } } else { DLP_DEBUG_POINT; state = CLIENT; NN_UTIL_PANIC_IF_FAILED(nn::uds::CreateEndpoint(&ed)); NN_UTIL_PANIC_IF_FAILED(nn::uds::Attach(&ed, nn::uds::BROADCAST_NODE_ID, 1)); } if (!connectCount) { DLP_DEBUG_PRINT("ConnectNetwork Timeout\n"); state = ERROR; } if (CONNECTING == state) { DLP_DEBUG_POINT; retryTimer.StartOneShot(nn::fnd::TimeSpan::FromSeconds(1)); } } } break; case CLIENT: { s_RenderSystem.DrawText(0, 0, "Connected Parent : %02x%02x%02x%02x%02x%02x", pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5]); } break; case ERROR: // If the system enters sleep or Wi-Fi OFF mode during this, UDS must be initialized again. { s_RenderSystem.DrawText(0, 0, "(Error) A: Finalize uds Library"); if(padStatus.trigger & nn::hid::BUTTON_A) { nn::uds::Finalize(); state = NOT_INITIALIZED; } }break; } s_RenderSystem.SwapBuffers(); //Display the communication status s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0); s_RenderSystem.Clear(); if (state == CLIENT) { u16 srcNodeId; size_t recvedSize; static u32 counter[nn::uds::UDS_PACKET_PAYLOAD_MAX_SIZE/sizeof(u32)+1]; result = nn::uds::ReceiveFrom(ed, counter, &recvedSize, &srcNodeId, sizeof(counter), nn::uds::NO_WAIT); if( result.IsFailure() ) { state = ERROR; DLP_DEBUG_POINT; NN_UTIL_PANIC_IF_FAILED(nn::uds::DestroyEndpoint(&ed)); } else if (recvedSize) { receiveCount = counter[0]; } s_RenderSystem.DrawText(0, 0, "Receiving packet : %08x", receiveCount); } s_RenderSystem.SwapBuffers(); s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH); #ifndef NN_CTR_SAMPLEDEMOS_FAKE_CHILD //Sleep support if ( nn::applet::IsExpectedToReplySleepQuery() ) { DLP_DEBUG_POINT; nn::uds::Finalize(); nn::applet::ReplySleepQuery(nn::applet::REPLY_ACCEPT); s_AwakeEvent.Wait(); DLP_DEBUG_POINT; // Processing after restart nn::gx::StartLcdDisplay(); } //Home Button support if ( nn::applet::IsExpectedToProcessHomeButton() ) { DLP_DEBUG_POINT; nn::uds::Finalize(); nn::applet::ProcessHomeButton(); AppletWakeupState r = nn::applet::WaitForStarting(); DLP_DEBUG_POINT; NN_UNUSED_VAR(r); // 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::uds::Finalize(); nn::applet::ProcessPowerButton(); AppletWakeupState r = nn::applet::WaitForStarting(); DLP_DEBUG_POINT; NN_UNUSED_VAR(r); // 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;; nn::uds::Finalize(); break; } } nn::hid::Finalize(); nn::applet::DisableSleep(); s_AwakeEvent.Finalize(); nn::applet::SetSleepQueryCallback(NULL, 0); nn::applet::SetAwakeCallback(NULL, 0); nn::applet::CloseApplication(); #else } #endif }