1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - MB - demos - multiboot-wfs - child
3   File:     child.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:: 2008-10-02#$
14   $Rev: 8827 $
15   $Author: yosizaki $
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 
30 #include    "util.h"
31 #include    "wh.h"
32 #include    "func.h"
33 #include    "common.h"
34 
35 
36 /*---------------------------------------------------------------------------*
37     Internal Constant Definitions
38  *---------------------------------------------------------------------------*/
39 
40 /* Overlay test array */
41 FS_EXTERN_OVERLAY(main_overlay_1);
42 FS_EXTERN_OVERLAY(main_overlay_2);
43 FS_EXTERN_OVERLAY(main_overlay_3);
44 
45 static FSOverlayID ovl_id[] = {
46     FS_OVERLAY_ID(main_overlay_1),
47     FS_OVERLAY_ID(main_overlay_2),
48     FS_OVERLAY_ID(main_overlay_3),
49 };
50 
51 enum
52 { OVL_ID_MAX = sizeof(ovl_id) / sizeof(*ovl_id) };
53 typedef void (*FUNC_TABLE) (char *);
54 
55 const FUNC_TABLE func_table[] = {
56     func_1,
57     func_2,
58     func_3,
59 };
60 
61 
62 /*---------------------------------------------------------------------------*
63     Internal Variable Definitions
64  *---------------------------------------------------------------------------*/
65 
66 /* For file operations */
67 static FSFile file[1];
68 static char tmp_buf[0x40000];
69 
70 static int file_index;
71 static int file_max;
72 static char file_path[8][256];
73 
74 /* Overlay test management variables */
75 static BOOL is_overlay_test = FALSE;
76 static BOOL is_overlay_loaded = FALSE;
77 static int current_overlay = 0;
78 static FSOverlayInfo ovl_info[1];
79 
80 static BOOL init_flag = FALSE;
81 
82 
83 /*---------------------------------------------------------------------------*
84     Internal Function Definitions
85  *---------------------------------------------------------------------------*/
86 
87 static void ModeChildFile(const KeyInfo * p_key);       /* Child file test */
88 static void ModeChildOverlay(const KeyInfo * p_key);    /* Child overlay test */
89 
90 
91 /*---------------------------------------------------------------------------*
92   Name:         CreateFileList
93 
94   Description:  Enumerates files from a directory.
95 
96   Arguments:    pe: The FSDirEntry structure to be recursively shared
97 
98   Returns:      None.
99  *---------------------------------------------------------------------------*/
CreateFileList(FSDirEntry * pe)100 static void CreateFileList(FSDirEntry *pe)
101 {
102     FSFile  d;
103     FS_InitFile(&d);
104     if (FS_SeekDir(&d, &pe->dir_id))
105     {
106         while (FS_ReadDir(&d, pe))
107         {
108             if (file_max >= sizeof(file_path) / sizeof(*file_path))
109                 break;
110             if (pe->is_directory)
111                 CreateFileList(pe);
112             else
113             {
114                 FSFile  f;
115                 FS_InitFile(&f);
116                 if (FS_OpenFileFast(&f, pe->file_id))
117                 {
118                     if (FS_GetPathLength(&f) <= (int)sizeof(*file_path))
119                     {
120                         if (FS_GetPathName(&f, file_path[file_max], sizeof(*file_path)))
121                         {
122                             ++file_max;
123                         }
124                     }
125                     (void)FS_CloseFile(&f);
126                 }
127             }
128         }
129     }
130 }
131 
132 /*---------------------------------------------------------------------------*
133   Name:         PrepareOverlay
134 
135   Description:  Loads the currently selected overlay.
136                 However, it proceeds to the step where the selected overlays are loaded asynchronously and FS_StartOverlay is not called.
137 
138 
139   Arguments:    new_overlay: The index of the newly-loaded overlay
140 
141   Returns:      None.
142  *---------------------------------------------------------------------------*/
PrepareOverlay(int new_overlay)143 static void PrepareOverlay(int new_overlay)
144 {
145     /*
146      * When loading an overlay, all other overlays competing for the region must be unloaded
147 
148 
149      */
150     if (is_overlay_loaded)
151     {
152         is_overlay_loaded = FALSE;
153         (void)FS_UnloadOverlayImage(ovl_info);
154     }
155 
156     current_overlay = new_overlay;
157 
158     /*
159      * First, get the overlay information.
160      * The table has been received via WFS, so this function returns control immediately.
161 
162      */
163     (void)FS_LoadOverlayInfo(ovl_info, MI_PROCESSOR_ARM9, ovl_id[current_overlay]);
164     {
165         /*
166          * Next, load actual data into the overlay module region.
167          * These can also be done simply by calling FS_LoadOverlay, but this would be a synchronous wireless process and therefore take an extremely long time.
168 
169          *
170          * To run the application framework also while waiting, you must either prepare a dedicated thread that calls FS_LoadOverlay or use FS_LoadOverlayImageAsync as follows.
171 
172 
173          */
174         if (!FS_LoadOverlayImageAsync(ovl_info, file))
175         {
176             OS_Panic("FS_LoadOverlayImageAsync() failed!");
177         }
178     }
179 }
180 
181 /*---------------------------------------------------------------------------*
182   Name:         ModeSelect
183 
184   Description:  Process in parent/child selection screen.
185 
186   Arguments:    None.
187 
188   Returns:      None.
189  *---------------------------------------------------------------------------*/
ModeSelect(void)190 void ModeSelect(void)
191 {
192     KeyInfo key[1];
193 
194     InitFrameLoop(key);
195     while (WH_GetSystemState() == WH_SYSSTATE_IDLE)
196     {
197         WaitForNextFrame(key);
198         PrintString(3, 12, COLOR_WHITE, "Press B to connect as CHILD");
199         if (key->trg & PAD_BUTTON_B)
200         {
201             const MBParentBssDesc* parentBssDesc = MB_GetMultiBootParentBssDesc();
202             if (parentBssDesc == NULL)
203             {
204                 OS_Panic("This program can not boot directly.");
205             }
206             (void)WH_ChildConnectAuto(WH_CONNECTMODE_MP_CHILD,
207                                       (const u8 *)parentBssDesc->bssid, 0);
208 
209             WFS_InitChild(port_wbt, StateCallbackForWFS, AllocatorForWFS, NULL);
210         }
211     }
212 }
213 
214 /*---------------------------------------------------------------------------*
215   Name:         ModeChild
216 
217   Description:  Child communications screen.
218 
219   Arguments:    None.
220 
221   Returns:      None.
222  *---------------------------------------------------------------------------*/
ModeChild(void)223 void ModeChild(void)
224 {
225     KeyInfo key[1];
226 
227     if (!init_flag)
228     {
229         init_flag = TRUE;
230         /* Initialize object for file test */
231         FS_InitFile(file);
232     }
233     file_max = 0;
234 
235     InitFrameLoop(key);
236     while (WH_GetSystemState() == WH_SYSSTATE_CONNECTED && WH_GetConnectMode() == WH_CONNECTMODE_MP_CHILD)
237     {
238         BOOL    bak_state = is_overlay_test;
239 
240         WaitForNextFrame(key);
241         PrintString(1, 22, COLOR_WHITE, "frame:%d", OS_GetVBlankCount());
242 
243         if (is_overlay_test)
244             ModeChildOverlay(key);
245         else
246             ModeChildFile(key);
247 
248         if (bak_state != is_overlay_test)
249         {
250             ClearLine();
251         }
252     }
253 
254 }
255 
256 /*---------------------------------------------------------------------------*
257   Name:         ModeChildFile
258 
259   Description:  The file load test process on the child communications screen.
260 
261   Arguments:    key: Key input
262 
263   Returns:      None.
264  *---------------------------------------------------------------------------*/
ModeChildFile(const KeyInfo * p_key)265 static void ModeChildFile(const KeyInfo * p_key)
266 {
267     int     i;
268 
269     PrintString(8, 1, COLOR_WHITE, "Child mode");
270     PrintString(2, 3, COLOR_WHITE, "ReadFile test.");
271     PrintString(2, 19, COLOR_WHITE, "Press B to move Overlay test.");
272     PrintString(2, 20, COLOR_WHITE, "Press START to disconnect.");
273 
274     if (WFS_GetStatus() == WFS_STATE_READY)
275     {
276 
277         /* Generate list of files */
278         if (file_max == 0)
279         {
280             FSFile  d;
281             FSDirEntry e;
282             FS_InitFile(&d);
283             (void)FS_FindDir(&d, "");
284             MI_WriteByte(e.name + 0, (u8)'\0');
285             (void)FS_TellDir(&d, &e.dir_id);
286             CreateFileList(&e);
287         }
288 
289         /* Select the file ID that should be loaded */
290         if (p_key->trg & PAD_KEY_UP)
291         {
292             if (--file_index < 0)
293             {
294                 file_index = file_max - 1;
295             }
296         }
297         if (p_key->trg & PAD_KEY_DOWN)
298         {
299             if (++file_index > file_max - 1)
300             {
301                 file_index = 0;
302             }
303         }
304 
305         PrintString(3, 5, COLOR_GREEN, "<UP & DOWN key>");
306         PrintString(3, 6, COLOR_WHITE, "select testing file");
307         PrintString(2, 7 + file_index, COLOR_WHITE, ">");
308         for (i = 0; i < file_max; ++i)
309         {
310             PrintString(4, 7 + i, COLOR_WHITE, file_path[i]);
311         }
312         PrintString(3, 15, COLOR_GREEN, "<press A button>");
313 
314         /* State in which the file read is empty */
315         if (!FS_IsFile(file))
316         {
317 
318             /* Go to overlay test with B button */
319             if (p_key->trg & PAD_BUTTON_B)
320             {
321                 is_overlay_test = TRUE;
322                 PrepareOverlay(current_overlay);
323             }
324 
325             /* Read selected file with A button */
326             else if (p_key->trg & PAD_BUTTON_A)
327             {
328 
329                 if (!FS_OpenFileEx(file, file_path[file_index], FS_FILEMODE_R))
330                 {
331                     file_index = 0;
332                     OS_TPrintf("No file:\"%s\"\n", file_path[file_index]);
333                 }
334                 else
335                 {
336                     /*
337                      * Go to read the file
338                      *
339                      * Setting asynchronous mode will immediately return processing, but to get the actual transfer speed we run a synchronous process
340 
341 
342                      * Note that if a game calls functions in this way from the main thread, the game sequence will be blocked for a very long time and the overall framework will be affected negatively
343 
344 
345 
346                      *
347                      * To see how to load in asynchronous mode, refer to the section that loads overlays
348 
349                      */
350                     int     ret;
351                     int     bps = 0;
352                     int     rest;
353                     u64     milli;
354                     OSTick  t;
355                     t = OS_GetTick();
356                     rest = (int)(FS_GetFileLength(file) - FS_GetFilePosition(file));
357                     if (rest > (int)sizeof(tmp_buf))
358                     {
359                         rest = (int)sizeof(tmp_buf);
360                     }
361                     PrintString(3, 16, COLOR_WHITE, "reading... %d BYTE", rest);
362 
363                     /*
364                      * Synchronous processing will not be interrupted as long as the WFS_End function is not called, so poll as follows to support disconnection detection in the synchronous version
365 
366                      * Except for the fact that it occupies CPU time by polling without transferring threads, this process is essentially equivalent to the FS_ReadFile function
367 
368                      *
369                      * If a thread separate from synchronous operations periodically checks for disconnection, this kind of process is unnecessary. Instead, you can use the FS_ReadFile function directly.
370 
371                      * (Note that you cannot call the WFS_End function from an interrupt handler)
372 
373                      */
374                     {
375                         ret = FS_ReadFileAsync(file, tmp_buf, sizeof(tmp_buf));
376                         while (FS_IsBusy(file))
377                         {
378                             if (WH_GetSystemState() == WH_SYSSTATE_IDLE)
379                             {
380                                 WFS_End();
381                                 ret = -1;
382                             }
383 #if defined(SDK_ENABLE_ARM7_PRINT)
384                             // PrintServer for ARM7 (for debugging purposes)
385                             OS_PrintServer();
386 #endif
387                         }
388                     }
389                     /*
390                      * The sample simply panics when there is an interruption, but an application can move on to recovery processing
391 
392                      * (The FS_GetResultCode function returns FS_RESULT_ERROR)
393                      */
394                     if (ret != rest)
395                     {
396                         OS_Panic("FS_ReadFileAsync() returned invalid length!");
397                     }
398                     milli = OS_TicksToMilliSeconds(OS_GetTick() - t);
399                     if (milli)
400                     {
401                         u64     d = ret * 8;
402                         d *= 1000;
403                         bps = (int)(d / milli);
404                         PrintLine(3, 16, "read done %d BYTE", ret);
405                         PrintLine(3, 17, "%d [bps]/%d [Bps]", bps, bps / 8);
406                     }
407                     (void)FS_CloseFile(file);
408                 }
409             }
410         }
411     }
412 
413     if (p_key->trg & PAD_BUTTON_START)
414     {
415         WH_Finalize();
416         while (WH_GetSystemState() != WH_SYSSTATE_IDLE) {}
417     }
418 }
419 
420 /*---------------------------------------------------------------------------*
421   Name:         ModeChildOverlay
422 
423   Description:  The file overlay test process on the child communications screen.
424 
425   Arguments:    key: Key input
426 
427   Returns:      None.
428  *---------------------------------------------------------------------------*/
ModeChildOverlay(const KeyInfo * p_key)429 static void ModeChildOverlay(const KeyInfo * p_key)
430 {
431     PrintString(8, 1, COLOR_WHITE, "Child mode");
432     PrintString(2, 3, COLOR_WHITE, "Overlay test.");
433     PrintString(2, 19, COLOR_WHITE, "Press B to move ReadFile test.");
434     PrintString(2, 20, COLOR_WHITE, "Press START to disconnect.");
435 
436     if (WFS_GetStatus() == WFS_STATE_READY)
437     {
438         PrintString(3, 5, COLOR_GREEN, "<UP & DOWN key>");
439         PrintString(3, 6, COLOR_WHITE, "select overlay");
440         PrintString(18, 6 + current_overlay, COLOR_WHITE, ">");
441         PrintString(20, 6, COLOR_WHITE, "func_1");
442         PrintString(20, 7, COLOR_WHITE, "func_2");
443         PrintString(20, 8, COLOR_WHITE, "func_3");
444 
445         PrintString(3, 10, COLOR_GREEN, "<press A button>");
446         PrintString(3, 11, COLOR_BLUE, "(call overlay func)");
447 
448         /* If in a state where the file read is empty, overlay operations are possible */
449         if (!FS_IsFile(file))
450         {
451 
452             /* Go to ReadFile test with B button */
453             if (p_key->trg & PAD_BUTTON_B)
454             {
455                 is_overlay_test = FALSE;
456             }
457             else
458             {
459                 /* Switch overlay with up and down */
460                 int     new_overlay = current_overlay;
461 
462                 if (p_key->trg & PAD_KEY_DOWN)
463                 {
464                     if (++new_overlay >= OVL_ID_MAX)
465                         new_overlay -= OVL_ID_MAX;
466                 }
467                 if (p_key->trg & PAD_KEY_UP)
468                 {
469                     if (--new_overlay < 0)
470                         new_overlay += OVL_ID_MAX;
471                 }
472                 if (current_overlay != new_overlay)
473                 {
474                     PrepareOverlay(new_overlay);
475                 }
476                 /* Call current function with A button */
477                 else if (p_key->trg & PAD_BUTTON_A)
478                 {
479                     char    tmp[64];
480                     (*(func_table[current_overlay])) (tmp);
481                     PrintLine(3, 11, tmp);
482                 }
483             }
484         }
485         else
486         {
487             /* Display progress if receiving overlay */
488             if (FS_IsBusy(file))
489             {
490                 int     current, total;
491                 PrintLine(2, 14, "loading...%8d BYTE", FS_GetFileLength(file));
492                 if (WFS_GetCurrentDownloadProgress(&current, &total))
493                 {
494                     PrintLine(2, 15, "progress %8d / %8d", current, total);
495                 }
496             }
497             /* Start up overlay if read is complete */
498             else
499             {
500                 if (!is_overlay_loaded)
501                 {
502                     PrintLine(2, 14, "loading done. %8d BYTE", FS_GetFileLength(file));
503                     PrintLine(2, 15, "");
504                     FS_StartOverlay(ovl_info);
505                     (void)FS_CloseFile(file);
506                     is_overlay_loaded = TRUE;
507                 }
508             }
509         }
510     }
511 
512     if (p_key->trg & PAD_BUTTON_START)
513     {
514         WH_Finalize();
515         while (WH_GetSystemState() != WH_SYSSTATE_IDLE) {}
516     }
517 }
518 
519 
520 /*---------------------------------------------------------------------------*
521   End of file
522  *---------------------------------------------------------------------------*/
523