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