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