1 /*---------------------------------------------------------------------------*
2 Project: Revolution DVD error handling demo
3 File: errorhandling.c
4
5 Copyright 2006 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 $Log: errorhandling.c,v $
14 Revision 1.5 07/28/2006 02:01:17 ooizumi
15 Disabled handling reset switch code.
16
17 Revision 1.4 06/10/2006 00:49:44 ooizumi
18 Disabled the default disc fatal screen.
19
20 Revision 1.3 02/28/2006 21:17:19 ooizumi
21 Removed audio streaming functions.
22 Modified several comments.
23
24 Revision 1.1 2006/01/17 02:43:50 hiratsu
25 Initial check in.
26
27
28 5 02/06/04 16:23 Hashida
29 Removed warnings.
30
31 4 02/02/18 17:20 Hashida
32 Added DVDGetCurrentDiskID.
33 Fixed a bug that the demo crashes when executing DVDChangeDisk twice.
34
35 3 1/03/02 5:48p Hashida
36 Added change disk.
37
38 2 6/16/01 5:50a Hashida
39 Changed so that error status and play address are shown only when it's
40 succeeded.
41
42 1 6/15/01 9:03p Hashida
43 Initial revision.
44
45 $NoKeywords: $
46 *---------------------------------------------------------------------------*/
47
48 /*---------------------------------------------------------------------------*
49 * This demo illustrates how to handle errors. See __refresh_status() for
50 * the actual error handling code!
51 *---------------------------------------------------------------------------*/
52
53 #include <demo.h>
54 #include <revolution.h>
55 #include <demo/DEMOWin.h>
56 #include <string.h>
57 #include <stdio.h>
58 #include "selectfile.h"
59
60 /*---------------------------------------------------------------------------*
61 * DVD definitions
62 *---------------------------------------------------------------------------*/
63 #define DVD_BUFFER_SIZE 0xf00000
64 static void* Buffer;
65
66 static DVDFileInfo FileInfo;
67 static volatile BOOL FileInfoIsInUse = FALSE;
68
69 static DVDDiskID DiskID;
70
71 /*---------------------------------------------------------------------------*
72 * Misc
73 *---------------------------------------------------------------------------*/
74 #define MIN(x, y) ((x) < (y)? (x):(y))
75
76
77 /*---------------------------------------------------------------------------*
78 * Data to pass from command issuing routines to status printing routine.
79 *---------------------------------------------------------------------------*/
80 enum{
81 COMMAND_READ,
82 COMMAND_SEEK,
83 COMMAND_GET_ERROR_STATUS,
84 COMMAND_CHANGE_DISK
85 };
86
87 typedef struct
88 {
89 u32 command;
90 s32 readLength;
91 } CommandBlockData;
92
93 static CommandBlockData Data;
94
95
96 /*---------------------------------------------------------------------------*
97 * Messages for errors
98 *---------------------------------------------------------------------------*/
99 typedef struct
100 {
101 char* line[6];
102 } Message;
103
104 // Error messages. XXX Caution: Subject to change.
105 Message ErrorMessages[] = {
106 {"Please insert the disc for xxx.", "", "", "", "", ""},
107 {"This disc is not for xxx.", "Please insert the disc for xxx.", "", "", "", ""},
108 {"The disc could not be read.", "", "Please read the NINTENDO REVOLUTION",
109 "Instruction Booklet for more information", "", ""},
110 {"An error has occurred.", "", "Turn the power OFF and check", "the NINTENDO REVOLUTION",
111 "Instruction Booklet for", "further instructions."},
112 {"Please insert the next disc.", "", "", "", "", ""},
113 };
114
115 enum{
116 MESSAGE_NO_DISK = 0,
117 MESSAGE_WRONG_DISK,
118 MESSAGE_RETRY_ERROR,
119 MESSAGE_FATAL_ERROR,
120 MESSAGE_CHANGE_DISK
121 };
122
123
124 /*---------------------------------------------------------------------------*
125 * Prototypes
126 *---------------------------------------------------------------------------*/
127 static void InitWindows(void);
128
129 static void __status_refresh(DEMOWinInfo *handle);
130
131 static void Run_Demo(void);
132
133 static void MNU_read(DEMOWinMenuInfo *menu, u32 item, u32 *result);
134 static void MNU_seek(DEMOWinMenuInfo *menu, u32 item, u32 *result);
135 static void MNU_cancel(DEMOWinMenuInfo *menu, u32 item, u32 *result);
136 static void MNU_change_disk(DEMOWinMenuInfo *menu, u32 item, u32 *result);
137 static void MNU_get_disk_id(DEMOWinMenuInfo *menu, u32 item, u32 *result);
138
139 static void MNU_pick_number(DEMOWinMenuInfo *menu, u32 item, u32 *result);
140
141 /*---------------------------------------------------------------------------*
142 * Main Control Menu Stuff!
143 *---------------------------------------------------------------------------*/
144 DEMOWinMenuItem control_menu_items[] =
145 {
146 { "ISSUE COMMAND", DEMOWIN_ITM_SEPARATOR, NULL, NULL },
147 { " DVDRead", DEMOWIN_ITM_NONE, MNU_read, NULL },
148 { " DVDSeek", DEMOWIN_ITM_NONE, MNU_seek, NULL },
149 { " DVDCancel", DEMOWIN_ITM_NONE, MNU_cancel, NULL },
150 { " DVDChangeDisk", DEMOWIN_ITM_NONE, MNU_change_disk, NULL },
151 { " DVDGetCurrentDiskID", DEMOWIN_ITM_NONE, MNU_get_disk_id, NULL },
152 { "", DEMOWIN_ITM_TERMINATOR, NULL, NULL }
153 };
154
155 DEMOWinMenuInfo control_menu =
156 {
157 "DVD Error Handling Demo", // title
158 NULL, // window handle
159 control_menu_items, // list of menu items
160 50, // max num of items to display at a time
161 DEMOWIN_MNU_NONE, // attribute flags?
162
163 // user callbacks for misc menu operations
164 NULL, NULL, NULL, NULL,
165 // private menu info members; do not touch
166 0, 0, 0, 0, 0
167 };
168 DEMOWinMenuInfo *control_menu_ptr;
169
170 DEMOWinMenuItem number_menu_items[] =
171 {
172 { "255", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
173 { "0", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
174 { "1", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
175 { "2", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
176 { "3", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
177 { "4", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
178 { "5", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
179 { "6", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
180 { "7", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
181 { "8", DEMOWIN_ITM_EOF, MNU_pick_number, NULL },
182 { "", DEMOWIN_ITM_TERMINATOR, NULL, NULL }
183 };
184 DEMOWinMenuInfo number_menu =
185 {
186 "Pick next disk number", // title
187 NULL, // window handle
188 number_menu_items, // list of menu items
189 10, // max num of items to display at a time
190 DEMOWIN_MNU_NONE, // attribute flags?
191
192 // user callbacks for misc menu operations
193 NULL, NULL, NULL, NULL,
194 // private menu info members; do not touch
195 0, 0, 0, 0, 0
196 };
197
198 /*---------------------------------------------------------------------------*
199 * Debug and Status window stuff!
200 *---------------------------------------------------------------------------*/
201 DEMOWinInfo *debug_win; // debug window
202 DEMOWinInfo *status_win; // status window
203 DEMOWinInfo *errmsg_win; // error message window
204
205
206 /*---------------------------------------------------------------------------*
207 Name: InitWindows
208
209 Description: Initialize windows
210
211 Arguments: none
212
213 Returns: none
214 *---------------------------------------------------------------------------*/
InitWindows(void)215 static void InitWindows(void)
216 {
217 DEMOWinInfo *p;
218
219 control_menu_ptr = DEMOWinCreateMenuWindow(&control_menu, 20, 20);
220 p = control_menu_ptr->handle;
221
222 // Initialize a window for showing status of DVD commands
223 // By passing "__status_refresh" as the last argument, the window system
224 // calls "__status_refresh" once every frame. We use this function to
225 // handle errors in this demo.
226 status_win = DEMOWinCreateWindow((u16)(p->x2+5), p->y1, 620, (u16)(p->y1+100),
227 "Status", 0, __status_refresh);
228
229 // Initialize a window for debug output
230 debug_win = DEMOWinCreateWindow((u16)(p->x2+5), (u16)(p->y1+105), 620, 434,
231 "Debug", 1024, NULL);
232
233 // Initialize a window for showing error message
234 errmsg_win = DEMOWinCreateWindow(120, 150, 520, 250,
235 "Error message", 0, NULL);
236
237 // Open status and debug windows. We don't open error message window until
238 // we hit an error.
239 DEMOWinOpenWindow(debug_win);
240 DEMOWinOpenWindow(status_win);
241
242 // Tell the pointer to the debug window to the "file select" system
243 InitSelectFile(debug_win);
244 }
245
246 /*---------------------------------------------------------------------------*
247 Name: __status_refresh
248
249 Description: This is the error handling part. This function is called
250 once every frame.
251
252 Arguments: handle Window handle for the status window
253
254 Returns: none
255 *---------------------------------------------------------------------------*/
__status_refresh(DEMOWinInfo * handle)256 static void __status_refresh(DEMOWinInfo *handle)
257 {
258 static u32 counter;
259 s32 message;
260 u32 i;
261 CommandBlockData *data;
262
263
264 // Clear status window (we only use the first two rows)
265 DEMOWinClearRow(handle, 0);
266 DEMOWinClearRow(handle, 1);
267
268 // We use "user data" as the information of the command that was issued
269 // last.
270 data = DVDGetUserData((DVDCommandBlock*)&FileInfo);
271
272 if (data)
273 {
274 // If it's a read command, show the progress
275 if (data->command == COMMAND_READ)
276 {
277 DEMOWinPrintfXY(handle, 0, 0, "Now loading....%3d%%(%d/%d)",
278 100*DVDGetTransferredSize(&FileInfo)/data->readLength,
279 DVDGetTransferredSize(&FileInfo), data->readLength);
280 }
281 }
282
283 message = -1;
284
285 // This part is for debugging purpose. Show the drive's status on status
286 // window.
287 switch(DVDGetDriveStatus())
288 {
289 case DVD_STATE_END:
290 FileInfoIsInUse = FALSE;
291 DEMOWinPrintfXY(handle, 0, 1, "Command finished");
292 break;
293 case DVD_STATE_FATAL_ERROR:
294 DEMOWinPrintfXY(handle, 0, 1, "Fatal error occurred");
295 message = MESSAGE_FATAL_ERROR;
296 break;
297 case DVD_STATE_BUSY:
298 break;
299 case DVD_STATE_NO_DISK:
300 DEMOWinPrintfXY(handle, 0, 1, "No disk");
301 message = MESSAGE_NO_DISK;
302 break;
303 case DVD_STATE_WRONG_DISK:
304 DEMOWinPrintfXY(handle, 0, 1, "Wrong disk");
305 message = MESSAGE_WRONG_DISK;
306 break;
307 case DVD_STATE_RETRY:
308 DEMOWinPrintfXY(handle, 0, 1, "Please retry");
309 message = MESSAGE_RETRY_ERROR;
310 break;
311 case DVD_STATE_MOTOR_STOPPED:
312 DEMOWinPrintfXY(handle, 0, 1, "Ready to replace");
313 message = MESSAGE_CHANGE_DISK;
314 break;
315 }
316
317 // If necessary, launch error message window to show the error message to
318 // the user.
319 if (message >= 0)
320 {
321 DEMOWinOpenWindow(errmsg_win);
322 counter = (counter+1) % 60;
323 for (i = 0; i < 6; i++)
324 {
325 if (counter < 45)
326 {
327 DEMOWinPrintfXY(errmsg_win, 0, (u16)i, ErrorMessages[message].line[i]);
328 }
329 else
330 {
331 DEMOWinClearRow(errmsg_win, (u16)i);
332 }
333 }
334 }
335 else
336 {
337 DEMOWinCloseWindow(errmsg_win);
338 }
339
340 #if 0
341 // temporary disabled until STM is implemented to firmware
342 if (OSGetResetSwitchState())
343 {
344 OSReport("reset is pressed\n");
345
346 while (OSGetResetSwitchState())
347 ;
348
349 OSReport("reset is released\n");
350
351 OSRestart(3);
352 }
353 #endif
354
355 } // end __status_refresh()
356
357
358 /*---------------------------------------------------------------------------*
359 Name: MNU_cancel
360
361 Description: Issue DVDCancel. This function is called when DVDCancel
362 is selected in the control window.
363
364 Arguments: menu, item, result unused
365
366 Returns: none
367 *---------------------------------------------------------------------------*/
MNU_cancel(DEMOWinMenuInfo * menu,u32 item,u32 * result)368 static void MNU_cancel(DEMOWinMenuInfo *menu, u32 item, u32 *result)
369 {
370 #pragma unused(menu, item, result)
371 DVDCancelAsync((DVDCommandBlock*)&FileInfo, NULL);
372 }
373
374
readCallback(s32 result,DVDFileInfo * fileInfo)375 static void readCallback(s32 result, DVDFileInfo* fileInfo)
376 {
377 #pragma unused(fileInfo)
378
379 if (result == DVD_RESULT_FATAL_ERROR)
380 return;
381
382 OSReport("read finished\n");
383 }
384
385 /*---------------------------------------------------------------------------*
386 Name: MNU_read
387
388 Description: Issue DVDRead, after letting the user to select a file
389 to read.
390
391 Arguments: menu Winmenuinfo for control window
392 item, result unused
393
394 Returns: none
395 *---------------------------------------------------------------------------*/
MNU_read(DEMOWinMenuInfo * menu,u32 item,u32 * result)396 static void MNU_read(DEMOWinMenuInfo *menu, u32 item, u32 *result)
397 {
398 #pragma unused(item)
399 #pragma unused(result)
400 s32 length;
401 char* file;
402
403 // Avoid using the same FileInfo/CommandBlock at the same time.
404 if (FileInfoIsInUse)
405 {
406 return;
407 }
408
409 DEMOWinLogPrintf(debug_win, "\nIssuing a read...\n");
410 DEMOWinLogPrintf(debug_win, "Press A to choose a file to read or change directory.\nPress B to exit.\n");
411
412 // Launch a window to let the user to select a file.
413 // The return value is the pointer to the selected file.
414 file = SelectFile(menu->handle);
415
416 DVDOpen(file, &FileInfo);
417 // If the size of the file is larger than the buffer size, we only read
418 // the first DVD_BUFFER_SIZE bytes.
419 length = (s32)OSRoundUp32B(MIN(DVDGetLength(&FileInfo), DVD_BUFFER_SIZE));
420
421 // Pass information to __status_refresh()
422 Data.command = COMMAND_READ;
423 Data.readLength = length;
424 DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)&Data);
425
426 FileInfoIsInUse = TRUE;
427 DVDReadAsync(&FileInfo, Buffer, length, 0, readCallback);
428
429 }
430
431 /*---------------------------------------------------------------------------*
432 Name: MNU_seek
433
434 Description: Issue DVDSeek, after letting the user to select a file
435 to seek to.
436
437 Arguments: menu Winmenuinfo for control window
438 item, result unused
439
440 Returns: none
441 *---------------------------------------------------------------------------*/
MNU_seek(DEMOWinMenuInfo * menu,u32 item,u32 * result)442 static void MNU_seek(DEMOWinMenuInfo *menu, u32 item, u32 *result)
443 {
444 #pragma unused(item)
445 #pragma unused(result)
446 char* file;
447
448 // Avoid using the same FileInfo/CommandBlock at the same time.
449 if (FileInfoIsInUse)
450 {
451 return;
452 }
453
454 DEMOWinLogPrintf(debug_win, "\nIssuing a seek...\n");
455 DEMOWinLogPrintf(debug_win, "Press A to choose a file to seek to or change directory.\nPress B to exit.\n");
456
457 // Launch a window to let the user to select a file.
458 // The return value is the pointer to the selected file.
459 file = SelectFile(menu->handle);
460
461 DVDOpen(file, &FileInfo);
462
463 // Pass information to __status_refresh()
464 Data.command = COMMAND_SEEK;
465 DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)&Data);
466
467 FileInfoIsInUse = TRUE;
468 DVDSeekAsync(&FileInfo, 0, NULL);
469
470 }
471
472
MNU_pick_number(DEMOWinMenuInfo * menu,u32 item,u32 * result)473 static void MNU_pick_number(DEMOWinMenuInfo *menu, u32 item, u32 *result)
474 {
475 #pragma unused (menu)
476 *result = (item == 0)? 0xff : item - 1;
477
478 } // end __select_file
479
480
PickNumber(DEMOWinInfo * handle)481 static u32 PickNumber(DEMOWinInfo *handle)
482 {
483 u32 val = 0;
484
485 DEMOWinSetWindowColor(handle, DEMOWIN_COLOR_CAPTION,
486 50, 50, 50, 255);
487
488 DEMOWinCreateMenuWindow(&number_menu, (u16)(handle->x2-10), (u16)(handle->y1+24));
489 val = DEMOWinMenu(&number_menu);
490 DEMOWinDestroyMenuWindow(&number_menu);
491
492 DEMOWinSetWindowColor(handle, DEMOWIN_COLOR_RESET, 0, 0, 0, 0);
493
494 return val;
495 }
496
497 /*---------------------------------------------------------------------------*
498 Name: MNU_change_disk
499
500 Description: Issue DVDChangeDisk
501
502 Arguments: menu Winmenuinfo for control window
503 item, result unused
504
505 Returns: none
506 *---------------------------------------------------------------------------*/
MNU_change_disk(DEMOWinMenuInfo * menu,u32 item,u32 * result)507 static void MNU_change_disk(DEMOWinMenuInfo *menu, u32 item, u32 *result)
508 {
509 #pragma unused(menu, item, result)
510 u32 n;
511
512 // Avoid using the same FileInfo/CommandBlock at the same time.
513 if (FileInfoIsInUse)
514 {
515 return;
516 }
517
518 // Pass information to __status_refresh()
519 Data.command = COMMAND_CHANGE_DISK;
520 DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)&Data);
521
522 n = PickNumber(menu->handle);
523
524 OSReport("number: %d\n", n);
525
526 memcpy(&DiskID, DVDGetCurrentDiskID(), sizeof(DVDDiskID));
527 DiskID.diskNumber = (u8)n; // BCD (0x00 ... 1st disk, 0x01 ... 2nd disk)
528
529 FileInfoIsInUse = TRUE;
530 DVDChangeDiskAsync((DVDCommandBlock*)&FileInfo, &DiskID, NULL);
531 }
532
changeDiskCallback(s32 result,DVDCommandBlock * commandBlock)533 static void changeDiskCallback(s32 result, DVDCommandBlock* commandBlock)
534 {
535 #pragma unused(result, commandBlock)
536 }
537
538 /*---------------------------------------------------------------------------*
539 Name: MNU_get_disk_id
540
541 Description: Show disk id
542
543 Arguments: menu Winmenuinfo for control window
544 item, result unused
545
546 Returns: none
547 *---------------------------------------------------------------------------*/
MNU_get_disk_id(DEMOWinMenuInfo * menu,u32 item,u32 * result)548 static void MNU_get_disk_id(DEMOWinMenuInfo *menu, u32 item, u32 *result)
549 {
550 #pragma unused(menu, item, result)
551 DVDDiskID* id;
552
553 id = DVDGetCurrentDiskID();
554
555 DEMOWinLogPrintf(debug_win, "====Current disk ID====\n");
556 DEMOWinLogPrintf(debug_win, " Game Name ... %-4.4s\n", id->gameName);
557 DEMOWinLogPrintf(debug_win, " Company ..... %-2.2s\n", id->company);
558 DEMOWinLogPrintf(debug_win, " Disk # ...... %x\n", id->diskNumber);
559 DEMOWinLogPrintf(debug_win, " Game ver .... %x\n", id->gameVersion);
560 }
561
562 /*---------------------------------------------------------------------------*
563 Name: Run_Demo
564
565 Description: Main loop of the demo.
566
567 Arguments: none
568
569 Returns: none
570 *---------------------------------------------------------------------------*/
Run_Demo(void)571 static void Run_Demo(void)
572 {
573 DEMOWinPadInfo pad;
574
575 DEMOWinLogPrintf(debug_win, "-------------------------------\n");
576 DEMOWinLogPrintf(debug_win, "DVD error handling sample\n");
577 DEMOWinLogPrintf(debug_win, "-------------------------------\n");
578 DEMOWinLogPrintf(debug_win, "- Stick Up/Down to move cursor\n");
579 DEMOWinLogPrintf(debug_win, "- Button A to select an item\n");
580 DEMOWinLogPrintf(debug_win, "- Button B to exit a menu\n");
581 DEMOWinLogPrintf(debug_win, "While you are executing a command, open cover, make no disk,\n");
582 DEMOWinLogPrintf(debug_win, "put other disks to see how to handle errors\n");
583
584 while(1)
585 {
586 // Launch control window. This function returns when B is pressed.
587 DEMOWinMenu(control_menu_ptr);
588
589 DEMOWinLogPrintf(debug_win, "-------------------------------------------\n");
590 DEMOWinLogPrintf(debug_win, "\nUse Stick Up/Down to scroll debug buffer.\n");
591 DEMOWinLogPrintf(debug_win, "\nHit Start to resume the demo.\n");
592
593 DEMOBeforeRender();
594 DEMOWinRefresh();
595 DEMODoneRender();
596 DEMOWinPadRead(&pad);
597
598 // Let the user to scroll the debug window. Press start button to
599 // go to the top of the outer loop and open the control window again.
600 while(1)
601 {
602
603 DEMOWinPadRead(&pad);
604
605 if (pad.pads[0].stickY < -50)
606 {
607 DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_DOWN);
608 if (pad.pads[0].triggerLeft > 150)
609 {
610 DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_DOWN);
611 DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_DOWN);
612 }
613 }
614 else if (pad.pads[0].stickY > 50)
615 {
616 DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_UP);
617 if (pad.pads[0].triggerLeft > 150)
618 {
619 DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_UP);
620 DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_UP);
621 }
622
623 }
624 else if (pad.changed_button[0] & PAD_BUTTON_START)
625 {
626 DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_HOME);
627 // get out of the inner loop
628 break;
629 }
630
631 DEMOBeforeRender();
632 DEMOWinRefresh();
633 DEMODoneRender();
634
635
636 } // debug buffer scroll loop
637
638 } // forever loop
639
640
641 } // end Init_Player_Windows()
642
643
644
645
main(void)646 void main(void)
647 {
648 void* arenaLo;
649
650 arenaLo = OSGetArenaLo();
651 Buffer = arenaLo;
652 OSSetArenaLo((void*)((u32)arenaLo + DVD_BUFFER_SIZE));
653
654 // disabled the default disc fatal screen
655 DVDSetAutoFatalMessaging(FALSE);
656
657 // clear user data
658 DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)NULL);
659
660 DEMOInit(NULL);
661
662 OSReport("Disk number is %x\n", DVDGetCurrentDiskID()->diskNumber);
663
664 AIInit(NULL);
665
666 OSReport("AIInit done\n");
667
668 DEMOWinInit();
669
670 OSReport("DEMOWinInit done\n");
671
672 InitWindows();
673
674 OSReport("InitWindows done\n");
675
676 Run_Demo();
677
678 } // end main
679