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