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