1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - WVR - demos - with_mb
3   File:     main.c
4 
5   Copyright 2003-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:: 2008-09-17#$
14   $Rev: 8556 $
15   $Author: okubata_ryoma $
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 #include <nitro/wvr.h>
30 
31 /*
32  * Sample application that reconnects after multiboot.
33  *
34  * Because the MB library samples use the multiboot functionality, multiple development units with the same communications environment (wired or wireless) are required.
35  *
36  * The mb_child.bin program in the directory $NitroSDK/bin/ARM9-TS/Release/ is a sample providing the same features as the multiboot child in the final commercial unit. Load this binary into other development units using the same method as for sample programs, and execute them together.
37  *
38  *
39  *
40  *
41  *
42  */
43 
44 /******************************************************************************/
45 
46 static void GetChannelMain(void);
47 static BOOL ConnectMain(u16 tgid);
48 static void PrintChildState(void);
49 static BOOL JudgeConnectableChild(WMStartParentCallback *cb);
50 
51 static void StartUpCallback(void *arg, WVRResult result);
52 
53 
54 //============================================================================
55 //  Constant Definitions
56 //============================================================================
57 
58 /* The GGID used in this demo */
59 #define WH_GGID                 SDK_MAKEGGID_SYSTEM(0x21)
60 
61 
62 /* The program information that this demo downloads */
63 const MBGameRegistry mbGameList = {
64     "/child.srl",                      // Child binary code
65     (u16 *)L"DataShareDemo",           // Game name
66     (u16 *)L"DataSharing demo",        // Game content description
67     "/data/icon.char",                 // Icon character data
68     "/data/icon.plt",                  // Icon palette data
69     WH_GGID,                           // GGID
70     MBP_CHILD_MAX + 1,                 // Max. number of players, including parents
71 };
72 
73 
74 
75 //============================================================================
76 //   Variable Definitions
77 //============================================================================
78 
79 static u32 gFrame;                     // Frame counter
80 
81 //-----------------------
82 // For keeping communication channels
83 //-----------------------
84 static u16 sChannel = 0;
85 static const MBPChildInfo *sChildInfo[MBP_CHILD_MAX];
86 
87 static volatile u8 startCheck;
88 
89 
90 //============================================================================
91 //   Function Definitions
92 //============================================================================
93 
94 /*---------------------------------------------------------------------------*
95   Name:         NitroMain
96 
97   Description:  Main routine.
98 
99   Arguments:    None.
100 
101   Returns:      None.
102  *---------------------------------------------------------------------------*/
NitroMain(void)103 void NitroMain(void)
104 {
105     u16     tgid = 0;
106 
107     // Initialize screen, OS
108     CommonInit();
109     // Initialize screen
110     DispInit();
111     // Initialize the heap
112     InitAllocateSystem();
113 
114     // Set data in WH
115     WH_SetGgid(WH_GGID);
116 
117     // Enable interrupts
118     (void)OS_EnableIrq();
119     (void)OS_EnableInterrupts();
120 
121     /*================================================================*/
122     // Start activating the wireless library
123     startCheck = 0;
124     if (WVR_RESULT_OPERATING != WVR_StartUpAsync(GX_VRAM_ARM7_128_D, StartUpCallback, NULL))
125     {
126         OS_TPanic("WVR_StartUpAsync failed. \n");
127     }
128     while (!startCheck)
129     {
130     }
131     /*================================================================*/
132 
133     DispOn();
134 
135     while (TRUE)
136     {
137         OS_WaitVBlankIntr();
138 
139         // Search for a channel with little traffic
140         GetChannelMain();
141 
142         /*
143          * Normally, a different TGID value is set every time the parent starts.
144          * Note that you will no longer be able to reconnect to a multiboot child when starting with a different tgid unless you rescan.
145          *
146          * You do not need to save the tgid if you reconnect after rescanning.
147          *
148          */
149         // Multiboot distribution
150         if (ConnectMain(++tgid))
151         {
152             // Multiboot child startup is successful
153             break;
154         }
155     }
156 
157     //--------------
158     // Following multiboot, the child is reset and communication is temporarily disconnected.
159     // The parent also needs to end the communication with MB_End() again in the current implementation.
160     // Start the communication from the beginning while parent and children are completely disconnected.
161     //
162     // 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.
163     //
164     //
165     //--------------
166 
167 
168     // Set buffer for data sharing communication
169     GInitDataShare();
170 
171 #if !defined(MBP_USING_MB_EX)
172     (void)WH_Initialize();
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:         StartUpCallback
217 
218   Description:  Callback function to be notified end of async processing in wireless operation control library.
219 
220 
221   Arguments:    arg: Argument specified when WVR_StartUpAsync is called. Not used.
222                 result: The processing results from async function
223 
224   Returns:      None.
225  *---------------------------------------------------------------------------*/
StartUpCallback(void * arg,WVRResult result)226 static void StartUpCallback(void *arg, WVRResult result)
227 {
228 #pragma unused( arg )
229 
230     if (result != WVR_RESULT_SUCCESS)
231     {
232         OS_TPanic("WVR_StartUpAsync error.[%08xh]\n", result);
233     }
234     startCheck = 1;
235 }
236 
237 /*---------------------------------------------------------------------------*
238   Name:         GetChannelMain
239 
240   Description:  Thoroughly checks the radio wave usage to find the channel to use.
241 
242   Arguments:    None.
243 
244   Returns:      None.
245  *---------------------------------------------------------------------------*/
GetChannelMain(void)246 static void GetChannelMain(void)
247 {
248 
249     /*-----------------------------------------------*
250      * Chooses the least-used channel after thoroughly checking the channels' radio wave activity.
251      *
252      * 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.
253      *
254      * First call WM_Initialize to check radio wave activity, then end processing with WM_End, and finally run MB_Init again.
255      *
256      *-----------------------------------------------*/
257     (void)WH_Initialize();
258 
259     while (TRUE)
260     {
261         ReadKey();
262         BgClear();
263         BgSetMessage(PLTT_YELLOW, " Search Channel ");
264 
265         switch (WH_GetSystemState())
266         {
267             //-----------------------------------------
268             // Initialization complete
269         case WH_SYSSTATE_IDLE:
270             BgSetMessage(PLTT_WHITE, " Push A Button to start   ");
271             if (IS_PAD_TRIGGER(PAD_BUTTON_A))
272             {
273                 BgSetMessage(PLTT_YELLOW, "Check Traffic ratio       ");
274                 (void)WH_StartMeasureChannel();
275             }
276             break;
277             //-----------------------------------------
278             // Complete channel search
279         case WH_SYSSTATE_MEASURECHANNEL:
280             {
281                 sChannel = WH_GetMeasureChannel();
282 #if !defined(MBP_USING_MB_EX)
283                 (void)WH_End();
284 #else
285                 /* Proceed to the multiboot process while maintaining the IDLE state */
286                 return;
287 #endif
288             }
289             break;
290             //-----------------------------------------
291             // End WM
292         case WH_SYSSTATE_STOP:
293             /* Proceed to the multiboot process once WM_End completes */
294             return;
295             //-----------------------------------------
296             // Busy
297         case WH_SYSSTATE_BUSY:
298             break;
299             //-----------------------------------------
300             // Error occurred
301         case WH_SYSSTATE_ERROR:
302             (void)WH_Reset();
303             break;
304             //-----------------------------------------
305         default:
306             OS_Panic("Illegal State\n");
307         }
308         OS_WaitVBlankIntr();           // Wait for completion of V-Blank interrupt
309     }
310 }
311 
312 
313 /*---------------------------------------------------------------------------*
314   Name:         ConnectMain
315 
316   Description:  Connect with multiboot.
317 
318   Arguments:    tgid: The tgid for booting as parent
319 
320   Returns:      Returns TRUE if the transfer to the child succeeds; returns FALSE if transfer fails or is cancelled.
321 
322  *---------------------------------------------------------------------------*/
ConnectMain(u16 tgid)323 static BOOL ConnectMain(u16 tgid)
324 {
325     MBP_Init(mbGameList.ggid, tgid);
326 
327     while (TRUE)
328     {
329         ReadKey();
330 
331         BgClear();
332 
333         BgSetMessage(PLTT_YELLOW, " MB Parent ");
334 
335         switch (MBP_GetState())
336         {
337             //-----------------------------------------
338             // Idle state
339         case MBP_STATE_IDLE:
340             {
341                 MBP_Start(&mbGameList, sChannel);
342             }
343             break;
344 
345             //-----------------------------------------
346             // Accepting entry from the child
347         case MBP_STATE_ENTRY:
348             {
349                 BgSetMessage(PLTT_WHITE, " Now Accepting            ");
350 
351                 if (IS_PAD_TRIGGER(PAD_BUTTON_B))
352                 {
353                     // Cancel multiboot with B Button
354                     MBP_Cancel();
355                     break;
356                 }
357 
358                 // If there is at least one child in entry, start is possible
359                 if (MBP_GetChildBmp(MBP_BMPTYPE_ENTRY) ||
360                     MBP_GetChildBmp(MBP_BMPTYPE_DOWNLOADING) ||
361                     MBP_GetChildBmp(MBP_BMPTYPE_BOOTABLE))
362                 {
363                     BgSetMessage(PLTT_WHITE, " Push START Button to start   ");
364 
365                     if (IS_PAD_TRIGGER(PAD_BUTTON_START))
366                     {
367                         // Start download
368                         MBP_StartDownloadAll();
369                     }
370                 }
371             }
372             break;
373 
374             //-----------------------------------------
375             // Program distribution process
376         case MBP_STATE_DATASENDING:
377             {
378 
379                 // If everyone has completed download, start is possible
380                 if (MBP_IsBootableAll())
381                 {
382                     // Start boot
383                     MBP_StartRebootAll();
384                 }
385             }
386             break;
387 
388             //-----------------------------------------
389             // Reboot process
390         case MBP_STATE_REBOOTING:
391             {
392                 BgSetMessage(PLTT_WHITE, " Rebooting now                ");
393             }
394             break;
395 
396             //-----------------------------------------
397             // Reconnect process
398         case MBP_STATE_COMPLETE:
399             {
400                 // Once all members have successfully connected, the multiboot processing ends and restarts the wireless as an normal parent
401                 //
402                 BgSetMessage(PLTT_WHITE, " Reconnecting now             ");
403 
404                 OS_WaitVBlankIntr();
405                 return TRUE;
406             }
407             break;
408 
409             //-----------------------------------------
410             // Error occurred
411         case MBP_STATE_ERROR:
412             {
413                 // Cancel communication
414                 MBP_Cancel();
415             }
416             break;
417 
418             //-----------------------------------------
419             // Communication cancellation processing
420         case MBP_STATE_CANCEL:
421             // None.
422             break;
423 
424             //-----------------------------------------
425             // Abnormal termination of communication
426         case MBP_STATE_STOP:
427             OS_WaitVBlankIntr();
428             return FALSE;
429         }
430 
431         // Display child state
432         PrintChildState();
433 
434         OS_WaitVBlankIntr();           // Wait for completion of V-Blank interrupt
435     }
436 }
437 
438 
439 /*---------------------------------------------------------------------------*
440   Name:         PrintChildState
441 
442   Description:  Displays child information on screen.
443 
444   Arguments:    None.
445 
446   Returns:      None.
447  *---------------------------------------------------------------------------*/
PrintChildState(void)448 static void PrintChildState(void)
449 {
450     static const char *STATE_NAME[] = {
451         "NONE       ",
452         "CONNECTING ",
453         "REQUEST    ",
454         "ENTRY      ",
455         "DOWNLOADING",
456         "BOOTABLE   ",
457         "BOOTING    ",
458     };
459     enum
460     {
461         STATE_DISP_X = 2,
462         INFO_DISP_X = 15,
463         BASE_DISP_Y = 2
464     };
465 
466     u16     i;
467 
468     /* Child list display */
469     for (i = 1; i <= MBP_CHILD_MAX; i++)
470     {
471         const MBPChildInfo *childInfo;
472         MBPChildState childState = MBP_GetChildState(i);
473         const u8 *macAddr;
474 
475         SDK_ASSERT(childState < MBP_CHILDSTATE_NUM);
476 
477         // State display
478         BgPutString(STATE_DISP_X, i + BASE_DISP_Y, PLTT_WHITE, STATE_NAME[childState]);
479 
480         // User information display
481         childInfo = MBP_GetChildInfo(i);
482         macAddr = MBP_GetChildMacAddress(i);
483 
484         if (macAddr != NULL)
485         {
486             BgPrintStr(INFO_DISP_X, i + BASE_DISP_Y, PLTT_WHITE,
487                        "%02x%02x%02x%02x%02x%02x",
488                        macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
489         }
490     }
491 }
492 
493 
494 /*---------------------------------------------------------------------------*
495   Name:         JudgeConnectableChild
496 
497   Description:  Determines if the child is connectable during reconnect.
498 
499   Arguments:    cb: Information for the child attempting to connect
500 
501   Returns:      If connection is accepted, TRUE.
502                 If not accepted, FALSE.
503  *---------------------------------------------------------------------------*/
JudgeConnectableChild(WMStartParentCallback * cb)504 static BOOL JudgeConnectableChild(WMStartParentCallback *cb)
505 {
506     u16     playerNo;
507 
508     /*  Search the MAC address for the AID of when multibooting the child of cb->aid */
509     playerNo = MBP_GetPlayerNo(cb->macAddress);
510 
511     OS_TPrintf("MB child(%d) -> DS child(%d)\n", playerNo, cb->aid);
512 
513     if (playerNo == 0)
514     {
515         return FALSE;
516     }
517 
518     sChildInfo[playerNo - 1] = MBP_GetChildInfo(playerNo);
519     return TRUE;
520 }
521