1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - MB - demos - cloneboot
3 File: parent.c
4
5 Copyright 2006-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: 11030 $
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
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 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
149 (void)WH_End();
150 while(WH_GetSystemState()==WH_SYSSTATE_BUSY){}
151 }
152 }
153
154 //--------------
155 // Following multiboot, the child is reset and communication is temporarily disconnected.
156 // The parent also needs to end the communication with MB_End() again in the current implementation.
157 // Start the communication from the beginning while parent and children are completely disconnected.
158 //
159 // 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.
160 //
161 //
162 //--------------
163
164
165 // Set buffer for data sharing communication
166 GInitDataShare();
167
168 #if !defined(MBP_USING_MB_EX)
169 if (!WH_Initialize())
170 {
171 OS_Panic("WH_Initialize failed.");
172 }
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: GetChannelMain
217
218 Description: Thoroughly checks the radio wave usage to find the channel to use.
219
220 Arguments: None.
221
222 Returns: None.
223 *---------------------------------------------------------------------------*/
GetChannelMain(void)224 static void GetChannelMain(void)
225 {
226
227 /*-----------------------------------------------*
228 * Chooses the least-used channel after thoroughly checking the channels' radio wave activity.
229 *
230 * 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.
231 *
232 * First call WM_Initialize to check radio wave activity, then end processing with WM_End, and finally run MB_Init again.
233 *
234 *-----------------------------------------------*/
235 if (!WH_Initialize())
236 {
237 OS_Panic("WH_Initialize failed.");
238 }
239
240 while (TRUE)
241 {
242 ReadKey();
243 BgClear();
244 BgSetMessage(PLTT_YELLOW, " Search Channel ");
245
246 switch (WH_GetSystemState())
247 {
248 //-----------------------------------------
249 // Initialization complete
250 case WH_SYSSTATE_IDLE:
251 BgSetMessage(PLTT_WHITE, " Push A Button to start ");
252 if (IS_PAD_TRIGGER(PAD_BUTTON_A))
253 {
254 BgSetMessage(PLTT_YELLOW, "Check Traffic ratio ");
255 (void)WH_StartMeasureChannel();
256 }
257 break;
258 //-----------------------------------------
259 // Complete channel search
260 case WH_SYSSTATE_MEASURECHANNEL:
261 {
262 sChannel = WH_GetMeasureChannel();
263 #if !defined(MBP_USING_MB_EX)
264 (void)WH_End();
265 #else
266 /* Proceed to the multiboot process while maintaining the IDLE state */
267 return;
268 #endif
269 }
270 break;
271 //-----------------------------------------
272 // End WM
273 case WH_SYSSTATE_STOP:
274 /* Proceed to the multiboot process once WM_End completes */
275 return;
276 //-----------------------------------------
277 // Busy
278 case WH_SYSSTATE_BUSY:
279 break;
280 //-----------------------------------------
281 // Error occurred
282 case WH_SYSSTATE_ERROR:
283 (void)WH_Reset();
284 break;
285 //-----------------------------------------
286 default:
287 OS_Panic("Illegal State\n");
288 }
289 OS_WaitVBlankIntr(); // Wait for completion of V-Blank interrupt
290 }
291 }
292
293
294 /*---------------------------------------------------------------------------*
295 Name: ConnectMain
296
297 Description: Connect with multiboot.
298
299 Arguments: tgid: The tgid for booting as parent
300
301 Returns: If transfer to the child is successful, TRUE.
302 If transfer fails or is canceled, FALSE.
303 *---------------------------------------------------------------------------*/
ConnectMain(u16 tgid)304 static BOOL ConnectMain(u16 tgid)
305 {
306 MBP_Init(mbGameList.ggid, tgid);
307
308 while (TRUE)
309 {
310 ReadKey();
311
312 BgClear();
313
314 BgSetMessage(PLTT_YELLOW, " MB Parent ");
315
316 switch (MBP_GetState())
317 {
318 //-----------------------------------------
319 // Idle state
320 case MBP_STATE_IDLE:
321 {
322 MBP_Start(&mbGameList, sChannel);
323 }
324 break;
325
326 //-----------------------------------------
327 // Accepting entry from the child
328 case MBP_STATE_ENTRY:
329 {
330 BgSetMessage(PLTT_WHITE, " Now Accepting ");
331
332 if (IS_PAD_TRIGGER(PAD_BUTTON_B))
333 {
334 // Cancel multiboot with B Button
335 MBP_Cancel();
336 break;
337 }
338
339 // If there is at least one child in entry, start is possible
340 if (MBP_GetChildBmp(MBP_BMPTYPE_ENTRY) ||
341 MBP_GetChildBmp(MBP_BMPTYPE_DOWNLOADING) ||
342 MBP_GetChildBmp(MBP_BMPTYPE_BOOTABLE))
343 {
344 BgSetMessage(PLTT_WHITE, " Push START Button to start ");
345
346 if (IS_PAD_TRIGGER(PAD_BUTTON_START))
347 {
348 // Start download
349 MBP_StartDownloadAll();
350 }
351 }
352 }
353 break;
354
355 //-----------------------------------------
356 // Program distribution process
357 case MBP_STATE_DATASENDING:
358 {
359
360 // If everyone has completed download, start is possible
361 if (MBP_IsBootableAll())
362 {
363 // Start boot
364 MBP_StartRebootAll();
365 }
366 }
367 break;
368
369 //-----------------------------------------
370 // Reboot process
371 case MBP_STATE_REBOOTING:
372 {
373 BgSetMessage(PLTT_WHITE, " Rebooting now ");
374 }
375 break;
376
377 //-----------------------------------------
378 // Reconnect process
379 case MBP_STATE_COMPLETE:
380 {
381 // Once all members have successfully connected, the multi-boot processing ends, and restarts the wireless as an normal parent
382 //
383 BgSetMessage(PLTT_WHITE, " Reconnecting now ");
384
385 OS_WaitVBlankIntr();
386 return TRUE;
387 }
388 break;
389
390 //-----------------------------------------
391 // Error occurred
392 case MBP_STATE_ERROR:
393 {
394 // Cancel communication
395 MBP_Cancel();
396 }
397 break;
398
399 //-----------------------------------------
400 // Communication cancellation processsing
401 case MBP_STATE_CANCEL:
402 // None.
403 break;
404
405 //-----------------------------------------
406 // Abnormal termination of communication
407 case MBP_STATE_STOP:
408 OS_WaitVBlankIntr();
409 return FALSE;
410 }
411
412 // Display child state
413 PrintChildState();
414
415 OS_WaitVBlankIntr(); // Wait for completion of V-Blank interrupt
416 }
417 }
418
419
420 /*---------------------------------------------------------------------------*
421 Name: PrintChildState
422
423 Description: Displays child information on screen.
424
425 Arguments: None.
426
427 Returns: None.
428 *---------------------------------------------------------------------------*/
PrintChildState(void)429 static void PrintChildState(void)
430 {
431 static const char *STATE_NAME[] = {
432 "NONE ",
433 "CONNECTING ",
434 "REQUEST ",
435 "ENTRY ",
436 "DOWNLOADING",
437 "BOOTABLE ",
438 "BOOTING ",
439 };
440 enum
441 {
442 STATE_DISP_X = 2,
443 INFO_DISP_X = 15,
444 BASE_DISP_Y = 2
445 };
446
447 u16 i;
448
449 /* Child list display */
450 for (i = 1; i <= MBP_CHILD_MAX; i++)
451 {
452 const MBPChildInfo *childInfo;
453 MBPChildState childState = MBP_GetChildState(i);
454 const u8 *macAddr;
455
456 SDK_ASSERT(childState < MBP_CHILDSTATE_NUM);
457
458 // State display
459 BgPutString(STATE_DISP_X, i + BASE_DISP_Y, PLTT_WHITE, STATE_NAME[childState]);
460
461 // User information display
462 childInfo = MBP_GetChildInfo(i);
463 macAddr = MBP_GetChildMacAddress(i);
464
465 if (macAddr != NULL)
466 {
467 BgPrintStr(INFO_DISP_X, i + BASE_DISP_Y, PLTT_WHITE,
468 "%02x%02x%02x%02x%02x%02x",
469 macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
470 }
471 }
472 }
473
474
475 /*---------------------------------------------------------------------------*
476 Name: JudgeConnectableChild
477
478 Description: Determines if the child is connectable during reconnect.
479
480 Arguments: cb: Information for the child attempting to connect
481
482 Returns: If connection is accepted, TRUE.
483 If not accepted, FALSE.
484 *---------------------------------------------------------------------------*/
JudgeConnectableChild(WMStartParentCallback * cb)485 static BOOL JudgeConnectableChild(WMStartParentCallback *cb)
486 {
487 u16 playerNo;
488
489 /* Search the MAC address for the AID of when multibooting the child of cb->aid */
490 playerNo = MBP_GetPlayerNo(cb->macAddress);
491
492 OS_TPrintf("MB child(%d) -> DS child(%d)\n", playerNo, cb->aid);
493
494 if (playerNo == 0)
495 {
496 return FALSE;
497 }
498
499 sChildInfo[playerNo - 1] = MBP_GetChildInfo(playerNo);
500 return TRUE;
501 }
502
503
504 /*****************************************************************************/
505 /* End the definition boundary of the .parent section parent device exclusive region */
506 #include <nitro/parent_end.h>
507 /*****************************************************************************/
508