1 /*---------------------------------------------------------------------------*
2 Project: TwlSDK - nandApp - demos - backup
3 File: main.c
4
5 Copyright 2007-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-06-04#$
14 $Rev: 10698 $
15 $Author: okubata_ryoma $
16 *---------------------------------------------------------------------------*/
17 #include <twl.h>
18 #include <twl/na.h>
19 #include <DEMO.h>
20 static void PrintBootType();
21 static void InitDEMOSystem();
22 static void InitInteruptSystem();
23 static void InitAllocSystem();
24 static void InitFileSystem();
25
26 static char* LoadFile(const char* path);
27 static BOOL SaveFile(const char* path, void* pData, u32 size);
28
29 static void PrintDirectory(const char* path);
30 static void CreateTree(const char* arc_name);
31 static void DeleteData(char *path);
32 static BOOL WriteData(const char *path, void* pData, u32 size);
33 static void ReadData(const char* arc_name);
34
35 static char* GetTestData(char *out, u32 size);
36 static void DrawString(const char *fmt, ...);
37 static void PrintTree(const char* path, u32 space);
38 static void MountOtherSaveData(const char *code, BOOL flag);
39
40 static const u32 BUF_SIZE = 256;
41
42 /*---------------------------------------------------------------------------*
43 Name: TwlMain
44
45 Description: Main function.
46
47 Arguments: None.
48
49 Returns: None.
50 *---------------------------------------------------------------------------*/
TwlMain(void)51 void TwlMain(void)
52 {
53 OS_Init();
54 RTC_Init();
55 InitInteruptSystem();
56 InitFileSystem();
57 InitAllocSystem();
58 InitDEMOSystem();
59 DrawString("*** start nandApp demo\n");
60
61 DrawString("Build:%s %s\n", __DATE__, __TIME__);
62 PrintBootType();
63 DrawString("\n");
64 DrawString("A - Delete, Create, Read\n");
65 DrawString("B - Print Directory Tree\n");
66
67 // It is possible for NAND applications to access the save data of other NAND applications.
68 //
69 //
70 // The NA_LoadOtherTitleArchive function can be used to mount the save data of another NAND application and access it as archives named "otherPub:" and "otherPrv:".
71 //
72 // Only one region can be mounted at a time, however.
73 //
74 // To mount other regions, you must call the NA_UnloadOtherTitleArchive function to unmount the current save data.
75 //
76 //
77 // This program accesses the backup region of the 'backup' demo. It provides examples of the following operations:
78 //
79 // 1. Loading files
80 // 2. Deleting backup data
81 // 3. Creating directory trees and files
82 //
83
84 // "dataPub" is the archive name of the backup data region copied to the SD card.
85 //
86 // This is used as general data.
87
88 // "dataPrv" is the archive name of the backup data region that is not copied to the SD card.
89 //
90 // This is used to save data you do not want copied.
91 {
92 u32 mode = 0;
93 const char code[5] = "4BNA";
94 DrawString("Target App Code = %s\n", code);
95 // To make the hardware reset valid, do not terminate
96 for (;;)
97 {
98 // Update the frame
99 DEMOReadKey();
100 if(DEMO_IS_TRIG(PAD_BUTTON_A))
101 {
102 DrawString("");
103 switch(mode)
104 {
105 case 0: // Execute loading of files
106 DrawString("Read\n");
107
108 MountOtherSaveData(code, TRUE);
109 ReadData("otherPub:");
110
111 MountOtherSaveData(code, FALSE);
112 ReadData("otherPrv:");
113 break;
114 case 1: // Execute delete
115 DrawString("Delete\n");
116
117 MountOtherSaveData(code, TRUE);
118 DeleteData("otherPub:");
119
120 MountOtherSaveData(code, FALSE);
121 DeleteData("otherPrv:");
122 break;
123 case 2: // Execute creation of directories and files
124 DrawString("Create\n");
125
126 MountOtherSaveData(code, TRUE);
127 CreateTree("otherPub:");
128
129 MountOtherSaveData(code, FALSE);
130 CreateTree("otherPrv:");
131 break;
132 }
133 mode = (mode + 1) % 3;
134 }else if(DEMO_IS_TRIG(PAD_BUTTON_B))
135 {
136 // Display the directory tree
137 DrawString("");
138
139 DrawString("Tree\notherPub:\n");
140
141 MountOtherSaveData(code, TRUE);
142 PrintTree("otherPub:", 1);
143
144 DrawString("\notherPrv:\n");
145
146 MountOtherSaveData(code, FALSE);
147 PrintTree("otherPrv:", 1);
148 }
149 DEMO_DrawFlip();
150 OS_WaitVBlankIntr();
151 }
152 }
153 }
154
155
156 /*---------------------------------------------------------------------------*
157 Name: LoadFile
158
159 Description: Internally allocates memory and loads a file.
160
161 Arguments: path: Path of the file to load
162
163 Returns: If the file exists, returns a pointer to the internally allocated buffer into which the file content was loaded.
164
165 This pointer must be deallocated with the FS_Free function.
166 *---------------------------------------------------------------------------*/
LoadFile(const char * path)167 static char* LoadFile(const char* path)
168 {
169 FSFile f;
170 BOOL bSuccess;
171 char* pBuffer;
172 u32 fileSize;
173 s32 readSize;
174
175 FS_InitFile(&f);
176
177 bSuccess = FS_OpenFileEx(&f, path, FS_FILEMODE_R);
178 if( ! bSuccess )
179 {
180 return NULL;
181 }
182
183 fileSize = FS_GetFileLength(&f);
184 pBuffer = (char*)OS_Alloc(fileSize + 1);
185 SDK_POINTER_ASSERT(pBuffer);
186
187 readSize = FS_ReadFile(&f, pBuffer, (s32)fileSize);
188 SDK_ASSERT( readSize == fileSize );
189
190 bSuccess = FS_CloseFile(&f);
191 SDK_ASSERT( bSuccess );
192
193 pBuffer[fileSize] = '\0';
194 return pBuffer;
195 }
196
197 /*---------------------------------------------------------------------------*
198 Name: SaveFile
199
200 Description: Creates a file and writes data to it.
201 Associated directories are not created.
202
203 Arguments: path: Path of the file to create
204 pData: Data to be written
205 size: Total size of data to be written
206
207 Returns: If successful, TRUE.
208 *---------------------------------------------------------------------------*/
SaveFile(const char * path,void * pData,u32 size)209 static BOOL SaveFile(const char* path, void* pData, u32 size)
210 {
211 FSFile f;
212 BOOL bSuccess;
213 FSResult fsResult;
214 s32 writtenSize;
215
216 FS_InitFile(&f);
217
218 (void)FS_CreateFile(path, (FS_PERMIT_R|FS_PERMIT_W));
219 bSuccess = FS_OpenFileEx(&f, path, FS_FILEMODE_W);
220 if (bSuccess == FALSE)
221 {
222 FSResult res = FS_GetArchiveResultCode(path);
223 DrawString("Failed create file:%d\n", res);
224 return FALSE;
225 }
226 SDK_ASSERT( bSuccess );
227
228 fsResult = FS_SetFileLength(&f, 0);
229 SDK_ASSERT( fsResult == FS_RESULT_SUCCESS );
230
231 writtenSize = FS_WriteFile(&f, pData, (s32)size);
232 SDK_ASSERT( writtenSize == size );
233
234 bSuccess = FS_CloseFile(&f);
235 SDK_ASSERT( bSuccess );
236 return TRUE;
237 }
238
239
240
241
242 /*---------------------------------------------------------------------------*
243 Name: CreateTree
244
245 Description: Creates a directory tree.
246
247 Arguments: arc_name: Target archive
248
249 Returns: None.
250 *---------------------------------------------------------------------------*/
CreateTree(const char * arc_name)251 static void CreateTree(const char* arc_name){
252 char *dir_path[] = {
253 "/",
254 "/testDir/",
255 "/testDir2/test/",
256 };
257 char *filename = "test";
258
259 u32 PATH_COUNT = 3;
260 u32 FILE_COUNT = 2;
261 char buf[BUF_SIZE];
262 BOOL bSuccess;
263
264
265 DrawString("Create:%s\n", arc_name);
266 // Generate directory
267 {
268 u32 i = 0, j = 0;
269 for(i = 1; i < PATH_COUNT; ++i)
270 {
271 (void)STD_TSNPrintf(buf, BUF_SIZE, "%s%s", arc_name, dir_path[i]);
272
273 bSuccess = FS_CreateDirectoryAuto(buf, FS_PERMIT_W | FS_PERMIT_R);
274 SDK_ASSERT(bSuccess);
275 DrawString(" %s\n", buf);
276 }
277 }
278
279 // Generate file
280 {
281 u32 i = 0, j = 0;
282 for(i = 0; i < PATH_COUNT; ++i)
283 {
284 for(j = 0; j < FILE_COUNT; ++j)
285 {
286 char data[BUF_SIZE];
287 (void)STD_TSNPrintf(buf, BUF_SIZE, "%s%s%s%d", arc_name, dir_path[i], filename, j);
288 (void)SaveFile(buf, GetTestData(data, BUF_SIZE), BUF_SIZE);
289 DrawString(" %s\n", buf);
290 }
291 }
292 }
293 DrawString("\n");
294 }
295
296
297 /*---------------------------------------------------------------------------*
298 Name: DeleteData
299
300 Description: Deletes all files and directories within a directory.
301
302 Arguments: path: Target directory path
303
304 Returns: None.
305 *---------------------------------------------------------------------------*/
DeleteData(char * path)306 static void DeleteData(char *path)
307 {
308 FSFile fp;
309 FSDirectoryEntryInfo entry;
310 char buf[BUF_SIZE];
311 BOOL bSuccess;
312 BOOL bDeleted = FALSE;
313 DrawString("Delete:%s\n", path);
314 FS_InitFile(&fp);
315 bSuccess = FS_OpenDirectory(&fp, path, FS_PERMIT_W | FS_PERMIT_R);
316 if(!bSuccess)
317 {
318 DrawString("Failed Open Directory\n");
319 return;
320 }
321
322 while(FS_ReadDirectory(&fp, &entry))
323 {
324 if(!STD_StrCmp(".", entry.longname) || !STD_StrCmp("..", entry.longname))
325 continue;
326
327 (void)STD_TSNPrintf(buf, BUF_SIZE, "%s/%s", path, entry.longname);
328 if(entry.attributes & FS_ATTRIBUTE_IS_DIRECTORY)
329 {
330 // For directories:
331 bSuccess = FS_DeleteDirectoryAuto(buf);
332 }
333 else
334 {
335 // For files:
336 bSuccess = FS_DeleteFile(buf);
337 }
338 if(!bSuccess)
339 {
340 DrawString("Failed Delete %s\n", buf);
341 continue;
342 }
343 else
344 {
345 DrawString(" %s\n", buf);
346 bDeleted = TRUE;
347 }
348 }
349 bSuccess = FS_CloseDirectory(&fp);
350 SDK_ASSERT(bSuccess);
351
352 if(!bDeleted)
353 {
354 DrawString("No File\n");
355 }
356
357 DrawString("\n");
358 }
359
360 /*---------------------------------------------------------------------------*
361 Name: GetTestData
362
363 Description: Creates data to write to test files.
364
365 Arguments: None.
366
367 Returns: None.
368 *---------------------------------------------------------------------------*/
GetTestData(char * out,u32 size)369 static char* GetTestData(char* out, u32 size)
370 {
371 RTCResult rtcResult;
372 RTCDate date;
373 RTCTime time;
374
375 // Generate content to write to a file
376 rtcResult = RTC_GetDateTime(&date, &time);
377 SDK_ASSERT( rtcResult == RTC_RESULT_SUCCESS );
378
379 (void)STD_TSNPrintf(out, size,
380 "Hello. %04d/%02d/%02d %02d:%02d:%02d\n",
381 date.year + 2000,
382 date.month,
383 date.day,
384 time.hour,
385 time.minute,
386 time.second );
387
388 return out;
389 }
390
391 /*---------------------------------------------------------------------------*
392 Name: ReadData
393
394 Description: Traverses within a directory and displays the content of the first found file.
395
396 Arguments: path: Target directory path
397
398 Returns: None.
399 *---------------------------------------------------------------------------*/
ReadData(const char * arc_name)400 static void ReadData(const char* arc_name)
401 {
402 FSFile fp;
403 FSDirectoryEntryInfo entry;
404
405 char buf[BUF_SIZE];
406 BOOL bSuccess;
407 BOOL bRead = FALSE;
408
409 DrawString("Read:%s\n", arc_name);
410 // Open directory
411 FS_InitFile(&fp);
412 bSuccess = FS_OpenDirectory(&fp, arc_name, FS_PERMIT_W | FS_PERMIT_R);
413 if(!bSuccess)
414 {
415 DrawString("Failed Open Directory");
416 return;
417 }
418
419 // Work within the directory and display content of first found file
420 while(FS_ReadDirectory(&fp, &entry))
421 {
422 if(!STD_StrCmp(".", entry.longname) || !STD_StrCmp("..", entry.longname))
423 continue;
424
425 (void)STD_TSNPrintf(buf, BUF_SIZE, "%s/%s", arc_name, entry.longname);
426 if(!(entry.attributes & FS_ATTRIBUTE_IS_DIRECTORY))
427 {
428 // For files:
429 char *data = NULL;
430 data = LoadFile(buf);
431 SDK_POINTER_ASSERT(buf);
432
433 DrawString("%s\n%s\n", buf, data);
434 OS_Free(data);
435 bRead = TRUE;
436 break;
437 }
438 }
439 bSuccess = FS_CloseDirectory(&fp);
440 SDK_ASSERT(bSuccess);
441 if(!bRead)
442 {
443 DrawString("No File\n");
444 }
445 DrawString("\n");
446 }
447
448 /*---------------------------------------------------------------------------*
449 Name: DrawString
450
451 Description: Renders using DEMODrawString.
452
453 Arguments: fmt: Based on DEMODrawString.
454 When fmt is " ", however, this function returns the cursor position to [0,0].
455
456 Returns: None.
457 *---------------------------------------------------------------------------*/
DrawString(const char * fmt,...)458 static void DrawString(const char* fmt, ...)
459 {
460 static s32 x = 0, y = 0;
461 char dst[256];
462 int ret;
463 va_list va;
464 va_start(va, fmt);
465 ret = OS_VSPrintf(dst, fmt, va);
466 va_end(va);
467
468 if(fmt[0] == '\0')
469 {
470 x = y = 0;
471 DEMOFillRect(0, 0, 256, 192, GX_RGBA(0, 0, 0, 1));
472 return;
473 }
474 DEMODrawText(x, y, dst);
475 {
476 s32 i, max = STD_StrLen(dst) - 1;
477 u32 cr = 0;
478 for(i = max; i >= 0; --i)
479 {
480 if(dst[i] == '\n')
481 {
482 x = (cr == 0) ? (max - i) * 8 : x;
483 cr++;
484 }
485 }
486 y += cr * 8;
487 }
488 }
489
490
491 /*---------------------------------------------------------------------------*
492 Name: PrintTree
493
494 Description: Displays a directory tree.
495
496 Arguments: path: Root path
497 space: For recursive calls. Normally 0 is specified.
498 Returns: None.
499 *---------------------------------------------------------------------------*/
PrintTree(const char * path,u32 space)500 static void PrintTree(const char* path, u32 space)
501 {
502 FSFile f;
503 FSDirectoryEntryInfo entry;
504 BOOL bSuccess;
505 char buf[BUF_SIZE];
506
507 FS_InitFile(&f);
508 bSuccess = FS_OpenDirectory(&f, path, FS_PERMIT_R);
509 if(!bSuccess)
510 return;
511
512 while( FS_ReadDirectory(&f, &entry) )
513 {
514 MI_CpuFill8(buf, ' ', space);
515 buf[space] = '\0';
516 // Skip entries indicative of self or parent.
517 if( (STD_StrCmp(entry.longname, ".") == 0)
518 || (STD_StrCmp(entry.longname, "..") == 0) )
519 {
520 continue;
521 }
522 if( (entry.attributes & FS_ATTRIBUTE_IS_DIRECTORY) != 0 )
523 {
524 // Directory
525 (void)STD_StrCat(buf, entry.longname);
526 DrawString("%s\n", buf);
527
528 // Combine paths and recursively call.
529 (void)STD_StrCpy(buf, path);
530 (void)STD_StrCat(buf, "/");
531 (void)STD_StrCat(buf, entry.longname);
532 PrintTree(buf, space + 1);
533 }
534 else
535 {
536 // Files
537 (void)STD_StrCat(buf, entry.longname);
538 DrawString("%s\n", buf);
539 }
540 }
541 bSuccess = FS_CloseDirectory(&f);
542 SDK_ASSERT( bSuccess );
543 }
544
545 /*---------------------------------------------------------------------------*
546 Name: PrintBootType
547
548 Description: Prints the BootType.
549
550 Arguments: None.
551
552 Returns: None.
553 *---------------------------------------------------------------------------*/
PrintBootType()554 static void PrintBootType()
555 {
556 const OSBootType btype = OS_GetBootType();
557
558 switch( btype )
559 {
560 case OS_BOOTTYPE_ROM: DrawString("OS_GetBootType = OS_BOOTTYPE_ROM\n"); break;
561 case OS_BOOTTYPE_NAND: DrawString("OS_GetBootType = OS_BOOTTYPE_NAND\n"); break;
562 default:
563 {
564 OS_Warning("unknown BootType(=%d)", btype);
565 }
566 break;
567 }
568 }
569
570 /*---------------------------------------------------------------------------*
571 Name: InitDEMOSystem
572
573 Description: Configures display settings for console screen output.
574
575 Arguments: None.
576
577 Returns: None.
578 *---------------------------------------------------------------------------*/
InitDEMOSystem()579 static void InitDEMOSystem()
580 {
581 // Initialize screen display
582 DEMOInitCommon();
583 DEMOInitVRAM();
584 DEMOInitDisplayBitmap();
585 DEMOHookConsole();
586 DEMOSetBitmapTextColor(GX_RGBA(31, 31, 31, 1));
587 DEMOSetBitmapGroundColor(DEMO_RGB_CLEAR);
588 DEMOStartDisplay();
589 }
590
591 /*---------------------------------------------------------------------------*
592 Name: InitInteruptSystem
593
594 Description: Initializes interrupts.
595
596 Arguments: None.
597
598 Returns: None.
599 *---------------------------------------------------------------------------*/
InitInteruptSystem()600 static void InitInteruptSystem()
601 {
602 // Enable master interrupt flag
603 (void)OS_EnableIrq();
604
605 // Allow IRQ interrupts
606 (void)OS_EnableInterrupts();
607 }
608
609 /*---------------------------------------------------------------------------*
610 Name: InitAllocSystem
611
612 Description: Creates a heap and makes OS_Alloc usable.
613
614 Arguments: None.
615
616 Returns: None.
617 *---------------------------------------------------------------------------*/
InitAllocSystem()618 static void InitAllocSystem()
619 {
620 void* newArenaLo;
621 OSHeapHandle hHeap;
622
623 // Initialize the main arena's allocation system
624 newArenaLo = OS_InitAlloc(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi(), 1);
625 OS_SetMainArenaLo(newArenaLo);
626
627 // Create a heap in the main arena
628 hHeap = OS_CreateHeap(OS_ARENA_MAIN, OS_GetMainArenaLo(), OS_GetMainArenaHi());
629 (void)OS_SetCurrentHeap(OS_ARENA_MAIN, hHeap);
630 }
631
632 /*---------------------------------------------------------------------------*
633 Name: InitFileSystem
634
635 Description: Initializes the file system.
636 The InitInteruptSystem function must have been called before this function is.
637
638
639 Arguments: None.
640
641 Returns: None.
642 *---------------------------------------------------------------------------*/
InitFileSystem()643 static void InitFileSystem()
644 {
645 // Initialize file system
646 FS_Init( FS_DMA_NOT_USE );
647 }
648
649 /*---------------------------------------------------------------------------*
650 Name: MountOtherSaveData
651
652 Description: Mounts the save data of another title.
653
654 Arguments: code: Target application's game code
655 flag: Mounts the Public save data when TRUE, mounts the Private save data when FALSE
656
657 Returns: None.
658 *---------------------------------------------------------------------------*/
MountOtherSaveData(const char * code,BOOL flag)659 static void MountOtherSaveData(const char* code, BOOL flag)
660 {
661 FSResult result;
662 result = NA_UnloadOtherTitleArchive();
663 SDK_ASSERT( result == FS_RESULT_SUCCESS || result == FS_RESULT_ALREADY_DONE );
664
665 result = NA_LoadOtherTitleArchive(code,
666 ((flag) ? NA_TITLE_ARCHIVE_DATAPUB : NA_TITLE_ARCHIVE_DATAPRV));
667 if(result != FS_RESULT_SUCCESS)
668 {
669 DrawString("Failed Mount %s\n", code);
670 }
671 }
672
673