1 /*---------------------------------------------------------------------------*
2   Project:  RevolutionDWC Demos
3   File:     ./common/src/main.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  *---------------------------------------------------------------------------*/
14 /**
15  *
16  *
17  * Brief comment:    Common code for demos
18  *
19  * This is common code used by the demos.
20  *
21  * -Main entry point
22  * -Establishment of network connection
23  * -Console output
24  * -Initialization and termination of RVLDWC
25  * -NAND read/write
26  * -Pad input
27  * -Sleep/Halt/V-Blank waiting
28  *
29  */
30 
31 #include <demo.h>
32 #include "include/common.h"
33 #include <revolution/so.h>
34 #include "include/d_net_connect.h"
35 
36 #define CONSOLE_ROWS    22
37 #define CONSOLE_COLS    40
38 #define CONSOLEBUF_SIZE (CONSOLE_ROWS * CONSOLE_COLS)
39 
40 void FreeFunc( DWCAllocType name, void* ptr,  u32 size  );
41 void* AllocFunc( DWCAllocType name, u32   size, int align );
42 
43 const GXColor Bkcolor =
44     {
45         0, 0, 64, 0
46     };
47 char	s_consolebuf[CONSOLEBUF_SIZE];
48 u16		s_cursor = 0;
49 
50 char	s_console_fixedrow_buf[CONSOLE_COLS+1];
51 
52 static OSFontHeader* FontData;
53 
54 static MEMHeapHandle    s_hmem2heap;
55 static OSMutex          s_mutex;
56 
57 /*---------------------------------------------------------------------------*
58   Check for inclusion in the Shift-JIS range
59  *---------------------------------------------------------------------------*/
IsShiftJISRange(unsigned char c)60 static BOOL IsShiftJISRange(unsigned char c)
61 {
62     return (c >= 0x81 && c <=0x9f) || (c >= 0xe0 && c <= 0xfc);
63 }
64 
65 /*---------------------------------------------------------------------------*
66   Renders a character
67  *---------------------------------------------------------------------------*/
DrawCell(int x,int y,int xChar,int yChar)68 static void DrawCell(int x, int y, int xChar, int yChar)
69 {
70     s16 posLeft   = (s16) x;
71     s16 posRight  = (s16) (posLeft + FontData->cellWidth);
72     s16 posTop    = (s16) y;
73     s16 posBottom = (s16) (posTop  + FontData->cellHeight);
74 
75     s16 texLeft   = (s16) xChar;
76     s16 texRight  = (s16) (xChar + FontData->cellWidth);
77     s16 texTop    = (s16) yChar;
78     s16 texBottom = (s16) (yChar + FontData->cellHeight);
79 
80     GXBegin(GX_QUADS, GX_VTXFMT0, 4);
81     GXPosition3s16(posLeft , posTop   , 0);
82     GXTexCoord2s16(texLeft , texTop);
83 
84     GXPosition3s16(posRight, posTop   , 0);
85     GXTexCoord2s16(texRight, texTop);
86 
87     GXPosition3s16(posRight, posBottom, 0);
88     GXTexCoord2s16(texRight, texBottom);
89 
90     GXPosition3s16(posLeft , posBottom, 0);
91     GXTexCoord2s16(texLeft , texBottom);
92     GXEnd();
93 }
94 
95 /*---------------------------------------------------------------------------*
96   Loads the font
97  *---------------------------------------------------------------------------*/
LoadSheet(void * image)98 static void LoadSheet(void* image)
99 {
100     Mtx      mtx;
101     GXTexObj texObj;
102 
103     // Set up and load texture object
104     GXInitTexObj(&texObj,                           // obj
105                  image,                             // image_ptr
106                  FontData->sheetWidth,              // weight
107                  FontData->sheetHeight,             // height
108                  (GXTexFmt) FontData->sheetFormat,  // format
109                  GX_CLAMP,                          // wrap_s (don't care)
110                  GX_CLAMP,                          // wrap_t (don't care)
111                  GX_FALSE);                         // mipmap (don't care)
112 
113     GXInitTexObjLOD(&texObj,
114                     GX_LINEAR,     // min_filt
115                     GX_LINEAR,     // max_filt
116                     0.0f,          // min_lod     (don't care)
117                     0.0f,          // max_lod     (don't care)
118                     0.0f,          // lod_bias    (don't care)
119                     GX_DISABLE,    // bias_clamp  (don't care)
120                     GX_FALSE,      // do_edge_lod (don't care)
121                     GX_ANISO_1);   // max_aniso   (don't care)
122 
123     GXLoadTexObj(&texObj, GX_TEXMAP0);
124     MTXScale(mtx, 1.0f / FontData->sheetWidth,
125              1.0f / FontData->sheetHeight,
126              1.0f);
127     GXLoadTexMtxImm(mtx, GX_TEXMTX0, GX_MTX2x4);
128     GXSetNumTexGens(1);
129     GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, GX_TEXMTX0);
130 }
131 
132 /*---------------------------------------------------------------------------*
133   Renders a character
134  *---------------------------------------------------------------------------*/
DrawChar(int x,int y,u16 code)135 static s32 DrawChar(int x, int y, u16 code)
136 {
137     char  buffer[3];
138     s32   width;
139     void* image;
140     s32   xChar;
141     s32   yChar;
142 
143     if (code == 0)
144     {
145         return 0;
146     }
147 
148     if (code < 256)
149     {
150         buffer[0] = (char) code;
151         buffer[1] = '\0';
152     }
153     else
154     {
155         buffer[0] = (char) (code >> 8);
156         buffer[1] = (char) (code & 0xff);
157         buffer[2] = '\0';
158     }
159 
160     OSGetFontTexture(buffer, &image, &xChar, &yChar, &width);
161     LoadSheet(image);
162     DrawCell(x, y, xChar, yChar);
163 
164     return width;
165 }
166 
167 /*---------------------------------------------------------------------------*
168   Renders a string
169  *---------------------------------------------------------------------------*/
DrawString(int x,int y,const char * string)170 static s32 DrawString(int x, int y, const char* string)
171 {
172     s32 cx = 0;
173     int counter = 0;
174 
175     while (*string)
176     {
177         void* image;
178         s32   xChar;
179         s32   yChar;
180         s32   width;
181 
182         if ( (*string == '\n') || (*string == '\0') )
183             break;
184 
185         // Multibyte (Shift_JIS) check
186         if (IsShiftJISRange((unsigned char)*string))
187         {
188             counter += 2;
189         }
190         else
191         {
192             counter++;
193         }
194 
195         if ( counter > CONSOLE_COLS )
196             break;
197 
198         string = OSGetFontTexture(string, &image, &xChar, &yChar, &width);
199         LoadSheet(image);
200         DrawCell(x + cx, y, xChar, yChar);
201         cx += width;
202     }
203 
204     return cx;
205 }
206 
207 /*---------------------------------------------------------------------------*
208   Initializes the console output
209  *---------------------------------------------------------------------------*/
ConsoleInit()210 static void ConsoleInit()
211 {
212 
213     Mtx44  projection;
214     Mtx    modelview;
215     GXRenderModeObj* rmp;
216     u16    top = 0x00;
217 
218     if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS)
219     {
220         FontData = OSAlloc(OS_FONT_SIZE_SJIS);
221     }
222     else
223     {
224         FontData = OSAlloc(OS_FONT_SIZE_ANSI);
225     }
226 
227     OSInitFont(FontData);
228 
229     // Clear EFB
230     GXSetCopyClear(Bkcolor, 0x00ffffff);
231     GXCopyDisp(DEMOGetCurrentBuffer(), GX_TRUE);
232 
233     // Set matrices up to screen coordinates system
234     rmp = DEMOGetRenderModeObj();
235     MTXOrtho(projection, 0.0f, (f32) rmp->efbHeight, 0.0f, (f32) rmp->fbWidth, 0.0f, -100.0f);
236     GXSetProjection(projection, GX_ORTHOGRAPHIC);
237     MTXIdentity(modelview);
238     GXLoadPosMtxImm(modelview, GX_PNMTX0);
239     GXSetCurrentMtx(GX_PNMTX0);
240 
241     // Set pixel processing mode
242     GXSetZMode(GX_ENABLE, GX_ALWAYS, GX_ENABLE);
243 
244     // Set TEV parameters to "REPLACE COLOR"
245     GXSetNumChans(0);
246     GXSetNumTevStages(1);
247     GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE);
248     GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL);
249 
250     // Translucent mode
251     GXSetBlendMode(GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR);
252 
253     // Set up vertex descriptors
254     GXClearVtxDesc();
255     GXSetVtxDesc(GX_VA_POS,  GX_DIRECT);
256     GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT);
257     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS,  GX_POS_XYZ, GX_S16, 0);
258     GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST,  GX_S16, 0);
259 
260     s_console_fixedrow_buf[0] = '\0';
261 }
262 
263 /*---------------------------------------------------------------------------*
264   Updates the console
265  *---------------------------------------------------------------------------*/
ConsoleFlush()266 static void	ConsoleFlush()
267 {
268 
269     u8 i;
270 
271     for (i=0; i<CONSOLE_ROWS; i++)
272         DrawString( 0, i*19, &s_consolebuf[i*CONSOLE_COLS] );
273 
274     // Display additional information at the very bottom
275     DrawString( 0, i*19, s_console_fixedrow_buf );
276 }
277 
278 /*---------------------------------------------------------------------------*
279   Outputs a string to the console
280  *---------------------------------------------------------------------------*/
ConsolePut(char * text)281 static void	ConsolePut(char* text)
282 {
283 
284     int i;
285 
286     while (*text != '\0')
287     {
288 
289         switch (*text)
290         {
291 
292             // Move the cursor to the next line when there is a newline character
293         case '\n':
294             s_consolebuf[s_cursor] = '\0';
295             s_cursor += CONSOLE_COLS;
296             s_cursor -= s_cursor % CONSOLE_COLS;
297             text++;
298             break;
299 
300             // Write a normal character
301         default:
302         {
303             if (IsShiftJISRange((unsigned char)*(text)))
304             {
305                 if (s_cursor % CONSOLE_COLS == CONSOLE_COLS-1)
306                 {
307                     s_consolebuf[s_cursor++] = ' ';         // Fill with blank because there is only one character's worth free
308                 }
309                 else
310                 {
311                     s_consolebuf[s_cursor++] = *(text++);   // Write two characters
312                     s_consolebuf[s_cursor++] = *(text++);
313                 }
314             }
315             else
316             {
317                 s_consolebuf[s_cursor++] = *(text++);
318             }
319         }
320         }
321 
322         // Shift everything once we arrive at the end of the buffer
323         if (s_cursor >= CONSOLEBUF_SIZE)
324         {
325 
326             s_cursor -= CONSOLE_COLS;
327 
328             for (i=0; i<CONSOLEBUF_SIZE-CONSOLE_COLS; i++)
329             {
330                 s_consolebuf[i] = s_consolebuf[i+CONSOLE_COLS];
331             }
332 
333             for (; i<CONSOLEBUF_SIZE; i++)
334             {
335                 s_consolebuf[i] = ' ';
336             }
337         }
338     }
339 }
340 
341 
342 /*---------------------------------------------------------------------------*
343   Memory allocation function for DWC
344  *---------------------------------------------------------------------------*/
AllocFunc(DWCAllocType name,u32 size,int align)345 void* AllocFunc( DWCAllocType name, u32   size, int align )
346 {
347     void* ptr = NULL;
348 
349     (void)name;
350     (void)align;
351 
352     OSLockMutex( &s_mutex );
353     ptr = MEMAllocFromExpHeapEx( s_hmem2heap, size, align );
354     OSUnlockMutex( &s_mutex );
355 
356     return ptr;
357 }
358 
359 /*---------------------------------------------------------------------------*
360   Memory deallocation function for DWC
361  *---------------------------------------------------------------------------*/
FreeFunc(DWCAllocType name,void * ptr,u32 size)362 void FreeFunc( DWCAllocType name, void* ptr,  u32 size  )
363 {
364     (void)name;
365     (void)size;
366 
367     // Make it possible to handle deallocation requests for unallocated areas (NULL pointers)
368     if ( ptr != NULL )
369     {
370         OSLockMutex( &s_mutex );
371         MEMFreeToExpHeap( s_hmem2heap, ptr );
372         OSUnlockMutex( &s_mutex );
373     }
374 }
375 
376 /*---------------------------------------------------------------------------*
377   main function
378  *---------------------------------------------------------------------------*/
379 
380 #define MAX_PARAMETER_NUM 24	// arbitrary
381 char* g_argv1 = NULL;
382 char* parameters[MAX_PARAMETER_NUM];	// Parameter set
383 u8 parameter_num = 0;					// Number of parameters
384 
main(int argc,char ** argv)385 int main(int argc, char** argv)
386 {
387     if (argc >= 2)
388     {
389         g_argv1 = argv[1];
390     }
391 
392     if (argc > 0)
393     {	// Set up arguments
394         int i;
395         if ((argc + 1) >= MAX_PARAMETER_NUM)
396         {
397             DWCDemoPrintf("*** too parameters!! (%d)\n", argc);
398             argc = MAX_PARAMETER_NUM;
399         }
400         for (i=0; i<(argc - 1); i++)
401         {
402             parameters[i] = argv[i + 1];
403             DWCDemoPrintf("parameters[%d]:%s\n", i, parameters[i]);
404         }
405         parameter_num = (u8)(argc - 1);
406     }
407 
408     // Demo library initialization
409     //
410     DEMOInit(NULL); // to init heap
411 
412     // Initialize the console screen
413     //
414     ConsoleInit();
415 
416     // Pad input initialization
417     //
418     DEMOPadInit();
419 
420     // Initialize NAND
421     //
422     NANDInit();
423 
424     // Set up the Mutex for the DWC memory allocator
425     //
426     OSInitMutex( &s_mutex );
427 
428     // Create an allocator to allocate from MEM2
429     //
430     s_hmem2heap = MEMCreateExpHeap( OSGetMEM2ArenaLo(),
431                                     (u32)OSGetMEM2ArenaHi() - (u32)OSGetMEM2ArenaLo() );
432 
433     OSSetMEM2ArenaLo( OSGetMEM2ArenaHi() );
434 
435     // Network connection
436     DWCDemoPrintf( "Connecting to the network...\n" );
437     DWCDemoUpdate();
438     if ( dNetConnect_Start() == FALSE )
439     {
440         DWCDemoPrintf( "Failed to conect to the network\n" );
441         OSHalt("");
442     }
443 
444     // Initialize DWC
445     //
446     DWCDemoPrintf( "DWC_Init()\n" );
447     DWCDemoUpdate();
448     DWC_Init( DWC_AUTHSERVER_DEBUG, GAME_NAME, INITIAL_CODE, AllocFunc, FreeFunc );
449 
450     // Set DWC's debug output level
451     //
452     DWC_SetReportLevel( DWC_REPORTFLAG_ALL );
453 
454     // Start of DemoMain
455     //
456     DWCDemoPrintf( "DWCDemoMain start!!\n" );
457     DWCDemoUpdate();
458     DWCDemoMain();
459 
460     // Shutdown of DWC
461     //
462     DWC_Shutdown();
463 
464     // Network disconnection
465     DWCDemoPrintf("dNetConnect_Finish\n");
466     dNetConnect_Finish();
467 
468     DWCDemoUpdate();
469 
470     // Quit
471     OSHalt( "exit" );
472 
473     return 0;
474 }
475 
476 /*---------------------------------------------------------------------------*
477   Get key input
478  *---------------------------------------------------------------------------*/
DWCDemoPadRead()479 u32 DWCDemoPadRead()
480 {
481 
482     u32 keyflag = 0;
483     u16 tmp = 0;
484 
485     // Load pad information
486     DEMOPadRead();
487 
488     // Read information from all four pads
489     tmp = DEMOPadGetButtonDown( 0 );
490     tmp |= DEMOPadGetButtonDown( 1 );
491     tmp |= DEMOPadGetButtonDown( 2 );
492     tmp |= DEMOPadGetButtonDown( 3 );
493 
494     // Apply the latest samples
495     if ( tmp & PAD_BUTTON_UP )
496         keyflag |= DWCDEMO_KEY_UP;
497     if ( tmp & PAD_BUTTON_DOWN )
498         keyflag |= DWCDEMO_KEY_DOWN;
499     if ( tmp & PAD_BUTTON_LEFT )
500         keyflag |= DWCDEMO_KEY_LEFT;
501     if ( tmp & PAD_BUTTON_RIGHT )
502         keyflag |= DWCDEMO_KEY_RIGHT;
503     if ( tmp & PAD_BUTTON_A )
504         keyflag |= DWCDEMO_KEY_A;
505     if ( tmp & PAD_BUTTON_B )
506         keyflag |= DWCDEMO_KEY_B;
507     if ( tmp & PAD_BUTTON_X )
508         keyflag |= DWCDEMO_KEY_X;
509     if ( tmp & PAD_BUTTON_Y )
510         keyflag |= DWCDEMO_KEY_Y;
511 
512     if ( tmp & PAD_TRIGGER_L )
513         keyflag |= DWCDEMO_KEY_L;
514     if ( tmp & PAD_TRIGGER_R )
515         keyflag |= DWCDEMO_KEY_R;
516 
517     if ( tmp & PAD_TRIGGER_Z )
518         keyflag |= DWCDEMO_KEY_Z;
519     if ( tmp & PAD_BUTTON_START )
520         keyflag |= DWCDEMO_KEY_START;
521 
522     return keyflag;
523 
524 }
525 
526 /*---------------------------------------------------------------------------*
527   Sleep
528  *---------------------------------------------------------------------------*/
DWCDemoSleep(u32 millisec)529 void DWCDemoSleep(u32 millisec)
530 {
531 
532     OSSleepMilliseconds( millisec );
533 
534 }
535 
536 /*---------------------------------------------------------------------------*
537   Console output
538  *---------------------------------------------------------------------------*/
DWCDemoPrintf(const char * format,...)539 void DWCDemoPrintf(const char* format, ... )
540 {
541 
542     char buf[1024];
543     va_list vlist;
544 
545     OSLockMutex( &s_mutex );
546 
547     va_start(vlist, format);
548     (void)vsnprintf(buf, sizeof(buf), format, vlist);
549     va_end(vlist);
550 
551     // Debugging output
552     printf( buf );
553 
554     // Screen output
555     ConsolePut( buf );
556 
557     OSUnlockMutex( &s_mutex );
558 }
559 
560 /*---------------------------------------------------------------------------*
561   Output to the console's bottom-most fixed row.
562   This will be applied at the next ConsoleFlush.
563  *---------------------------------------------------------------------------*/
DWCDemoPrintfToFixedRow(const char * format,...)564 void DWCDemoPrintfToFixedRow(const char* format, ... )
565 {
566     va_list vlist;
567 
568     OSLockMutex( &s_mutex );
569 
570     va_start(vlist, format);
571     (void)vsnprintf(s_console_fixedrow_buf, sizeof(s_console_fixedrow_buf), format, vlist);
572     va_end(vlist);
573 
574     OSUnlockMutex( &s_mutex );
575 }
576 
577 /*---------------------------------------------------------------------------*
578   Screen update
579  *---------------------------------------------------------------------------*/
DWCDemoUpdate()580 void DWCDemoUpdate()
581 {
582 
583     // Flush
584     //
585     // One frame is consumed here
586     //
587     DEMOBeforeRender();
588 
589     ConsoleFlush();
590 
591     DEMODoneRender();
592 
593 }
594 
595 /*---------------------------------------------------------------------------*
596   Panic
597  *---------------------------------------------------------------------------*/
DWCDemoPanic(const char * msg)598 void DWCDemoPanic(const char* msg)
599 {
600 
601     OSHalt( msg );
602 
603 }
604 
605 /*---------------------------------------------------------------------------*
606   Load data from NAND
607  *---------------------------------------------------------------------------*/
DWCDemoLoadNAND(const char * filename,s32 seek,u8 * buf,u32 bufsize)608 void DWCDemoLoadNAND( const char* filename, s32 seek, u8* buf, u32 bufsize)
609 {
610 
611     NANDFileInfo info;
612     char homedir[NAND_MAX_PATH];
613     char path[NAND_MAX_PATH];
614 
615     // Must be 32-byte aligned.
616     ASSERT( (bufsize & 0x1f) == 0 );
617     ASSERT( (((u32)buf) & 0x1f) == 0 );
618 
619     DWCi_Np_CpuClear32( buf, bufsize );
620 
621     // Get the home directory
622     if ( NANDGetHomeDir( homedir ) != NAND_RESULT_OK )
623     {
624         // Failed
625         DWCDemoPrintf( "[error] Failed to get the home directory.\n" );
626         DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
627         return;
628     }
629 
630     // Open the file
631     snprintf( path, sizeof(path), "%s/nocopy/%s", homedir, filename );
632 
633     switch ( NANDOpen( path, &info, NAND_ACCESS_READ ) )
634     {
635 
636     case NAND_RESULT_OK:
637         break;
638 
639     case NAND_RESULT_NOEXISTS:
640 
641         DWCDemoPrintf( "Create new file.\n");
642 
643         // There is none, so make one
644         DWCDemoSaveNAND( filename, seek, buf, bufsize );
645 
646         return;
647 
648     default:
649         // File could not be opened
650         DWCDemoPanic("Couldn't open a file.");
651         break;
652 
653     }
654 
655     // Seek
656     NANDSeek( &info, seek, NAND_SEEK_SET );
657 
658     // Read
659     NANDRead( &info, (void*)buf, bufsize );
660 
661     // Close
662     NANDClose( &info );
663 
664 }
665 
666 /*---------------------------------------------------------------------------*
667   Save the data in NAND
668  *---------------------------------------------------------------------------*/
DWCDemoSaveNAND(const char * filename,s32 seek,u8 * buf,u32 bufsize)669 void DWCDemoSaveNAND( const char* filename, s32 seek, u8* buf, u32 bufsize)
670 {
671 
672     NANDFileInfo info;
673     char currentdir[NAND_MAX_PATH];
674     char homedir[NAND_MAX_PATH];
675     char path[NAND_MAX_PATH];
676 
677     // Must be 32-byte aligned.
678     ASSERT( (bufsize & 0x1f) == 0 );
679     ASSERT( (((u32)buf) & 0x1f) == 0 );
680 
681     // Save the current directory
682     if ( NANDGetCurrentDir( currentdir ) != NAND_RESULT_OK )
683     {
684         // Failed
685         DWCDemoPrintf( "[error] Failed to get the current directory.\n" );
686         DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
687         return;
688     }
689 
690     // Get the home directory
691     if ( NANDGetHomeDir( homedir ) != NAND_RESULT_OK )
692     {
693         // Failed
694         DWCDemoPrintf( "[error] Failed to get the home directory.\n" );
695         DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
696         return;
697     }
698 
699     // Create the nocopy directory
700     if ( NANDChangeDir( homedir ) != NAND_RESULT_OK )
701     {
702         // Failed
703         DWCDemoPrintf( "[error] Failed to move to the home directory.\n" );
704         DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
705         return;
706     }
707 
708     switch ( NANDChangeDir( "nocopy" ) )
709     {
710     case NAND_RESULT_OK:
711         break;
712 
713     case NAND_RESULT_NOEXISTS:
714         // There is none, so make one
715         if ( NANDCreateDir( "nocopy", NAND_PERM_OWNER_READ|NAND_PERM_OWNER_WRITE, 0 )
716                 != NAND_RESULT_OK )
717         {
718             // Failed
719             DWCDemoPrintf( "[error] Failed to create the nocopy directory.\n" );
720             DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
721             NANDChangeDir( currentdir );
722             return;
723         }
724 
725         break;
726 
727     case NAND_RESULT_ACCESS:
728     case NAND_RESULT_INVALID:
729     case NAND_RESULT_UNKNOWN:
730     case NAND_RESULT_FATAL_ERROR:
731         // Failed
732         DWCDemoPrintf( "[error] Failed to move to the \"nocopy\" directory.\n" );
733         DWCDemoPrintf( "[error] Couldn't load data from NAND.\n" );
734         NANDChangeDir( currentdir );
735         return;
736     }
737 
738     NANDChangeDir( currentdir );
739 
740     // Open the file
741     snprintf( path, sizeof(path), "%s/nocopy/%s", homedir, filename );
742 
743     switch ( NANDOpen( path, &info, NAND_ACCESS_WRITE ) )
744     {
745 
746     case NAND_RESULT_OK:
747         break;
748 
749     case NAND_RESULT_NOEXISTS:
750 
751         // There is none, so make one
752         NANDCreate( path, NAND_PERM_OWNER_READ|NAND_PERM_OWNER_WRITE, 0);
753 
754         if ( NANDOpen( path, &info, NAND_ACCESS_WRITE ) != NAND_RESULT_OK )
755         {
756             // File could not be opened
757             DWCDemoPanic("Couldn't open a file.");
758             return;
759         }
760 
761         break;
762 
763     default:
764         // File could not be opened
765         DWCDemoPanic("Couldn't open a file.");
766         break;
767 
768     }
769 
770     // Seek
771     NANDSeek( &info, seek, NAND_SEEK_SET );
772 
773     // Write
774     NANDWrite( &info, (void*)buf, bufsize );
775 
776     // Close
777     NANDClose( &info );
778 
779 }
780 
781 /*---------------------------------------------------------------------------*
782   Display friend status
783  *---------------------------------------------------------------------------*/
784 #ifndef DWC_NOGS
DWCDemoGetFriendStatusString(const DWCFriendData * param)785 const char* DWCDemoGetFriendStatusString(const DWCFriendData* param)
786 {
787     u8 status;
788 
789     if (param == NULL) return "IGNORED!!";
790     status = DWC_GetFriendStatusSC(param, NULL, NULL, NULL);
791     switch (status)
792     {
793     case DWC_STATUS_OFFLINE:
794         return "OFFLINE";
795     case DWC_STATUS_ONLINE:
796         return "ONLINE";
797     case DWC_STATUS_PLAYING:
798         return "PLAYING";
799     case DWC_STATUS_MATCH_ANYBODY:
800         return "ANYBODY";
801     case DWC_STATUS_MATCH_FRIEND:
802         return "FRIEND";
803     case DWC_STATUS_MATCH_SC_SV:
804         return "SERVER";
805     case DWC_STATUS_MATCH_SC_CL:
806         return "CLIENT";
807     }
808 
809     return "IGNORED!!";
810 }
811 #endif
812