1 /*---------------------------------------------------------------------------*
2 Project: Horizon
3 File: Child.cpp
4
5 Copyright (C)2009-2012 Nintendo Co., Ltd. All rights reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Rev: 47228 $
14 *---------------------------------------------------------------------------*/
15
16 #include <string.h>
17 #include <nn.h>
18 #include <nn/fs.h>
19 #include <nn/dlp.h>
20 #include "Child.h"
21 #include <nn/types.h>
22 #include <nn/dbg.h>
23 #include <nn/nstd/nstd_String.h>
24
25 #include <nn/os/os_Memory.h>
26 #include <nn/os/os_MemoryTypes.h>
27 #include <nn/fnd/fnd_ExpHeap.h>
28
29 #include <nn/gx.h>
30
31 #include "child.h"
32 #include "dlpDemo.h"
33 #include "demo.h"
34
35 const int GL_MEMORY_SIZE = 0x800000;
36
37 enum ChildState
38 {
39 NOT_INITIALIZED, // Uninitialized state
40 SCANNING, // Scanning
41 CONNECTING, // Connecting to parent device
42 CLIENT, // Communicating as Client
43 ERROR // Entered sleep or Wi-Fi OFF mode
44 };
45
46 #ifndef NN_CTR_SAMPLEDEMOS_FAKE_CHILD
47 nn::os::LightEvent s_AwakeEvent; // Wake events
48
mySleepQueryCallback(uptr arg)49 nn::applet::AppletQueryReply mySleepQueryCallback(uptr arg)
50 {
51 NN_UNUSED_VAR(arg);
52 DLP_DEBUG_PRINT("SLEEP QUERY\n");
53 return nn::applet::CTR::REPLY_LATER;
54 }
55
myAwakeCallback(uptr arg)56 void myAwakeCallback(uptr arg)
57 {
58 NN_UNUSED_VAR(arg);
59 DLP_DEBUG_PRINT("AWAKE\n");
60 s_AwakeEvent.Signal();
61 }
62
63
nnMain(void)64 void nnMain(void)
65 {
66 //Sleep support
67 nn::applet::SetSleepQueryCallback( mySleepQueryCallback, 0 );
68 nn::applet::SetAwakeCallback( myAwakeCallback, 0 );
69 nn::applet::Enable();
70 s_AwakeEvent.Initialize(false);
71
72 DLP_DEBUG_PRINT("Child Start\n");
73 nn::dlp::RebootInfo rebootInfo;
74 nn::dlp::CTR::GetRebootInfo(&rebootInfo);
75 const u8* pBssid = rebootInfo.bssid;
76 char* pPassphrase = rebootInfo.passphrase;
77
78 NN_ASSERT(nn::dlp::IsChild());
79
80 #else
81 void DoChild(const u8 serverMac[], const char passphrase[])
82 {
83 DLP_DEBUG_PRINT("Fake Child Start\n");
84 const u8* pBssid = serverMac;
85 char pPassphrase[nn::dlp::MAX_CHILD_UDS_PASSPHRASE_LENGTH];
86
87 nn::nstd::MemCpy(pPassphrase, passphrase, sizeof(pPassphrase));
88 #endif
89
90 nn::Result result;
91 size_t connectCount;
92 nn::uds::EndpointDescriptor ed;
93 u32 receiveCount;
94 nn::uds::NetworkDescription netDesc;
95 ChildState state = NOT_INITIALIZED;
96 uptr heapForGx;
97 nn::os::Timer retryTimer;
98 nn::os::Event statusUpdateEvent;
99
100
101 static demo::RenderSystemDrawing s_RenderSystem;
102 static nn::fnd::ExpHeap s_AppHeap;
103 static bit8 s_UdsReceiveBuffer[4096*20] NN_ATTRIBUTE_ALIGN(4096);
104
105 // Initialize hid
106 result = nn::hid::Initialize();
107 NN_UTIL_PANIC_IF_FAILED(result);
108
109 // Create heap
110 s_AppHeap.Initialize(nn::os::GetDeviceMemoryAddress(),
111 nn::os::GetDeviceMemorySize() );
112 heapForGx = reinterpret_cast<uptr>(s_AppHeap.Allocate(GL_MEMORY_SIZE));
113
114 // Allocates 8 MB memory in FCRAM for graphics
115 s_RenderSystem.Initialize(heapForGx, GL_MEMORY_SIZE);
116
117 s_RenderSystem.SetClearColor(NN_GX_DISPLAY0, 0.0f, 0.0f, 0.0f, 0.0f);
118 s_RenderSystem.SetClearColor(NN_GX_DISPLAY1, 0.0f, 0.0f, 0.0f, 0.0f);
119
120 nn::hid::PadReader padReader;
121 nn::hid::PadStatus padStatus;
122
123 retryTimer.Initialize(false);
124
125 while(true)
126 {
127 s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY1);
128 s_RenderSystem.Clear();
129 s_RenderSystem.SetFontSize(FONT_SIZE);
130 s_RenderSystem.SetColor(1.0f, 1.0f, 1.0f);
131
132 padReader.ReadLatest(&padStatus);
133
134 switch( state )
135 {
136 case NOT_INITIALIZED:
137 {
138 s_RenderSystem.DrawText(0, 0, "Press A to start");
139 if( padStatus.trigger & nn::hid::BUTTON_A )
140 {
141 if( nn::uds::Initialize( &statusUpdateEvent, s_UdsReceiveBuffer, sizeof(s_UdsReceiveBuffer)).IsFailure())
142 {
143 state = ERROR;
144 }
145 else
146 {
147 DLP_DEBUG_POINT;
148 connectCount = MAX_RETRY_COUNT;
149 receiveCount = 0;
150 state = SCANNING;
151 }
152 }
153 }break;
154
155 case SCANNING:
156 {
157 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]);
158
159 static bit8 s_ScanBuffer[16384];
160 size_t foundNetworkNum;
161
162 if (nn::uds::Scan(s_ScanBuffer, sizeof(s_ScanBuffer), SUB_ID, nn::uds::CreateLocalCommunicationId(UNIQUE_ID_SAMPLEDEMOS_DLP)).IsSuccess())
163 {
164 nn::uds::ScanResultReader networkList(s_ScanBuffer);
165
166 foundNetworkNum = networkList.GetCount();
167 if( foundNetworkNum > SCAN_NUM )
168 {
169 foundNetworkNum = SCAN_NUM;
170 }
171
172 for( int i= 0;i < foundNetworkNum; i++ )
173 {
174 nn::uds::NetworkDescriptionReader netDescReader = networkList.GetNextDescription();
175 if (netDescReader.GetNetworkDescription(&netDesc).IsSuccess())
176 {
177 if (!::std::memcmp(netDesc.GetBssid(), pBssid, 6))
178 {
179 DLP_DEBUG_POINT;
180 state = CONNECTING;
181 retryTimer.StartOneShot(nn::fnd::TimeSpan::FromSeconds(0));
182 break;
183 }
184 }
185 }
186 }
187 else
188 {
189 state = ERROR;
190 }
191 } break;
192
193 case CONNECTING:
194 {
195 s_RenderSystem.DrawText(0, 0, "Connecting Parent : %02x%02x%02x%02x%02x%02x",
196 pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5]);
197 if (retryTimer.WaitOne(nn::fnd::TimeSpan::FromSeconds(0)))
198 {
199 DLP_DEBUG_POINT;
200 -- connectCount;
201 pPassphrase[nn::dlp::MAX_CHILD_UDS_PASSPHRASE_LENGTH - 1] = '\0';
202 DLP_DEBUG_PRINT("Passphrase : %s \n", pPassphrase);
203 result = nn::uds::ConnectNetwork(netDesc, nn::uds::CONNECT_AS_CLIENT, pPassphrase, strlen(pPassphrase));
204 if ( result.IsFailure() )
205 {
206 if( result == nn::uds::CTR::ResultNotFoundNetwork() // Communication environment is bad -> Retry
207 || 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
208 || result == nn::uds::CTR::ResultConnectionTimeout() // Communication environment is bad -> Retry
209 )
210 {
211 DLP_DEBUG_PRINT("ConnectNetwork Retry (result = 0x%08x)\n", result.GetValue());
212 }
213 else
214 {
215 DLP_DEBUG_PRINT("ConnectNetwork Error (result = 0x%08x)\n", result.GetValue());
216 state = ERROR;
217 }
218 }
219 else
220 {
221 DLP_DEBUG_POINT;
222 state = CLIENT;
223 NN_UTIL_PANIC_IF_FAILED(nn::uds::CreateEndpoint(&ed));
224 NN_UTIL_PANIC_IF_FAILED(nn::uds::Attach(&ed, nn::uds::BROADCAST_NODE_ID, 1));
225 }
226
227 if (!connectCount)
228 {
229 DLP_DEBUG_PRINT("ConnectNetwork Timeout\n");
230 state = ERROR;
231 }
232
233 if (CONNECTING == state)
234 {
235 DLP_DEBUG_POINT;
236 retryTimer.StartOneShot(nn::fnd::TimeSpan::FromSeconds(1));
237 }
238 }
239 } break;
240 case CLIENT:
241 {
242 s_RenderSystem.DrawText(0, 0, "Connected Parent : %02x%02x%02x%02x%02x%02x",
243 pBssid[0], pBssid[1], pBssid[2], pBssid[3], pBssid[4], pBssid[5]);
244 } break;
245 case ERROR: // If the system enters sleep or Wi-Fi OFF mode during this, UDS must be initialized again.
246 {
247 s_RenderSystem.DrawText(0, 0, "(Error) A: Finalize uds Library");
248 if(padStatus.trigger & nn::hid::BUTTON_A)
249 {
250 nn::uds::Finalize();
251 state = NOT_INITIALIZED;
252 }
253 }break;
254 }
255
256 s_RenderSystem.SwapBuffers();
257
258 //Display the communication status
259 s_RenderSystem.SetRenderTarget(NN_GX_DISPLAY0);
260 s_RenderSystem.Clear();
261
262 if (state == CLIENT)
263 {
264 u16 srcNodeId;
265 size_t recvedSize;
266
267 static u32 counter[nn::uds::UDS_PACKET_PAYLOAD_MAX_SIZE/sizeof(u32)+1];
268
269 result = nn::uds::ReceiveFrom(ed, counter, &recvedSize, &srcNodeId, sizeof(counter), nn::uds::NO_WAIT);
270 if( result.IsFailure() )
271 {
272 state = ERROR;
273 DLP_DEBUG_POINT;
274 NN_UTIL_PANIC_IF_FAILED(nn::uds::DestroyEndpoint(&ed));
275 }
276 else if (recvedSize)
277 {
278 receiveCount = counter[0];
279
280 }
281 s_RenderSystem.DrawText(0, 0, "Receiving packet : %08x", receiveCount);
282 }
283
284 s_RenderSystem.SwapBuffers();
285 s_RenderSystem.WaitVsync(NN_GX_DISPLAY_BOTH);
286
287 #ifndef NN_CTR_SAMPLEDEMOS_FAKE_CHILD
288 //Sleep support
289 if ( nn::applet::IsExpectedToReplySleepQuery() )
290 {
291 DLP_DEBUG_POINT;
292 nn::uds::Finalize();
293 nn::applet::ReplySleepQuery(nn::applet::REPLY_ACCEPT);
294 s_AwakeEvent.Wait(); DLP_DEBUG_POINT;
295
296 // Processing after restart
297 nn::gx::StartLcdDisplay();
298 }
299
300 //Home Button support
301 if ( nn::applet::IsExpectedToProcessHomeButton() )
302 {
303 DLP_DEBUG_POINT;
304 nn::uds::Finalize();
305 nn::applet::ProcessHomeButton();
306 AppletWakeupState r = nn::applet::WaitForStarting(); DLP_DEBUG_POINT;
307 NN_UNUSED_VAR(r);
308
309 // Recover the GPU register settings
310 nngxUpdateState(NN_GX_STATE_ALL);
311 nngxValidateState(NN_GX_STATE_ALL,GL_TRUE);
312
313 if ( nn::applet::IsExpectedToCloseApplication() )
314 {
315 DLP_DEBUG_POINT;
316 break;
317 }
318 }
319
320 //POWER Button support
321 if ( nn::applet::IsExpectedToProcessPowerButton() )
322 {
323 DLP_DEBUG_POINT;
324 nn::uds::Finalize();
325 nn::applet::ProcessPowerButton();
326 AppletWakeupState r = nn::applet::WaitForStarting(); DLP_DEBUG_POINT;
327 NN_UNUSED_VAR(r);
328
329 // Recover the GPU register settings
330 nngxUpdateState(NN_GX_STATE_ALL);
331 nngxValidateState(NN_GX_STATE_ALL,GL_TRUE);
332
333 if ( nn::applet::IsExpectedToCloseApplication() )
334 {
335 DLP_DEBUG_POINT;
336 break;
337 }
338 }
339
340 // Support for termination request
341 if (nn::applet::IsExpectedToCloseApplication())
342 {
343 DLP_DEBUG_POINT;;
344 nn::uds::Finalize();
345 break;
346 }
347 }
348 nn::hid::Finalize();
349 nn::applet::DisableSleep();
350 s_AwakeEvent.Finalize();
351 nn::applet::SetSleepQueryCallback(NULL, 0);
352 nn::applet::SetAwakeCallback(NULL, 0);
353 nn::applet::CloseApplication();
354 #else
355 }
356 #endif
357 }
358
359
360