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