1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - MB - demos - multiboot-wfs - parent
3 File: multiboot.c
4
5 Copyright 2005-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-18#$
14 $Rev: 8575 $
15 $Author: nishimoto_takashi $
16 *---------------------------------------------------------------------------*/
17
18
19 #ifdef SDK_TWL
20 #include <twl.h>
21 #else
22 #include <nitro.h>
23 #endif
24 #include <nitro/wm.h>
25 #include <nitro/wbt.h>
26 #include <nitro/fs.h>
27
28 #include "wfs.h"
29 #include "wh.h"
30 #include "mbp.h"
31
32 #include "util.h"
33 #include "common.h"
34
35
36 /*---------------------------------------------------------------------------*
37 Internal Constant Definitions
38 *---------------------------------------------------------------------------*/
39
40 /* The program information that this demo downloads */
41 const MBGameRegistry mbGameList = {
42 "data/main.srl", // Child binary code
43 (u16 *)L"MultibootWFS", // Game name
44 (u16 *)L"Multiboot-WFS demo", // Game content description
45 "data/icon.char", // Icon character data
46 "data/icon.plt", // Icon palette data
47 GGID_WBT_FS, // GGID
48 MBP_CHILD_MAX + 1, // Max. number of players, including parents
49 };
50
51
52 /*---------------------------------------------------------------------------*
53 Internal Variable Definitions
54 *---------------------------------------------------------------------------*/
55
56 static void *sWmWork;
57
58 /* Initialize variables for channel measurement */
59 static volatile BOOL sChannelBusy;
60 static u16 sChannel;
61 static u16 sChannelBusyRatio;
62 static u16 sChannelBitmap;
63
64
65 /*---------------------------------------------------------------------------*
66 Function Definitions
67 *---------------------------------------------------------------------------*/
68
69 static void GetChannelProc(void *arg);
70 static void GetChannelMain(void);
71 static void ConnectMain(void);
72 static void PrintChildState(void);
73
74
75 /*---------------------------------------------------------------------------*
76 Name: ModeMultiboot
77
78 Description: DS Single-Card play parent processing.
79
80 Arguments: None.
81
82 Returns: None.
83 *---------------------------------------------------------------------------*/
ModeMultiboot(void)84 void ModeMultiboot(void)
85 {
86 /* Search channel with the lowest radio wave usage rate */
87 GetChannelMain();
88
89 /* Multiboot distribution */
90 ConnectMain();
91 }
92
93 /*---------------------------------------------------------------------------*
94 Name: GetChannelProc
95
96 Description: Series of WM function callbacks for channel measurement.
97 When specified as the WM_Initialize callback, measure the usage rate of all available channels, and store the lowest channel in sChannel to complete.
98
99
100 When specified as the WM_End callback, complete immediately.
101 When completing, set sChannelBusy to FALSE.
102
103 Arguments: arg: WM function callback structure
104
105 Returns: None.
106 *---------------------------------------------------------------------------*/
GetChannelProc(void * arg)107 static void GetChannelProc(void *arg)
108 {
109 u16 channel = 1;
110 u16 allowedChannel;
111
112 WMCallback *cb = (WMCallback *)arg;
113
114 /* If WM_End callback, indicate completion */
115 if (cb->apiid == WM_APIID_END)
116 {
117 sChannelBusy = FALSE;
118 return;
119 }
120 /* If WM_Initialize callback, start measurement process */
121 else if (cb->apiid == WM_APIID_INITIALIZE)
122 {
123 }
124 /* Otherwise, WM_MeasureChannel callback */
125 else
126 {
127 WMMeasureChannelCallback *cb = (WMMeasureChannelCallback *)arg;
128 if (cb->errcode != WM_ERRCODE_SUCCESS)
129 {
130 OS_TPanic("WM_MeasureChannel() failed!");
131 }
132 channel = cb->channel;
133 /* If the usage rate is the lowest so far, use it */
134 if (sChannelBusyRatio > cb->ccaBusyRatio)
135 {
136 sChannelBusyRatio = cb->ccaBusyRatio;
137 sChannelBitmap = (u16)(1 << (channel - 1));
138 }
139 /* Use it also if the value is equal to the lowest so far */
140 else if (sChannelBusyRatio == cb->ccaBusyRatio)
141 {
142 sChannelBitmap |= 1 << (channel - 1);
143 }
144 ++channel;
145 }
146
147 /* Obtain the available channels */
148 allowedChannel = WM_GetAllowedChannel();
149 if (allowedChannel == 0x8000)
150 {
151 OS_TPanic("WM_GetAllowedChannel() failed!");
152 }
153 else if (allowedChannel == 0)
154 {
155 OS_TPanic("no available wireless channels!");
156 }
157
158 /* Complete after all channels are measured */
159 if ((1 << (channel - 1)) > allowedChannel)
160 {
161 int num = MATH_CountPopulation(sChannelBitmap);
162 if (num == 0)
163 {
164 OS_TPanic("no available wireless channels!");
165 }
166 else if (num == 1)
167 {
168 sChannel = (u16)(31 - MATH_CountLeadingZeros(sChannelBitmap) + 1);
169 }
170 /* If more than one channel has the same usage rate, pick one at random */
171 else
172 {
173 int select = (int)(((OS_GetVBlankCount() & 0xFF) * num) / 0x100);
174 int i;
175 for (i = 0; i < 16; i++)
176 {
177 if ((sChannelBitmap & (1 << i)) && (--select < 0))
178 {
179 break;
180 }
181 }
182 sChannel = (u16)(i + 1);
183 }
184 sChannelBusy = FALSE;
185 }
186 /* If there is an unmeasured channel, continue process */
187 else
188 {
189 while (((1 << (channel - 1)) & allowedChannel) == 0)
190 {
191 ++channel;
192 }
193 if (WM_MeasureChannel(GetChannelProc, 3, 17, channel, 30) != WM_ERRCODE_OPERATING)
194 {
195 OS_TPanic("WM_MeasureChannel() failed!");
196 }
197 }
198 }
199
200 /*---------------------------------------------------------------------------*
201 Name: GetChannelMain
202
203 Description: Measure channel with the lowest usage rate.
204
205 Arguments: None.
206
207 Returns: None.
208 *---------------------------------------------------------------------------*/
GetChannelMain(void)209 static void GetChannelMain(void)
210 {
211 KeyInfo key[1];
212
213 /* Initialize variables for channel measurement */
214 sChannelBusy = TRUE;
215 sChannel = 0;
216 sChannelBusyRatio = 100 + 1;
217 sChannelBitmap = 0;
218
219 /* Allocate WM work memory and start library */
220 sWmWork = OS_Alloc(WM_SYSTEM_BUF_SIZE);
221 if (!sWmWork)
222 {
223 OS_TPanic("failed to allocate memory for WM!");
224 }
225 else if (WM_Initialize(sWmWork, GetChannelProc, 2) != WM_ERRCODE_OPERATING)
226 {
227 OS_TPanic("WM_Initialize() failed!");
228 }
229
230 /* Standby until measurement is done */
231 InitFrameLoop(key);
232 while (sChannelBusy)
233 {
234 WaitForNextFrame(key);
235 PrintString(4, 22, COLOR_YELLOW, " Searching Channel %c",
236 ((OS_GetVBlankCount() / 10) & 1) ? '_' : ' ');
237 }
238
239 #if !defined(MBP_USING_MB_EX)
240 /* Close library and release WM work memory */
241 sChannelBusy = TRUE;
242 if (WM_End(GetChannelProc) != WM_ERRCODE_OPERATING)
243 {
244 OS_TPanic("WM_End() failed!");
245 }
246 while (sChannelBusy)
247 {
248 }
249 OS_Free(sWmWork), sWmWork = NULL;
250 #endif
251
252 }
253
254 /*---------------------------------------------------------------------------*
255 Name: ConnectMain
256
257 Description: Connect with multiboot.
258
259 Arguments: tgid: Specifies the tgid for booting as parent
260
261 Returns: TRUE if the transfer to the child succeeds; FALSE if transfer fails or is canceled.
262
263 *---------------------------------------------------------------------------*/
ConnectMain(void)264 static void ConnectMain(void)
265 {
266 KeyInfo key[1];
267
268 MBP_Init(mbGameList.ggid, WM_GetNextTgid());
269
270 InitFrameLoop(key);
271 for (;;)
272 {
273 int state;
274
275 WaitForNextFrame(key);
276 PrintString(4, 22, COLOR_YELLOW, " MB Parent ");
277 state = MBP_GetState();
278 /* Idle state */
279 if (state == MBP_STATE_IDLE)
280 {
281 MBP_Start(&mbGameList, sChannel);
282 }
283 /* Accepting entry from the child */
284 else if (state == MBP_STATE_ENTRY)
285 {
286 PrintString(4, 22, COLOR_WHITE, " Now Accepting ");
287 /* Cancel multiboot with B button */
288 if (key->trg & PAD_BUTTON_B)
289 {
290 MBP_Cancel();
291 }
292 /* If there is at least one child in entry, start is possible */
293 else if (MBP_GetChildBmp(MBP_BMPTYPE_ENTRY) ||
294 MBP_GetChildBmp(MBP_BMPTYPE_DOWNLOADING) ||
295 MBP_GetChildBmp(MBP_BMPTYPE_BOOTABLE))
296 {
297 PrintString(4, 22, COLOR_WHITE, " Push START Button to start ");
298 if (key->trg & PAD_BUTTON_START)
299 {
300 /* Start download */
301 MBP_StartDownloadAll();
302 }
303 }
304 }
305 /*
306 * Program distribution process.
307 * If everyone has finished downloading, send a reboot request
308 */
309 else if (state == MBP_STATE_DATASENDING)
310 {
311 if (MBP_IsBootableAll())
312 {
313 MBP_StartRebootAll();
314 }
315 }
316 /* Standby processing for child reboot */
317 else if (state == MBP_STATE_REBOOTING)
318 {
319 PrintString(4, 22, COLOR_WHITE, " Rebooting now ");
320 }
321 /* Processing for when child reboot is finished */
322 else if (state == MBP_STATE_COMPLETE)
323 {
324 PrintString(4, 22, COLOR_WHITE, " Reconnecting now ");
325 break;
326 }
327 /* When error occurs, cancel communication */
328 else if (state == MBP_STATE_ERROR)
329 {
330 MBP_Cancel();
331 }
332 /* Communication cancellation processing */
333 else if (state == MBP_STATE_CANCEL)
334 {
335 }
336 /* Abnormal termination of communication */
337 else if (state == MBP_STATE_STOP)
338 {
339 break;
340 }
341
342 /* Display child status */
343 PrintChildState();
344 }
345
346 #if defined(MBP_USING_MB_EX)
347 /* Close library and release WM work memory */
348 sChannelBusy = TRUE;
349 if (WM_End(GetChannelProc) != WM_ERRCODE_OPERATING)
350 {
351 OS_TPanic("WM_End() failed!");
352 }
353 while (sChannelBusy)
354 {
355 }
356 OS_Free(sWmWork), sWmWork = NULL;
357 #endif
358
359 }
360
361 /*---------------------------------------------------------------------------*
362 Name: PrintChildState
363
364 Description: Displays child information on screen.
365
366 Arguments: None.
367
368 Returns: None.
369 *---------------------------------------------------------------------------*/
PrintChildState(void)370 static void PrintChildState(void)
371 {
372 static const char *STATE_NAME[] = {
373 "NONE ",
374 "CONNECTING ",
375 "REQUEST ",
376 "ENTRY ",
377 "DOWNLOADING",
378 "BOOTABLE ",
379 "BOOTING ",
380 };
381 enum
382 {
383 STATE_DISP_X = 2,
384 INFO_DISP_X = 15,
385 BASE_DISP_Y = 2
386 };
387
388 u16 i;
389
390 /* Child list display */
391 for (i = 1; i <= MBP_CHILD_MAX; i++)
392 {
393 const MBPChildInfo *childInfo;
394 MBPChildState childState = MBP_GetChildState(i);
395 const u8 *macAddr;
396
397 SDK_ASSERT(childState < MBP_CHILDSTATE_NUM);
398
399 // State display
400 PrintString(STATE_DISP_X, i + BASE_DISP_Y, COLOR_WHITE, STATE_NAME[childState]);
401
402 // User information display
403 childInfo = MBP_GetChildInfo(i);
404 macAddr = MBP_GetChildMacAddress(i);
405
406 if (macAddr != NULL)
407 {
408 PrintString(INFO_DISP_X, i + BASE_DISP_Y, COLOR_WHITE,
409 "%02x%02x%02x%02x%02x%02x",
410 macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
411 }
412 }
413 }
414
415
416 /*---------------------------------------------------------------------------*
417 End of file
418 *---------------------------------------------------------------------------*/
419