1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - demos - cloneboot
3   File:     parent.c
4 
5   Copyright 2006-2009 Nintendo.  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   $Date:: 2009-08-31#$
14   $Rev: 11030 $
15   $Author: tominaga_masafumi $
16 *---------------------------------------------------------------------------*/
17 
18 
19 #include <nitro.h>
20 #include <nitro/wm.h>
21 #include <nitro/mb.h>
22 
23 #include "mbp.h"
24 #include "common.h"
25 #include "disp.h"
26 #include "gmain.h"
27 #include "wh.h"
28 
29 
30 /******************************************************************************/
31 
32 static void GetChannelMain(void);
33 static BOOL ConnectMain(u16 tgid);
34 static void PrintChildState(void);
35 static BOOL JudgeConnectableChild(WMStartParentCallback *cb);
36 
37 
38 //============================================================================
39 //  Constant Definitions
40 //============================================================================
41 
42 /* The GGID used in this demo */
43 #define WH_GGID                 SDK_MAKEGGID_SYSTEM(0x22)
44 
45 
46 /* The program information that this demo downloads */
47 const MBGameRegistry mbGameList = {
48     /*
49      * When clone booting, specify NULL as the program's path name.
50      * This is the specification for MBP_RegistFile() in the MBP module, however: the argument actually passed to MB_RegisterFile() can be anything.
51      *
52      */
53     NULL,
54     (u16 *)L"DataShareDemo",           // Game name
55     (u16 *)L"DataSharing demo(cloneboot)",      // Game content description
56     "/data/icon.char",                 // Icon character data
57     "/data/icon.plt",                  // Icon palette data
58     WH_GGID,                           // GGID
59     MBP_CHILD_MAX + 1,                 // Max. number of players, including parents
60 };
61 
62 
63 
64 //============================================================================
65 //   Variable Definitions
66 //============================================================================
67 
68 static s32 gFrame;                     // Frame counter
69 
70 //-----------------------
71 // For keeping communication channels
72 //-----------------------
73 static u16 sChannel = 0;
74 static const MBPChildInfo *sChildInfo[MBP_CHILD_MAX];
75 
76 
77 //============================================================================
78 //   Function Definitions
79 //============================================================================
80 
81 
82 /*****************************************************************************/
83 /* Start the definition range of the .parent section parent device exclusive region */
84 #include <nitro/parent_begin.h>
85 /*****************************************************************************/
86 
87 
88 /*---------------------------------------------------------------------------*
89   Name:         ParentMain
90 
91   Description:  Parent main routine
92 
93   Arguments:    None.
94 
95   Returns:      None.
96  *---------------------------------------------------------------------------*/
ParentMain(void)97 void ParentMain(void)
98 {
99     u16     tgid = 0;
100 
101     // Initialize screen, OS
102     CommonInit();
103     // Initialize screen
104     DispInit();
105     // Initialize the heap
106     InitAllocateSystem();
107 
108     // Set data in WH
109     WH_SetGgid(WH_GGID);
110 
111     // Enable interrupts
112     (void)OS_EnableIrq();
113     (void)OS_EnableInterrupts();
114 
115 
116     {                                  /* FS initialization */
117         static u32 fs_tablework[0x100 / 4];
118         FS_Init(FS_DMA_NOT_USE);
119         (void)FS_LoadTable(fs_tablework, sizeof(fs_tablework));
120     }
121 
122     DispOn();
123 
124     while (TRUE)
125     {
126         OS_WaitVBlankIntr();
127 
128         // Search for a channel with little traffic
129         GetChannelMain();
130 
131         /*
132          * Normally, a different TGID value is set every time the parent starts.
133          * Note that you will no longer be able to reconnect to a multiboot child when starting with a different tgid unless you rescan.
134          *
135          * You do not need to save the tgid if you reconnect after rescanning.
136          *
137          */
138         // Multiboot distribution
139         if (ConnectMain(++tgid))
140         {
141             // Multiboot child startup is successful
142             break;
143         }
144         else
145         {
146             // Exit the WH module and repeat
147             WH_Finalize();
148             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
149             (void)WH_End();
150             while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
151         }
152     }
153 
154     //--------------
155     // Following multiboot, the child is reset and communication is temporarily disconnected.
156     // The parent also needs to end the communication with MB_End() again in the current implementation.
157     // Start the communication from the beginning while parent and children are completely disconnected.
158     //
159     // At this time, the AIDs of the children will be shuffled. If necessary, save the AID and MAC address combination before multiboot, and link it to a new AID when reconnecting.
160     //
161     //
162     //--------------
163 
164 
165     // Set buffer for data sharing communication
166     GInitDataShare();
167 
168 #if !defined(MBP_USING_MB_EX)
169     if (!WH_Initialize())
170     {
171         OS_Panic("WH_Initialize failed.");
172     }
173 #endif
174 
175     // Set the function to determine connected children
176     WH_SetJudgeAcceptFunc(JudgeConnectableChild);
177 
178     /* Main routine */
179     for (gFrame = 0; TRUE; gFrame++)
180     {
181         OS_WaitVBlankIntr();
182 
183         ReadKey();
184 
185         BgClear();
186 
187         switch (WH_GetSystemState())
188         {
189         case WH_SYSSTATE_IDLE:
190             /* ----------------
191              * To reconnect a child to the same parent without rescanning, the parent needs to have the same tgid and channel as the child.
192              *
193              * In this demo, the parent and child use the same channel as, and a tgid one greater than, the multiboot value, allowing them to connect without rescanning.
194              *
195              *
196              * You don't need to use the same tgid or channel if you rescan with a specified MAC address.
197              *
198              * ---------------- */
199             (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, (u16)(tgid + 1), sChannel);
200             break;
201 
202         case WH_SYSSTATE_CONNECTED:
203         case WH_SYSSTATE_KEYSHARING:
204         case WH_SYSSTATE_DATASHARING:
205             {
206                 BgPutString(8, 1, 0x2, "Parent mode");
207                 GStepDataShare(gFrame);
208                 GMain();
209             }
210             break;
211         }
212     }
213 }
214 
215 /*---------------------------------------------------------------------------*
216   Name:         GetChannelMain
217 
218   Description:  Thoroughly checks the radio wave usage to find the channel to use.
219 
220   Arguments:    None.
221 
222   Returns:      None.
223  *---------------------------------------------------------------------------*/
GetChannelMain(void)224 static void GetChannelMain(void)
225 {
226 
227     /*-----------------------------------------------*
228      * Chooses the least-used channel after thoroughly checking the channels' radio wave activity.
229      *
230      * The state must be IDLE to call WM_MeasureChannel(). This cannot be run in a multiboot state because it does not stop in the IDLE state.
231      *
232      * First call WM_Initialize to check radio wave activity, then end processing with WM_End, and finally run MB_Init again.
233      *
234      *-----------------------------------------------*/
235     if (!WH_Initialize())
236     {
237         OS_Panic("WH_Initialize failed.");
238     }
239 
240     while (TRUE)
241     {
242         ReadKey();
243         BgClear();
244         BgSetMessage(PLTT_YELLOW, " Search Channel ");
245 
246         switch (WH_GetSystemState())
247         {
248             //-----------------------------------------
249             // Initialization complete
250         case WH_SYSSTATE_IDLE:
251             BgSetMessage(PLTT_WHITE, " Push A Button to start   ");
252             if (IS_PAD_TRIGGER(PAD_BUTTON_A))
253             {
254                 BgSetMessage(PLTT_YELLOW, "Check Traffic ratio       ");
255                 (void)WH_StartMeasureChannel();
256             }
257             break;
258             //-----------------------------------------
259             // Complete channel search
260         case WH_SYSSTATE_MEASURECHANNEL:
261             {
262                 sChannel = WH_GetMeasureChannel();
263 #if !defined(MBP_USING_MB_EX)
264                 (void)WH_End();
265 #else
266                 /* Proceed to the multiboot process while maintaining the IDLE state */
267                 return;
268 #endif
269             }
270             break;
271             //-----------------------------------------
272             // End WM
273         case WH_SYSSTATE_STOP:
274             /* Proceed to the multiboot process once WM_End completes */
275             return;
276             //-----------------------------------------
277             // Busy
278         case WH_SYSSTATE_BUSY:
279             break;
280             //-----------------------------------------
281             // Error occurred
282         case WH_SYSSTATE_ERROR:
283             (void)WH_Reset();
284             break;
285             //-----------------------------------------
286         default:
287             OS_Panic("Illegal State\n");
288         }
289         OS_WaitVBlankIntr();           // Wait for completion of V-Blank interrupt
290     }
291 }
292 
293 
294 /*---------------------------------------------------------------------------*
295   Name:         ConnectMain
296 
297   Description:  Connect with multiboot.
298 
299   Arguments:    tgid: The tgid for booting as parent
300 
301   Returns:      If transfer to the child is successful, TRUE.
302                 If transfer fails or is canceled, FALSE.
303  *---------------------------------------------------------------------------*/
ConnectMain(u16 tgid)304 static BOOL ConnectMain(u16 tgid)
305 {
306     MBP_Init(mbGameList.ggid, tgid);
307 
308     while (TRUE)
309     {
310         ReadKey();
311 
312         BgClear();
313 
314         BgSetMessage(PLTT_YELLOW, " MB Parent ");
315 
316         switch (MBP_GetState())
317         {
318             //-----------------------------------------
319             // Idle state
320         case MBP_STATE_IDLE:
321             {
322                 MBP_Start(&mbGameList, sChannel);
323             }
324             break;
325 
326             //-----------------------------------------
327             // Accepting entry from the child
328         case MBP_STATE_ENTRY:
329             {
330                 BgSetMessage(PLTT_WHITE, " Now Accepting            ");
331 
332                 if (IS_PAD_TRIGGER(PAD_BUTTON_B))
333                 {
334                     // Cancel multiboot with B Button
335                     MBP_Cancel();
336                     break;
337                 }
338 
339                 // If there is at least one child in entry, start is possible
340                 if (MBP_GetChildBmp(MBP_BMPTYPE_ENTRY) ||
341                     MBP_GetChildBmp(MBP_BMPTYPE_DOWNLOADING) ||
342                     MBP_GetChildBmp(MBP_BMPTYPE_BOOTABLE))
343                 {
344                     BgSetMessage(PLTT_WHITE, " Push START Button to start   ");
345 
346                     if (IS_PAD_TRIGGER(PAD_BUTTON_START))
347                     {
348                         // Start download
349                         MBP_StartDownloadAll();
350                     }
351                 }
352             }
353             break;
354 
355             //-----------------------------------------
356             // Program distribution process
357         case MBP_STATE_DATASENDING:
358             {
359 
360                 // If everyone has completed download, start is possible
361                 if (MBP_IsBootableAll())
362                 {
363                     // Start boot
364                     MBP_StartRebootAll();
365                 }
366             }
367             break;
368 
369             //-----------------------------------------
370             // Reboot process
371         case MBP_STATE_REBOOTING:
372             {
373                 BgSetMessage(PLTT_WHITE, " Rebooting now                ");
374             }
375             break;
376 
377             //-----------------------------------------
378             // Reconnect process
379         case MBP_STATE_COMPLETE:
380             {
381                 // Once all members have successfully connected, the multi-boot processing ends, and restarts the wireless as an normal parent
382                 //
383                 BgSetMessage(PLTT_WHITE, " Reconnecting now             ");
384 
385                 OS_WaitVBlankIntr();
386                 return TRUE;
387             }
388             break;
389 
390             //-----------------------------------------
391             // Error occurred
392         case MBP_STATE_ERROR:
393             {
394                 // Cancel communication
395                 MBP_Cancel();
396             }
397             break;
398 
399             //-----------------------------------------
400             // Communication cancellation processsing
401         case MBP_STATE_CANCEL:
402             // None.
403             break;
404 
405             //-----------------------------------------
406             // Abnormal termination of communication
407         case MBP_STATE_STOP:
408             OS_WaitVBlankIntr();
409             return FALSE;
410         }
411 
412         // Display child state
413         PrintChildState();
414 
415         OS_WaitVBlankIntr();           // Wait for completion of V-Blank interrupt
416     }
417 }
418 
419 
420 /*---------------------------------------------------------------------------*
421   Name:         PrintChildState
422 
423   Description:  Displays child information on screen.
424 
425   Arguments:    None.
426 
427   Returns:      None.
428  *---------------------------------------------------------------------------*/
PrintChildState(void)429 static void PrintChildState(void)
430 {
431     static const char *STATE_NAME[] = {
432         "NONE       ",
433         "CONNECTING ",
434         "REQUEST    ",
435         "ENTRY      ",
436         "DOWNLOADING",
437         "BOOTABLE   ",
438         "BOOTING    ",
439     };
440     enum
441     {
442         STATE_DISP_X = 2,
443         INFO_DISP_X = 15,
444         BASE_DISP_Y = 2
445     };
446 
447     u16     i;
448 
449     /* Child list display */
450     for (i = 1; i <= MBP_CHILD_MAX; i++)
451     {
452         const MBPChildInfo *childInfo;
453         MBPChildState childState = MBP_GetChildState(i);
454         const u8 *macAddr;
455 
456         SDK_ASSERT(childState < MBP_CHILDSTATE_NUM);
457 
458         // State display
459         BgPutString(STATE_DISP_X, i + BASE_DISP_Y, PLTT_WHITE, STATE_NAME[childState]);
460 
461         // User information display
462         childInfo = MBP_GetChildInfo(i);
463         macAddr = MBP_GetChildMacAddress(i);
464 
465         if (macAddr != NULL)
466         {
467             BgPrintStr(INFO_DISP_X, i + BASE_DISP_Y, PLTT_WHITE,
468                        "%02x%02x%02x%02x%02x%02x",
469                        macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
470         }
471     }
472 }
473 
474 
475 /*---------------------------------------------------------------------------*
476   Name:         JudgeConnectableChild
477 
478   Description:  Determines if the child is connectable during reconnect.
479 
480   Arguments:    cb: Information for the child attempting to connect
481 
482   Returns:      If connection is accepted, TRUE.
483                 If not accepted, FALSE.
484  *---------------------------------------------------------------------------*/
JudgeConnectableChild(WMStartParentCallback * cb)485 static BOOL JudgeConnectableChild(WMStartParentCallback *cb)
486 {
487     u16     playerNo;
488 
489     /*  Search the MAC address for the AID of when multibooting the child of cb->aid */
490     playerNo = MBP_GetPlayerNo(cb->macAddress);
491 
492     OS_TPrintf("MB child(%d) -> DS child(%d)\n", playerNo, cb->aid);
493 
494     if (playerNo == 0)
495     {
496         return FALSE;
497     }
498 
499     sChildInfo[playerNo - 1] = MBP_GetChildInfo(playerNo);
500     return TRUE;
501 }
502 
503 
504 /*****************************************************************************/
505 /* End the definition boundary of the .parent section parent device exclusive region */
506 #include <nitro/parent_end.h>
507 /*****************************************************************************/
508