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(¤t, &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