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