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