1 /*---------------------------------------------------------------------------*
2   Project:  TwlSDK - demos - CARD - backup
3   File:     main.c
4 
5   Copyright 2007-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-11-27#$
14   $Rev: 9430 $
15   $Author: yosizaki $
16  *---------------------------------------------------------------------------*/
17 
18 
19 #include <nitro.h>
20 
21 #include "DEMO.h"
22 
23 
24 /*---------------------------------------------------------------------------*/
25 /* Variables */
26 
27 // ID for locking the CARD backup.
28 // This is used by CARD_LockBackup() and CARD_UnlockBackup() because use of the CARD hardware resources is mutually exclusive with the FS library and other functions.
29 //
30 static u16  card_lock_id;
31 
32 // The resulting value when a CARD access function has an error.
33 // The return value from CARD_GetResultCode() will be changed by functions such as CARD_UnlockBackup(): take note of this when access processing and error handling are separated.
34 //
35 static CARDResult last_result = CARD_RESULT_SUCCESS;
36 
37 // Flag that indicates whether a write-test has been run.
38 static BOOL is_test_run;
39 
40 
41 /*---------------------------------------------------------------------------*/
42 /* functions */
43 
44 /*---------------------------------------------------------------------------*
45   Name:         GetCardResultString
46 
47   Description:  Gets a string for a CARD function's return value.
48 
49   Arguments:    result: CARDResult result value
50 
51   Returns:      Pointer to a string that describes the result value.
52  *---------------------------------------------------------------------------*/
GetCardResultString(CARDResult result)53 static const char *GetCardResultString(CARDResult result)
54 {
55     switch (result)
56     {
57     case CARD_RESULT_SUCCESS:
58         return "success";
59     case CARD_RESULT_FAILURE:
60         return "failure";
61     case CARD_RESULT_INVALID_PARAM:
62         return "invalid param";
63     case CARD_RESULT_UNSUPPORTED:
64         return "unsupported";
65     case CARD_RESULT_TIMEOUT:
66         return "timeout";
67     case CARD_RESULT_CANCELED:
68         return "canceled";
69     case CARD_RESULT_NO_RESPONSE:
70         return "no response";
71     case CARD_RESULT_ERROR:
72         return "error";
73     default:
74         return "unknown error";
75     }
76 }
77 
78 /*---------------------------------------------------------------------------*
79   Name:         SelectDevice
80 
81   Description:  Device selection screen.
82 
83   Arguments:    None.
84 
85   Returns:      None.
86  *---------------------------------------------------------------------------*/
SelectDevice(void)87 static void SelectDevice(void)
88 {
89     /* *INDENT-OFF* */
90     static const struct
91     {
92         CARDBackupType type;
93         const char *comment;
94     }
95     types_table[] =
96     {
97         { CARD_BACKUP_TYPE_EEPROM_4KBITS,   "EEPROM    4 kb"},
98         { CARD_BACKUP_TYPE_EEPROM_64KBITS,  "EEPROM   64 kb"},
99         { CARD_BACKUP_TYPE_EEPROM_512KBITS, "EEPROM  512 kb"},
100         { CARD_BACKUP_TYPE_EEPROM_1MBITS,   "EEPROM    1 Mb"},
101         { CARD_BACKUP_TYPE_FLASH_2MBITS,    "FLASH     2 Mb"},
102         { CARD_BACKUP_TYPE_FLASH_4MBITS,    "FLASH     4 Mb"},
103         { CARD_BACKUP_TYPE_FLASH_8MBITS,    "FLASH     8 Mb"},
104         { CARD_BACKUP_TYPE_FLASH_16MBITS,   "FLASH    16 Mb"},
105         { CARD_BACKUP_TYPE_FLASH_64MBITS,   "FLASH    64 Mb"},
106     };
107     /* *INDENT-ON* */
108     enum
109     { types_table_max = sizeof(types_table) / sizeof(*types_table) };
110 
111     int     cur = 0;
112     BOOL    error = FALSE;
113     BOOL    end = FALSE;
114     int     i;
115 
116     while (!end)
117     {
118         DEMOReadKey();
119         // Move the cursor with the up and down buttons
120         if (DEMO_IS_TRIG(PAD_KEY_DOWN))
121         {
122             error = FALSE;
123             if (++cur >= types_table_max)
124             {
125                 cur -= types_table_max;
126             }
127         }
128         if (DEMO_IS_TRIG(PAD_KEY_UP))
129         {
130             error = FALSE;
131             if (--cur < 0)
132             {
133                 cur += types_table_max;
134             }
135         }
136 
137         // Set the currently selected device with the A Button.
138         // Set this correctly because the library cannot determine whether the specified device has actually been loaded.
139         //
140         if (DEMO_IS_TRIG(PAD_BUTTON_A))
141         {
142             CARD_LockBackup(card_lock_id);
143             end = CARD_IdentifyBackup(types_table[cur].type);
144             if (!end)
145             {
146                 error = TRUE;
147                 last_result = CARD_GetResultCode();
148             }
149             CARD_UnlockBackup(card_lock_id);
150         }
151 
152         // Displays screen
153         DEMOFillRect(0, 0, GX_LCD_SIZE_X, GX_LCD_SIZE_Y, DEMO_RGB_CLEAR);
154         DEMOSetBitmapTextColor(GX_RGBA(0, 31, 0, 1));
155         DEMODrawText(10, 40, "select device!");
156         for (i = 0; i < types_table_max; ++i)
157         {
158             DEMODrawText(10, 60 + 10 * i, "%c%s",
159                          (cur == i) ? '>' : ' ', types_table[i].comment);
160         }
161         if (error)
162         {
163             DEMOSetBitmapTextColor(GX_RGBA(31, 0, 0, 1));
164             DEMODrawText(10, 160, "error!");
165             DEMODrawText(10, 170, "result:\"%s\"", GetCardResultString(last_result));
166         }
167 
168         DEMO_DrawFlip();
169         OS_WaitVBlankIntr();
170     }
171 }
172 
173 /*---------------------------------------------------------------------------*
174   Name:         TestWriteAndVerify
175 
176   Description:  Write test screen.
177 
178   Arguments:    None.
179 
180   Returns:      None.
181  *---------------------------------------------------------------------------*/
TestWriteAndVerify(void)182 static void TestWriteAndVerify(void)
183 {
184     const u32   page_size = CARD_GetBackupPageSize();
185     const u32   sector_size = CARD_GetBackupSectorSize();
186     const u32   total_size = CARD_GetBackupTotalSize();
187 
188     OSTick      erase_time = 0;
189     u32         pos = 0;
190 
191     BOOL        end = FALSE;
192 
193     // Initialize the screen
194     {
195         DEMOFillRect(0, 0, GX_LCD_SIZE_X, GX_LCD_SIZE_Y, DEMO_RGB_CLEAR);
196         DEMOSetBitmapTextColor(GX_RGBA(31, 31, 31, 1));
197         if (CARD_IsBackupEeprom())
198         {
199             DEMODrawText(10, 10, "EEPROM");
200         }
201         else if (CARD_IsBackupFlash())
202         {
203             DEMODrawText(10, 10, "FLASH");
204         }
205         DEMODrawText(10, 20, "page:%d  sector:%d", page_size, sector_size);
206         DEMODrawText(10, 30, "total:%d", total_size);
207         DEMOFillRect(10, 50, GX_LCD_SIZE_X - 10 * 2, 100, GX_RGBA(0, 0, 0, 1));
208         DEMODrawFrame(8, 45, GX_LCD_SIZE_X - 8 * 2, 182 - 8 - 45, GX_RGBA(0, 0, 31, 1));
209         DEMO_DrawFlip();
210         OS_WaitVBlankIntr();
211     }
212 
213     while (!end)
214     {
215         DEMOReadKey();
216         // Start with the A Button if nothing has started yet
217         if (!is_test_run)
218         {
219             if (DEMO_IS_TRIG(PAD_BUTTON_A))
220             {
221                 is_test_run = TRUE;
222             }
223         }
224         //Stop test with B Button
225         else if (DEMO_IS_TRIG(PAD_BUTTON_B))
226         {
227             end = TRUE;
228         }
229 
230         // Perform a test write and onscreen display
231         if (!is_test_run)
232         {
233             DEMOSetBitmapTextColor(GX_RGBA(31, 31, 31, 1));
234             DEMODrawText(10, 50, "press A-BUTTON to test");
235         }
236         else
237         {
238             static u8 tmp_buf[65536];
239             SDK_ASSERT(sizeof(tmp_buf) >= sector_size);
240 
241             DEMOFillRect(10, 50, 256 - 10 * 2, 100, GX_RGBA(0, 0, 0, 1));
242             DEMOSetBitmapTextColor(GX_RGBA(0, 31, 0, 1));
243             DEMODrawText(10, 50, "now testing...");
244             DEMODrawText(10, 60, "address:%d-%d", pos, pos + page_size);
245 
246             // Lock CARD resources for subsequent backup accesses.
247             // This blocks card access from the FS library and other modules until CARD_UnlockBackup() is called.
248             // Be careful about process deadlocks.
249             //
250             CARD_LockBackup(card_lock_id);
251             {
252                 OSTick  tick;
253                 int     i;
254                 for (i = 0; i < page_size; ++i)
255                 {
256                     tmp_buf[i] = (u8)(pos * 3 + i);
257                 }
258                 tick = OS_GetTick();
259                 // Write asynchronously + verify content check
260                 if (CARD_IsBackupEeprom())
261                 {
262                     CARD_WriteAndVerifyEepromAsync(pos, tmp_buf, page_size, NULL, NULL);
263                 }
264                 else if (CARD_IsBackupFlash())
265                 {
266                     // Write operations can be used on nearly all flash devices
267                     if (CARD_GetCurrentBackupType() != CARD_BACKUP_TYPE_FLASH_64MBITS)
268                     {
269                         CARD_WriteAndVerifyFlashAsync(pos, tmp_buf, page_size, NULL, NULL);
270                     }
271                     // With some large-capacity FLASH devices, only EraseSector operations and Program operations can be used.
272                     // Note that you must be cautious of the fact that erase operations can be carried out only in integer units of the sector size.
273                     else
274                     {
275                         BOOL    programmable = FALSE;
276                         if ((pos % sector_size) == 0)
277                         {
278                             // Each and every sector of the area that will now be written must be erased beforehand.
279                             // This sample demo replaces the contents of an entire sector. If you want to replace only part of a sector, you must first back up the sector's data, erase the sector, and then rewrite the same data.
280                             //
281                             //
282                             erase_time = tick;
283                             programmable = CARD_EraseFlashSector(pos, sector_size);
284                             tick = OS_GetTick();
285                             erase_time = tick - erase_time;
286                             last_result = CARD_GetResultCode();
287                         }
288                         else
289                         {
290                             // Areas which have already been erased may be written as-is.
291                             programmable = TRUE;
292                         }
293                         if (programmable)
294                         {
295                             CARD_ProgramAndVerifyFlashAsync(pos, tmp_buf, page_size, NULL, NULL);
296                         }
297                     }
298                 }
299 
300                 // This sample waits here for processing to complete and then checks the result.
301                 // Because some device types and specified sizes may cause this to block for a very long time, figure out how to wait in a way that is suited to the various user application frameworks.
302                 // (For example, use CARD_TryWaitBackupAsync() to check only once per frame.)
303                 //
304                 (void)CARD_WaitBackupAsync();
305                 last_result = CARD_GetResultCode();
306                 if (last_result != CARD_RESULT_SUCCESS)
307                 {
308                     // If there is an error, end for now
309                     end = TRUE;
310                 }
311                 else
312                 {
313                     // Display the time if successful
314                     tick = OS_GetTick() - tick;
315                     DEMODrawText(10, 70, "write:%6d[ms]/%d[BYTE]", (int)OS_TicksToMilliSeconds(tick), page_size);
316                     if (erase_time != 0)
317                     {
318                         DEMODrawText(10, 80, "erase:%6d[ms]/%d[BYTE]", (int)OS_TicksToMilliSeconds(erase_time), sector_size);
319                     }
320                     // Move the test address to the next address
321                     pos += page_size;
322                     if (pos + page_size > total_size)
323                     {
324                         end = TRUE;
325                     }
326                 }
327             }
328             CARD_UnlockBackup(card_lock_id);
329         }
330 
331         DEMO_DrawFlip();
332         OS_WaitVBlankIntr();
333     }
334 }
335 
336 /*---------------------------------------------------------------------------*
337   Name:         ShowResult
338 
339   Description:  Test results display screen.
340 
341   Arguments:    None.
342 
343   Returns:      None.
344  *---------------------------------------------------------------------------*/
ShowResult(void)345 static void ShowResult(void)
346 {
347     BOOL    end = FALSE;
348 
349     while (!end)
350     {
351         DEMOReadKey();
352         // Go back with A / B / START Buttons
353         if (DEMO_IS_TRIG(PAD_BUTTON_A | PAD_BUTTON_B | PAD_BUTTON_START))
354         {
355             end = TRUE;
356         }
357 
358         // Displays screen
359         if (last_result == CARD_RESULT_SUCCESS)
360         {
361             DEMOSetBitmapTextColor(GX_RGBA(31, 31, 31, 1));
362             DEMODrawText(10, 100, "done! (success)");
363         }
364         else
365         {
366             DEMOSetBitmapTextColor(GX_RGBA(0, 31, 0, 1));
367             DEMODrawText(10, 100, "error!");
368             DEMODrawText(10, 110, "result:\"%s\"", GetCardResultString(last_result));
369         }
370         DEMO_DrawFlip();
371         OS_WaitVBlankIntr();
372     }
373 }
374 
375 /*---------------------------------------------------------------------------*
376   Name:         NitroMain
377 
378   Description:  Main entry point.
379 
380   Arguments:    None.
381 
382   Returns:      None.
383  *---------------------------------------------------------------------------*/
NitroMain(void)384 void NitroMain(void)
385 {
386     // Initialize the SDK
387     OS_Init();
388     OS_InitTick();
389     (void)OS_EnableIrq();
390     (void)OS_EnableInterrupts();
391 
392     // Initialize the display for the demo
393     DEMOInitCommon();
394     DEMOInitVRAM();
395     DEMOInitDisplayBitmap();
396     DEMOHookConsole();
397     DEMOSetBitmapTextColor(GX_RGBA(31, 31, 0, 1));
398     DEMOSetBitmapGroundColor(DEMO_RGB_CLEAR);
399     DEMOStartDisplay();
400 
401     // When accessing a ROM or backup from a non-card application, you must determine that the inserted DS Card is a title from the same company and then explicitly call the CARD_Enable function to enable it.
402     // See the Programming Guidelines for details.
403     //
404     //
405     if (OS_GetBootType() != OS_BOOTTYPE_ROM)
406     {
407         const CARDRomHeader *own_header = (const CARDRomHeader *)HW_ROM_HEADER_BUF;
408         const CARDRomHeader *rom_header = (const CARDRomHeader *)CARD_GetRomHeader();
409         if (own_header->maker_code != rom_header->maker_code)
410         {
411             // The purpose of this sample is accessing backup devices, so it will stop here if a DS Card has not been inserted
412             //
413             static const char *message = "cannot detect own-maker title DS-CARD!";
414             DEMOFillRect(0, 0, GX_LCD_SIZE_X, GX_LCD_SIZE_Y, DEMO_RGB_CLEAR);
415             DEMOSetBitmapTextColor(GX_RGBA(31, 0, 0, 1));
416             DEMODrawText(10, 40, message);
417             DEMO_DrawFlip();
418             OS_WaitVBlankIntr();
419             OS_TPanic(message);
420         }
421         else
422         {
423             CARD_Enable(TRUE);
424         }
425     }
426 
427     {
428         // Secures an ID for locking the CARD library's data bus
429         s32     ret = OS_GetLockID();
430         if (ret == OS_LOCK_ID_ERROR)
431         {
432             OS_TPanic("demo fatal error! OS_GetLockID() failed");
433         }
434         card_lock_id = (u16)ret;
435     }
436 
437     // Screen transition
438     for (;;)
439     {
440         // Device selection screen
441         SelectDevice();
442         // Test start
443         is_test_run = FALSE;
444         TestWriteAndVerify();
445         // Display results
446         if (is_test_run)
447         {
448             ShowResult();
449         }
450     }
451 
452 }
453