1 /*---------------------------------------------------------------------------*
2   Project:  Horizon
3   File:     SimpleServer.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 <nn.h>
17 #include <nn/applet.h>
18 #include <nn/dlp.h>
19 #include <nn/hid.h>
20 #include "demo.h"
21 #include "SimpleServer.h"
22 #include "dlpDemo.h"
23 #include "Parent.h"
24 #include "nn/dlp/CTR/dlp_ServerWithName.h"
25 
26 #include <wchar.h>
27 #include <stdlib.h>
28 
29 static size_t s_DlpServerWorkBufferSize;
30 static void* s_pWorkBuffer;
31 static void* s_pAlignedWorkBuffer;
32 static bool s_IsDistributionDone = false;
33 static bool s_IsNoticeNeeded = false;
34 static nn::os::Event s_DlpServerEvent;
35 static u16 s_Selected = 0;
36 static nn::hid::PadStatus s_PadStatus;
37 static nn::os::LightEvent s_AwakeEvent; // Wake events
38 static u16 s_ClientNum;
39 static char s_Passphraase[nn::dlp::MAX_CHILD_UDS_PASSPHRASE_LENGTH];
40 static nn::cfg::UserName s_UserName;
41 
mySleepQueryCallback(uptr arg)42 nn::applet::AppletQueryReply mySleepQueryCallback(uptr arg)
43 {
44     NN_UNUSED_VAR(arg);
45     DLP_DEBUG_POINT;
46     return nn::applet::CTR::IsActive()? nn::applet::CTR::REPLY_LATER: nn::applet::CTR::REPLY_ACCEPT;
47 }
48 
myAwakeCallback(uptr arg)49 void myAwakeCallback(uptr arg)
50 {
51     NN_UNUSED_VAR(arg);
52     DLP_DEBUG_POINT;
53     s_AwakeEvent.Signal();
54 }
55 
56 // Display client status
DisplayClientState(u16 x,u16 y,nn::dlp::ClientState state,demo::RenderSystemDrawing * pRenderSystem)57 void DisplayClientState(u16 x, u16 y, nn::dlp::ClientState state,
58         demo::RenderSystemDrawing* pRenderSystem)
59 {
60     switch (state)
61     {
62     case nn::dlp::CLIENT_STATE_WAITING_INVITE:
63         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "WAIT INVITE");
64         break;
65     case nn::dlp::CLIENT_STATE_WAITING_ACCEPT:
66         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "WAIT ACCEPT");
67         break;
68     case nn::dlp::CLIENT_STATE_JOINED_SESSION:
69         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "JOINED");
70         break;
71     case nn::dlp::CLIENT_STATE_DOWNLOADING:
72         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "DOWNLOADING");
73         break;
74     case nn::dlp::CLIENT_STATE_DOWNLOAD_COMPLETE:
75         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "COMPLETE");
76         break;
77     default:
78         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "INVALID");
79     }
80 }
81 
82 // Display a list of clients
DisplayClientList(u16 selected,u16 x,u16 y,demo::RenderSystemDrawing * pRenderSystem)83 u16 DisplayClientList(u16 selected, u16 x, u16 y, demo::RenderSystemDrawing* pRenderSystem)
84 {
85     char buffer[14];
86 
87     // Specify white in font color
88     pRenderSystem->SetColor(WHITE_COLOR);
89     pRenderSystem->DrawText(FONT_SIZE * (x + 3), FONT_SIZE * y, "CLIENT NAME");
90     pRenderSystem->DrawText(FONT_SIZE * (x + 15), FONT_SIZE * y, "STATE");
91     pRenderSystem->DrawText(FONT_SIZE * (x + 28), FONT_SIZE * y, "PROGRESS");
92 
93     // Get the client list
94     u16 clientNum = 0;
95     u16 clientId[MAX_CLIENT];
96     nn::dlp::Server::GetConnectingClients(&clientNum, clientId, MAX_CLIENT);
97 
98     y += 2;
99 
100     for (int i = 0; i < clientNum; i++)
101     {
102         if (i == selected)
103         {
104             // Specify green in font color
105             pRenderSystem->SetColor(GREEN_COLOR);
106         }
107         else
108         {
109             // Specify white in font color
110             pRenderSystem->SetColor(WHITE_COLOR);
111         }
112 
113         nn::dlp::NodeInfo clientInfo;
114         nn::dlp::ClientState clientState;
115         size_t totalNum;
116         size_t downloadedNum;
117 
118         if (   nn::dlp::Server::GetClientInfo(&clientInfo, clientId[i]).IsFailure()
119             || nn::dlp::Server::GetClientState(&clientState, &totalNum, &downloadedNum, clientId[i]).IsFailure())
120         {
121             clientNum = 0;
122             break;
123         }
124 
125         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "%02d", i + 1);
126         wcstombs(buffer, clientInfo.userName.userName, 11);
127         pRenderSystem->DrawText(FONT_SIZE * (x +  3), FONT_SIZE * y, "%s", buffer);
128         DisplayClientState(x + 15, y, clientState, pRenderSystem);
129         pRenderSystem->DrawText(FONT_SIZE * (x + 28), FONT_SIZE * y, "%5d/%5d",
130                 downloadedNum, totalNum);
131         y++;
132     }
133 
134     // Use --- to fill in blanks where there is no client
135     for (int i = clientNum; i < MAX_CLIENT; i++)
136     {
137         if (i == selected)
138         {
139             // Specify green in font color
140             pRenderSystem->SetColor(GREEN_COLOR);
141         }
142         else
143         {
144             // Specify white in font color
145             pRenderSystem->SetColor(WHITE_COLOR);
146         }
147 
148         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y, "%02d", i + 1);
149         pRenderSystem->DrawText(FONT_SIZE * (x + 3), FONT_SIZE * y,  "----------");
150         pRenderSystem->DrawText(FONT_SIZE * (x + 15), FONT_SIZE * y, "------------");
151         pRenderSystem->DrawText(FONT_SIZE * (x + 28), FONT_SIZE * y, "-----------");
152         y++;
153     }
154 
155     return y;
156 }
157 
158 
159 // Display child device program information
DisplayTitleInfo(demo::RenderSystemDrawing * pRenderSystem)160 void DisplayTitleInfo(demo::RenderSystemDrawing* pRenderSystem)
161 {
162     u16 x = 1;
163     u16 y = 2;
164 
165     // Specify white in font color
166     pRenderSystem->SetColor(WHITE_COLOR);
167 
168     // Display child device program information
169     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "TITLE INFO");
170 
171 }
172 
173 /*!--------------------------------------------------------------------------*
174  Initialization state
175  *---------------------------------------------------------------------------*/
DisplayInitialize(demo::RenderSystemDrawing * pRenderSystem)176 void DisplayInitialize(demo::RenderSystemDrawing* pRenderSystem)
177 {
178     u16 x = 1;
179     u16 y = 2;
180 
181     pRenderSystem->SetColor(WHITE_COLOR);
182     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "SIMPLE SERVER");
183 
184     y++;
185     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++,
186             "NOW INITIALIZING...");
187 }
188 
189 /*!--------------------------------------------------------------------------*
190  Start state
191  *---------------------------------------------------------------------------*/
UpdateStart(const nn::hid::PadStatus padStatus)192 void UpdateStart(const nn::hid::PadStatus padStatus)
193 {
194     if (padStatus.trigger & nn::hid::BUTTON_A)
195     {
196         // Start download session
197         // Because there is a bug that it difficult to connect with 1 ch
198         DLP_DEBUG_POINT;
199         nn::dlp::Server::OpenSessions(true, 6);
200     }
201     else if (padStatus.trigger & nn::hid::BUTTON_Y)
202     {
203         // Initialize with the user name specified with the code
204         std::memcpy( s_UserName.userName, L"SERVER", sizeof(L"SERVER"));
205         nn::dlp::Server::Finalize();
206         nn::dlp::ServerWithName::Initialize(
207                         &s_IsNoticeNeeded,
208                         s_DlpServerEvent.GetHandle(),
209                         MAX_CLIENT,
210                         CHILD_INDEX,
211                         s_pAlignedWorkBuffer,
212                         s_DlpServerWorkBufferSize,
213                         nn::dlp::MIN_NETWORK_BLOCK_BUFFER_SIZE * 2,
214                         nn::dlp::MIN_NETWORK_BLOCK_BUFFER_NUM,
215                         &s_UserName );
216         // Start download session
217         // Because there is a bug that it difficult to connect with 1 ch
218         DLP_DEBUG_POINT;
219         nn::dlp::Server::OpenSessions(true, 6);
220     }
221 
222 }
223 
DisplayStart(demo::RenderSystemDrawing * pRenderSystem)224 void DisplayStart(demo::RenderSystemDrawing* pRenderSystem)
225 {
226     u16 x = 1;
227     u16 y = 2;
228 
229     pRenderSystem->SetColor(WHITE_COLOR);
230     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "SIMPLE SERVER");
231 
232     y++;
233     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS A TO START");
234     y++;
235     if (s_IsNoticeNeeded)
236     {
237         y++;
238         pRenderSystem->SetColor(RED_COLOR);
239         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "[WARNING]");
240         y++;
241         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "SimpleServer may disconnect clients without");
242         pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "a notice. Please update clients via network.");
243     }
244 }
245 
246 /*!--------------------------------------------------------------------------*
247  Accept client status
248  *---------------------------------------------------------------------------*/
UpdateAcceptClient(u16 * pSelected,const nn::hid::PadStatus padStatus)249 void UpdateAcceptClient(u16* pSelected, const nn::hid::PadStatus padStatus)
250 {
251     // Get the client list
252     u16 clientNum = 0;
253     u16 clientId[MAX_CLIENT];
254     nn::dlp::Server::GetConnectingClients(&clientNum, clientId, MAX_CLIENT);
255 
256     // Checks whether waiting for Accept
257     bool isWaitingAccept = false;
258     if ((*pSelected) < clientNum)
259     {
260         DLP_DEBUG_POINT;
261         // Gets client status
262         nn::dlp::ClientState clientState;
263         nn::dlp::Server::GetClientState(&clientState, clientId[*pSelected]);
264         if (clientState == nn::dlp::CLIENT_STATE_WAITING_ACCEPT)
265         {
266             DLP_DEBUG_POINT;
267             isWaitingAccept = true;
268         }
269     }
270 
271     if (padStatus.trigger & nn::hid::BUTTON_A)
272     {
273         DLP_DEBUG_POINT;
274         // ACCEPT
275         if (isWaitingAccept)
276         {
277             DLP_DEBUG_POINT;
278             // Accept
279             nn::dlp::Server::AcceptClient(clientId[*pSelected]);
280         }
281     }
282     else if (padStatus.trigger & nn::hid::BUTTON_B)
283     {
284         DLP_DEBUG_POINT;
285         // REJECT
286         if (isWaitingAccept)
287         {
288             DLP_DEBUG_POINT;
289             // Disconnect
290             nn::dlp::Server::DisconnectClient(clientId[*pSelected]);
291         }
292     }
293     else if (padStatus.trigger & nn::hid::BUTTON_X)
294     {
295         DLP_DEBUG_POINT;
296         // Start distribution
297         nn::dlp::Server::StartDistribute();
298         nn::dlp::Server::GetConnectingClients(&s_ClientNum, clientId, MAX_CLIENT);
299     }
300     else if (padStatus.trigger & nn::hid::BUTTON_UP)
301     {
302         DLP_DEBUG_POINT;
303         // Move the selection
304         (*pSelected) = ((*pSelected) - 1 + MAX_CLIENT) % MAX_CLIENT;
305     }
306     else if (padStatus.trigger & nn::hid::BUTTON_DOWN)
307     {
308         DLP_DEBUG_POINT;
309         // Move the selection
310         (*pSelected) = ((*pSelected) + 1) % MAX_CLIENT;
311     }
312 }
313 
DisplayAcceptClient(u16 selected,demo::RenderSystemDrawing * pRenderSystem)314 void DisplayAcceptClient(u16 selected, demo::RenderSystemDrawing* pRenderSystem)
315 {
316     u16 x = 1;
317     u16 y = 2;
318 
319     y = DisplayClientList(selected, x, y, pRenderSystem);
320 
321     y++;
322     pRenderSystem->SetColor(WHITE_COLOR);
323     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++,
324             "PRESS A TO ACCEPT CLIENT");
325     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++,
326             "PRESS B TO REJECT CLIENT");
327     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++,
328             "(WAIT ACCEPT STATE CLIENT ONLY)");
329     y++;
330     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++,
331             "PRESS X TO START DISTRIBUTE");
332 }
333 
334 /*!--------------------------------------------------------------------------*
335  Distribution status
336  *---------------------------------------------------------------------------*/
UpdateDistribute(nn::hid::PadStatus padStatus)337 void UpdateDistribute(nn::hid::PadStatus padStatus)
338 {
339     if (padStatus.trigger & nn::hid::BUTTON_B)
340     {
341         DLP_DEBUG_POINT;
342         nn::dlp::Server::CloseSessions();
343     }
344 }
345 
DisplayDistribute(demo::RenderSystemDrawing * pRenderSystem)346 void DisplayDistribute(demo::RenderSystemDrawing* pRenderSystem)
347 {
348     u16 x = 1;
349     u16 y = 2;
350 
351     y = DisplayClientList(MAX_CLIENT + 1, x, y, pRenderSystem);
352 
353     pRenderSystem->SetColor(WHITE_COLOR);
354     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "PRESS B TO CANCEL");
355 }
356 
357 /*!--------------------------------------------------------------------------*
358  Distribution completion status
359  *---------------------------------------------------------------------------*/
UpdateComplete()360 void UpdateComplete()
361 {
362     DLP_DEBUG_POINT;
363 
364     u32 random;
365 
366     ::std::srand(static_cast<s32>(nn::os::Tick::GetSystemCurrent() >> 1));
367     random = static_cast<u32>(::std::rand());
368 
369     nn::nstd::TSNPrintf(s_Passphraase, sizeof(s_Passphraase), "%08x", random);
370     DLP_DEBUG_PRINT("Passphrase : %s \n", s_Passphraase);
371 
372     nn::dlp::Server::RebootAllClients(s_Passphraase);
373 }
374 
375 /*!--------------------------------------------------------------------------*
376  Waiting for reboot status
377  *---------------------------------------------------------------------------*/
UpdateReboot()378 void UpdateReboot()
379 {
380     // Get the client list
381     u16 clientNum = 0;
382     u16 clientId[MAX_CLIENT];
383     if (nn::dlp::Server::GetConnectingClients(&clientNum, clientId, MAX_CLIENT).IsSuccess())
384     {
385         DLP_DEBUG_POINT;
386         if (clientNum == 0)
387         {
388             DLP_DEBUG_POINT;
389             s_IsDistributionDone = true;
390         }
391     }
392 }
393 
DisplayReboot(demo::RenderSystemDrawing * pRenderSystem)394 void DisplayReboot(demo::RenderSystemDrawing* pRenderSystem)
395 {
396     u16 x = 1;
397     u16 y = 2;
398 
399     y = DisplayClientList(MAX_CLIENT + 1, x, y, pRenderSystem);
400 }
401 
402 
403 /*!--------------------------------------------------------------------------*
404  Error state
405  *---------------------------------------------------------------------------*/
UpdateError(nn::hid::PadStatus padStatus)406 void UpdateError(nn::hid::PadStatus padStatus)
407 {
408     nn::dlp::Server::Finalize();
409     if (padStatus.trigger & nn::hid::BUTTON_A)
410     {
411         DLP_DEBUG_POINT;
412         s_Selected = 0;
413         nn::dlp::Server::Initialize(
414                         &s_IsNoticeNeeded,
415                         s_DlpServerEvent.GetHandle(),
416                         MAX_CLIENT,
417                         CHILD_INDEX,
418                         s_pAlignedWorkBuffer,
419                         s_DlpServerWorkBufferSize);
420     }
421 }
422 
DisplayError(demo::RenderSystemDrawing * pRenderSystem)423 void DisplayError(demo::RenderSystemDrawing* pRenderSystem)
424 {
425     u16 x = 1;
426     u16 y = 2;
427 
428     pRenderSystem->SetColor(WHITE_COLOR);
429     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++, "+++ ERROR +++");
430 
431     y++;
432     pRenderSystem->DrawText(FONT_SIZE * x, FONT_SIZE * y++,
433             "PRESS A TO RESTART");
434 }
435 
436 /*!--------------------------------------------------------------------------*
437  Black background
438  *---------------------------------------------------------------------------*/
DisplayBlackBack(demo::RenderSystemDrawing & renderSystem)439 void DisplayBlackBack(demo::RenderSystemDrawing& renderSystem)
440 {
441     renderSystem.SetRenderTarget(NN_GX_DISPLAY0);
442     renderSystem.Clear();
443     renderSystem.SwapBuffers();
444     renderSystem.SetRenderTarget(NN_GX_DISPLAY1);
445     renderSystem.Clear();
446     renderSystem.SwapBuffers();
447 }
448 
449 
450 /*!--------------------------------------------------------------------------*
451  Update/display state functions
452  *---------------------------------------------------------------------------*/
Update(nn::dlp::ServerState serverState,u16 * pSelected,const nn::hid::PadStatus padStatus)453 void Update(nn::dlp::ServerState serverState, u16* pSelected,
454         const nn::hid::PadStatus padStatus)
455 {
456     switch (serverState)
457     {
458     case nn::dlp::SERVER_STATE_INITIALIZED:
459         UpdateStart(padStatus);
460         break;
461     case nn::dlp::SERVER_STATE_OPENED_SESSIONS:
462         UpdateAcceptClient(pSelected, padStatus);
463         break;
464     case nn::dlp::SERVER_STATE_DISTRIBUTING:
465         UpdateDistribute(padStatus);
466         break;
467     case nn::dlp::SERVER_STATE_COMPLETE_DISTRIBUTION:
468         UpdateComplete();
469         break;
470     case nn::dlp::SERVER_STATE_REBOOTING_CLIENTS:
471         UpdateReboot();
472         break;
473     case nn::dlp::SERVER_STATE_ERROR:
474     case nn::dlp::SERVER_STATE_INVALID:
475         UpdateError(padStatus);
476         break;
477     }
478 }
Display(nn::dlp::ServerState serverState,u16 selected,demo::RenderSystemDrawing * pRenderSystem)479 void Display(nn::dlp::ServerState serverState, u16 selected,
480         demo::RenderSystemDrawing* pRenderSystem)
481 {
482     // Render on the upper screen
483     pRenderSystem->SetRenderTarget(NN_GX_DISPLAY0);
484     pRenderSystem->Clear();
485 
486     switch (serverState)
487     {
488     case nn::dlp::SERVER_STATE_INITIALIZED:
489         DisplayStart(pRenderSystem);
490         break;
491     case nn::dlp::SERVER_STATE_OPENED_SESSIONS:
492         DisplayAcceptClient(selected, pRenderSystem);
493         break;
494     case nn::dlp::SERVER_STATE_DISTRIBUTING:
495     case nn::dlp::SERVER_STATE_COMPLETE_DISTRIBUTION:
496         DisplayDistribute(pRenderSystem);
497         break;
498     case nn::dlp::SERVER_STATE_REBOOTING_CLIENTS:
499         DisplayReboot(pRenderSystem);
500         break;
501     case nn::dlp::SERVER_STATE_ERROR:
502     case nn::dlp::SERVER_STATE_INVALID:
503         DisplayError(pRenderSystem);
504         break;
505     }
506 
507     pRenderSystem->SwapBuffers();
508 
509     // Render on the lower screen
510     pRenderSystem->SetRenderTarget(NN_GX_DISPLAY1);
511     pRenderSystem->Clear();
512 
513     // DisplayTitleInfo(pRenderSystem);
514 
515     pRenderSystem->SwapBuffers();
516 }
517 
518 /*!--------------------------------------------------------------------------*
519  Main function
520  *---------------------------------------------------------------------------*/
521 
nnMain(void)522 void nnMain(void)
523 {
524     nn::Result result;
525 
526     //Set sleep callback, sleep recovery callback
527     nn::applet::SetSleepQueryCallback(mySleepQueryCallback, 0);
528     nn::applet::SetAwakeCallback(myAwakeCallback, 0);
529     nn::applet::Enable();
530     s_AwakeEvent.Initialize(false); DLP_DEBUG_POINT;
531 
532     // Initialize hid
533     result = nn::hid::Initialize();
534     NN_UTIL_PANIC_IF_FAILED(result);
535 
536     // Prepare pad
537     nn::hid::PadReader padReader;
538 
539     // Allocate heap
540     nn::fnd::ExpHeap appHeap;
541     appHeap.Initialize(nn::os::GetDeviceMemoryAddress(), 16 * 1024 * 1024 ); // nn::os::GetDeviceMemorySize()
542 
543     // Prepare RenderSystem
544     uptr heapForGx = reinterpret_cast<uptr> (appHeap.Allocate(0x800000));
545     demo::RenderSystemDrawing renderSystem;
546     renderSystem.Initialize(heapForGx, 0x800000);
547     renderSystem.SetClearColor(NN_GX_DISPLAY_BOTH, 0.f, 0.f, 0.f, 0.f);
548     renderSystem.SetFontSize(FONT_SIZE);
549     renderSystem.SetLineWidth(LINE_WIDTH);
550 
551     // Initialize event used by DLP server
552     s_DlpServerEvent.Initialize(false);
553 
554     // Get work buffer size necessary to initialize DLP server
555     s_DlpServerWorkBufferSize = nn::dlp::Server::GetBufferSize(MAX_CLIENT);
556     DLP_DEBUG_PRINT("dlpServerWorkBufferSize %d\n", s_DlpServerWorkBufferSize);
557 
558     // Get DLP server work buffer
559     s_pWorkBuffer = new u8[s_DlpServerWorkBufferSize + 4096];
560     DLP_DEBUG_PRINT("dlpServerWorkBuffer allocated address 0x%08x\n", s_pWorkBuffer);
561     s_pAlignedWorkBuffer
562             = reinterpret_cast<void*> (DLP_ROUNDUP(reinterpret_cast<u32>(s_pWorkBuffer), 4096UL));
563     DLP_DEBUG_PRINT("dlpServerWorkBuffer aligned  address 0x%08x\n", s_pAlignedWorkBuffer);
564 
565     renderSystem.SetRenderTarget(NN_GX_DISPLAY0);
566     renderSystem.Clear();
567     DisplayInitialize(&renderSystem);
568     renderSystem.SwapBuffers();
569 
570     // Initialize DLP server
571     nn::dlp::Server::Initialize(
572                     &s_IsNoticeNeeded,
573                     s_DlpServerEvent.GetHandle(),
574                     MAX_CLIENT,
575                     CHILD_INDEX,
576                     s_pAlignedWorkBuffer,
577                     s_DlpServerWorkBufferSize);
578     DLP_DEBUG_POINT;
579 
580     nn::dlp::ServerState serverState;
581 
582     while (!s_IsDistributionDone)
583     {
584         // Get pad input
585         padReader.ReadLatest(&s_PadStatus);
586         nn::dlp::Server::GetState(&serverState);
587 
588         // Update
589         Update(serverState, &s_Selected, s_PadStatus);
590 
591         // Render
592         Display(serverState, s_Selected, &renderSystem);
593 
594 
595         //Sleep support
596         if ( nn::applet::IsExpectedToReplySleepQuery() )
597         {
598             DLP_DEBUG_POINT;
599             nn::dlp::Server::Finalize();    // Finalize before sleep.
600             nn::applet::ReplySleepQuery(nn::applet::REPLY_ACCEPT); DLP_DEBUG_POINT;
601             s_AwakeEvent.Wait(); DLP_DEBUG_POINT;
602 
603             // Processing after restart
604             nn::gx::StartLcdDisplay(); DLP_DEBUG_POINT;
605         }
606 
607         //HOME Button support
608         if (nn::applet::IsExpectedToProcessHomeButton())
609         {
610             DLP_DEBUG_POINT;
611             nn::dlp::Server::Finalize();
612             nn::applet::ProcessHomeButton();
613             nn::applet::WaitForStarting(); DLP_DEBUG_POINT;
614 
615             // Recover the GPU register settings
616             nngxUpdateState(NN_GX_STATE_ALL);
617             nngxValidateState(NN_GX_STATE_ALL,GL_TRUE);
618 
619             if (nn::applet::IsExpectedToCloseApplication())
620             {
621                 DLP_DEBUG_POINT;
622                 break;
623             }
624         }
625 
626         //POWER Button support
627         if ( nn::applet::IsExpectedToProcessPowerButton() )
628         {
629             DLP_DEBUG_POINT;
630             nn::dlp::Server::Finalize();
631             nn::applet::ProcessPowerButton();
632             nn::applet::WaitForStarting(); DLP_DEBUG_POINT;
633 
634             // Recover the GPU register settings
635             nngxUpdateState(NN_GX_STATE_ALL);
636             nngxValidateState(NN_GX_STATE_ALL,GL_TRUE);
637 
638             if ( nn::applet::IsExpectedToCloseApplication() )
639             {
640                 DLP_DEBUG_POINT;
641                 break;
642             }
643         }
644 
645         // Support for termination request
646         if (nn::applet::IsExpectedToCloseApplication())
647         {
648             DLP_DEBUG_POINT;
649             DisplayBlackBack(renderSystem);
650             break;
651         }
652     }
653 
654     nn::dlp::Server::Finalize(); DLP_DEBUG_POINT;
655     s_DlpServerEvent.Finalize(); DLP_DEBUG_POINT;
656     delete[] s_pWorkBuffer; DLP_DEBUG_POINT;
657     renderSystem.Finalize();
658     appHeap.Free(reinterpret_cast<void*>(heapForGx));
659     appHeap.Finalize();
660     nn::hid::Finalize();
661     nn::applet::DisableSleep();
662     nn::applet::SetSleepQueryCallback(NULL, 0);
663     nn::applet::SetAwakeCallback(NULL, 0);
664     s_AwakeEvent.Finalize();
665 
666     // Communicate with child device as the parent device
667     if (s_IsDistributionDone)
668     {
669         DLP_DEBUG_POINT;
670         // Because this is a provisional implementation, the SLEEP, HOME, and POWER Buttons do not work after this
671         DoParent(s_ClientNum, s_Passphraase);
672     }
673 
674     nn::applet::CloseApplication();
675     // Execution does not come here
676     DLP_DEBUG_PRINT("EXIT.\n");
677 }
678