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