1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - demos - cloneboot
3   File:     parent.c
4 
5   Copyright 2006-2008 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-01-14#$
14   $Rev: 9840 $
15   $Author: nishimoto_takashi $
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             (void)WH_End();
149         }
150     }
151 
152     //--------------
153     // Following multiboot, the child is reset and communication is temporarily disconnected.
154     // The parent also needs to end the communication with MB_End() again in the current implementation.
155     // Start the communication from the beginning while parent and children are completely disconnected.
156     //
157     // 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.
158     //
159     //
160     //--------------
161 
162 
163     // Set buffer for data sharing communication
164     GInitDataShare();
165 
166 #if !defined(MBP_USING_MB_EX)
167     if (!WH_Initialize())
168     {
169         OS_Panic("WH_Initialize failed.");
170     }
171 #endif
172 
173     // Set the function to determine connected children
174     WH_SetJudgeAcceptFunc(JudgeConnectableChild);
175 
176     /* Main routine */
177     for (gFrame = 0; TRUE; gFrame++)
178     {
179         OS_WaitVBlankIntr();
180 
181         ReadKey();
182 
183         BgClear();
184 
185         switch (WH_GetSystemState())
186         {
187         case WH_SYSSTATE_IDLE:
188             /* ----------------
189              * To reconnect a child to the same parent without rescanning, the parent needs to have the same tgid and channel as the child.
190              *
191              * 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.
192              *
193              *
194              * You don't need to use the same tgid or channel if you rescan with a specified MAC address.
195              *
196              * ---------------- */
197             (void)WH_ParentConnect(WH_CONNECTMODE_DS_PARENT, (u16)(tgid + 1), sChannel);
198             break;
199 
200         case WH_SYSSTATE_CONNECTED:
201         case WH_SYSSTATE_KEYSHARING:
202         case WH_SYSSTATE_DATASHARING:
203             {
204                 BgPutString(8, 1, 0x2, "Parent mode");
205                 GStepDataShare(gFrame);
206                 GMain();
207             }
208             break;
209         }
210     }
211 }
212 
213 /*---------------------------------------------------------------------------*
214   Name:         GetChannelMain
215 
216   Description:  Thoroughly checks the radio wave usage to find the channel to use.
217 
218   Arguments:    None.
219 
220   Returns:      None.
221  *---------------------------------------------------------------------------*/
GetChannelMain(void)222 static void GetChannelMain(void)
223 {
224 
225     /*-----------------------------------------------*
226      * Chooses the least-used channel after thoroughly checking the channels' radio wave activity.
227      *
228      * 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.
229      *
230      * First call WM_Initialize to check radio wave activity, then end processing with WM_End, and finally run MB_Init again.
231      *
232      *-----------------------------------------------*/
233     if (!WH_Initialize())
234     {
235         OS_Panic("WH_Initialize failed.");
236     }
237 
238     while (TRUE)
239     {
240         ReadKey();
241         BgClear();
242         BgSetMessage(PLTT_YELLOW, " Search Channel ");
243 
244         switch (WH_GetSystemState())
245         {
246             //-----------------------------------------
247             // Initialization complete
248         case WH_SYSSTATE_IDLE:
249             BgSetMessage(PLTT_WHITE, " Push A Button to start   ");
250             if (IS_PAD_TRIGGER(PAD_BUTTON_A))
251             {
252                 BgSetMessage(PLTT_YELLOW, "Check Traffic ratio       ");
253                 (void)WH_StartMeasureChannel();
254             }
255             break;
256             //-----------------------------------------
257             // Complete channel search
258         case WH_SYSSTATE_MEASURECHANNEL:
259             {
260                 sChannel = WH_GetMeasureChannel();
261 #if !defined(MBP_USING_MB_EX)
262                 (void)WH_End();
263 #else
264                 /* Proceed to the multiboot process while maintaining the IDLE state */
265                 return;
266 #endif
267             }
268             break;
269             //-----------------------------------------
270             // End WM
271         case WH_SYSSTATE_STOP:
272             /* Proceed to the multiboot process once WM_End completes */
273             return;
274             //-----------------------------------------
275             // Busy
276         case WH_SYSSTATE_BUSY:
277             break;
278             //-----------------------------------------
279             // Error occurred
280         case WH_SYSSTATE_ERROR:
281             (void)WH_Reset();
282             break;
283             //-----------------------------------------
284         default:
285             OS_Panic("Illegal State\n");
286         }
287         OS_WaitVBlankIntr();           // Wait for completion of V-Blank interrupt
288     }
289 }
290 
291 
292 /*---------------------------------------------------------------------------*
293   Name:         ConnectMain
294 
295   Description:  Connect with multiboot.
296 
297   Arguments:    tgid: The tgid for booting as parent
298 
299   Returns:      If transfer to the child is successful, TRUE.
300                 If transfer fails or is canceled, FALSE.
301  *---------------------------------------------------------------------------*/
ConnectMain(u16 tgid)302 static BOOL ConnectMain(u16 tgid)
303 {
304     MBP_Init(mbGameList.ggid, tgid);
305 
306     while (TRUE)
307     {
308         ReadKey();
309 
310         BgClear();
311 
312         BgSetMessage(PLTT_YELLOW, " MB Parent ");
313 
314         switch (MBP_GetState())
315         {
316             //-----------------------------------------
317             // Idle state
318         case MBP_STATE_IDLE:
319             {
320                 MBP_Start(&mbGameList, sChannel);
321             }
322             break;
323 
324             //-----------------------------------------
325             // Accepting entry from the child
326         case MBP_STATE_ENTRY:
327             {
328                 BgSetMessage(PLTT_WHITE, " Now Accepting            ");
329 
330                 if (IS_PAD_TRIGGER(PAD_BUTTON_B))
331                 {
332                     // Cancel multiboot with B Button
333                     MBP_Cancel();
334                     break;
335                 }
336 
337                 // If there is at least one child in entry, start is possible
338                 if (MBP_GetChildBmp(MBP_BMPTYPE_ENTRY) ||
339                     MBP_GetChildBmp(MBP_BMPTYPE_DOWNLOADING) ||
340                     MBP_GetChildBmp(MBP_BMPTYPE_BOOTABLE))
341                 {
342                     BgSetMessage(PLTT_WHITE, " Push START Button to start   ");
343 
344                     if (IS_PAD_TRIGGER(PAD_BUTTON_START))
345                     {
346                         // Start download
347                         MBP_StartDownloadAll();
348                     }
349                 }
350             }
351             break;
352 
353             //-----------------------------------------
354             // Program distribution process
355         case MBP_STATE_DATASENDING:
356             {
357 
358                 // If everyone has completed download, start is possible
359                 if (MBP_IsBootableAll())
360                 {
361                     // Start boot
362                     MBP_StartRebootAll();
363                 }
364             }
365             break;
366 
367             //-----------------------------------------
368             // Reboot process
369         case MBP_STATE_REBOOTING:
370             {
371                 BgSetMessage(PLTT_WHITE, " Rebooting now                ");
372             }
373             break;
374 
375             //-----------------------------------------
376             // Reconnect process
377         case MBP_STATE_COMPLETE:
378             {
379                 // Once all members have successfully connected, the multi-boot processing ends, and restarts the wireless as an normal parent
380                 //
381                 BgSetMessage(PLTT_WHITE, " Reconnecting now             ");
382 
383                 OS_WaitVBlankIntr();
384                 return TRUE;
385             }
386             break;
387 
388             //-----------------------------------------
389             // Error occurred
390         case MBP_STATE_ERROR:
391             {
392                 // Cancel communication
393                 MBP_Cancel();
394             }
395             break;
396 
397             //-----------------------------------------
398             // Communication cancellation processsing
399         case MBP_STATE_CANCEL:
400             // None.
401             break;
402 
403             //-----------------------------------------
404             // Abnormal termination of communication
405         case MBP_STATE_STOP:
406             OS_WaitVBlankIntr();
407             return FALSE;
408         }
409 
410         // Display child state
411         PrintChildState();
412 
413         OS_WaitVBlankIntr();           // Wait for completion of V-Blank interrupt
414     }
415 }
416 
417 
418 /*---------------------------------------------------------------------------*
419   Name:         PrintChildState
420 
421   Description:  Displays child information on screen.
422 
423   Arguments:    None.
424 
425   Returns:      None.
426  *---------------------------------------------------------------------------*/
PrintChildState(void)427 static void PrintChildState(void)
428 {
429     static const char *STATE_NAME[] = {
430         "NONE       ",
431         "CONNECTING ",
432         "REQUEST    ",
433         "ENTRY      ",
434         "DOWNLOADING",
435         "BOOTABLE   ",
436         "BOOTING    ",
437     };
438     enum
439     {
440         STATE_DISP_X = 2,
441         INFO_DISP_X = 15,
442         BASE_DISP_Y = 2
443     };
444 
445     u16     i;
446 
447     /* Child list display */
448     for (i = 1; i <= MBP_CHILD_MAX; i++)
449     {
450         const MBPChildInfo *childInfo;
451         MBPChildState childState = MBP_GetChildState(i);
452         const u8 *macAddr;
453 
454         SDK_ASSERT(childState < MBP_CHILDSTATE_NUM);
455 
456         // State display
457         BgPutString(STATE_DISP_X, i + BASE_DISP_Y, PLTT_WHITE, STATE_NAME[childState]);
458 
459         // User information display
460         childInfo = MBP_GetChildInfo(i);
461         macAddr = MBP_GetChildMacAddress(i);
462 
463         if (macAddr != NULL)
464         {
465             BgPrintStr(INFO_DISP_X, i + BASE_DISP_Y, PLTT_WHITE,
466                        "%02x%02x%02x%02x%02x%02x",
467                        macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
468         }
469     }
470 }
471 
472 
473 /*---------------------------------------------------------------------------*
474   Name:         JudgeConnectableChild
475 
476   Description:  Determines if the child is connectable during reconnect.
477 
478   Arguments:    cb: Information for the child attempting to connect
479 
480   Returns:      If connection is accepted, TRUE.
481                 If not accepted, FALSE.
482  *---------------------------------------------------------------------------*/
JudgeConnectableChild(WMStartParentCallback * cb)483 static BOOL JudgeConnectableChild(WMStartParentCallback *cb)
484 {
485     u16     playerNo;
486 
487     /*  Search the MAC address for the AID of when multibooting the child of cb->aid */
488     playerNo = MBP_GetPlayerNo(cb->macAddress);
489 
490     OS_TPrintf("MB child(%d) -> DS child(%d)\n", playerNo, cb->aid);
491 
492     if (playerNo == 0)
493     {
494         return FALSE;
495     }
496 
497     sChildInfo[playerNo - 1] = MBP_GetChildInfo(playerNo);
498     return TRUE;
499 }
500 
501 
502 /*****************************************************************************/
503 /* End the definition boundary of the .parent section parent device exclusive region */
504 #include <nitro/parent_end.h>
505 /*****************************************************************************/
506