/*---------------------------------------------------------------------------* Project: Revolution DVD error handling demo File: errorhandling.c Copyright 2006 Nintendo. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Log: errorhandling.c,v $ Revision 1.8 2006/09/19 00:24:27 ooizumi Removed the code to handle DVD_STATE_NO_INPUT status. Revision 1.7 2006/09/07 00:10:05 ooizumi Modified to handle DVD_STATE_NO_INPUT state. Revision 1.6 2006/09/05 12:06:18 ooizumi Enabled to handle reset switch. Revision 1.5 2006/07/28 02:01:17 ooizumi Disabled handling reset switch code. Revision 1.4 2006/06/10 00:49:44 ooizumi Disabled the default disc fatal screen. Revision 1.3 2006/02/28 21:17:19 ooizumi Removed audio streaming functions. Modified several comments. Revision 1.1 2006/01/17 02:43:50 hiratsu Initial check in. 5 02/06/04 16:23 Hashida Removed warnings. 4 02/02/18 17:20 Hashida Added DVDGetCurrentDiskID. Fixed a bug that the demo crashes when executing DVDChangeDisk twice. 3 1/03/02 5:48p Hashida Added change disk. 2 6/16/01 5:50a Hashida Changed so that error status and play address are shown only when it's succeeded. 1 6/15/01 9:03p Hashida Initial revision. $NoKeywords: $ *---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------* * This demo illustrates how to handle errors. See __refresh_status() for * the actual error handling code! *---------------------------------------------------------------------------*/ #include #include #include #include #include #include "selectfile.h" /*---------------------------------------------------------------------------* * DVD definitions *---------------------------------------------------------------------------*/ #define DVD_BUFFER_SIZE 0xf00000 static void* Buffer; static DVDFileInfo FileInfo; static volatile BOOL FileInfoIsInUse = FALSE; static DVDDiskID DiskID; /*---------------------------------------------------------------------------* * Misc *---------------------------------------------------------------------------*/ #define MIN(x, y) ((x) < (y)? (x):(y)) /*---------------------------------------------------------------------------* * Data to pass from command issuing routines to status printing routine. *---------------------------------------------------------------------------*/ enum{ COMMAND_READ, COMMAND_SEEK, COMMAND_GET_ERROR_STATUS, COMMAND_CHANGE_DISK }; typedef struct { u32 command; s32 readLength; } CommandBlockData; static CommandBlockData Data; /*---------------------------------------------------------------------------* * Messages for errors *---------------------------------------------------------------------------*/ typedef struct { char* line[6]; } Message; // Error messages. XXX Caution: Subject to change. Message ErrorMessages[] = { {"Please insert the disc for xxx.", "", "", "", "", ""}, {"This disc is not for xxx.", "Please insert the disc for xxx.", "", "", "", ""}, {"The disc could not be read.", "", "Please read the NINTENDO REVOLUTION", "Instruction Booklet for more information", "", ""}, {"An error has occurred.", "", "Turn the power OFF and check", "the NINTENDO REVOLUTION", "Instruction Booklet for", "further instructions."}, {"Please insert the next disc.", "", "", "", "", ""}, }; enum{ MESSAGE_NO_DISK = 0, MESSAGE_WRONG_DISK, MESSAGE_RETRY_ERROR, MESSAGE_FATAL_ERROR, MESSAGE_CHANGE_DISK }; /*---------------------------------------------------------------------------* * Prototypes *---------------------------------------------------------------------------*/ static void InitWindows(void); static void __status_refresh(DEMOWinInfo *handle); static void Run_Demo(void); static void MNU_read(DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_seek(DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_cancel(DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_change_disk(DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_get_disk_id(DEMOWinMenuInfo *menu, u32 item, u32 *result); static void MNU_pick_number(DEMOWinMenuInfo *menu, u32 item, u32 *result); /*---------------------------------------------------------------------------* * Main Control Menu Stuff! *---------------------------------------------------------------------------*/ DEMOWinMenuItem control_menu_items[] = { { "ISSUE COMMAND", DEMOWIN_ITM_SEPARATOR, NULL, NULL }, { " DVDRead", DEMOWIN_ITM_NONE, MNU_read, NULL }, { " DVDSeek", DEMOWIN_ITM_NONE, MNU_seek, NULL }, { " DVDCancel", DEMOWIN_ITM_NONE, MNU_cancel, NULL }, { " DVDChangeDisk", DEMOWIN_ITM_NONE, MNU_change_disk, NULL }, { " DVDGetCurrentDiskID", DEMOWIN_ITM_NONE, MNU_get_disk_id, NULL }, { "", DEMOWIN_ITM_TERMINATOR, NULL, NULL } }; DEMOWinMenuInfo control_menu = { "DVD Error Handling Demo", // title NULL, // window handle control_menu_items, // list of menu items 50, // max num of items to display at a time DEMOWIN_MNU_NONE, // attribute flags? // user callbacks for misc menu operations NULL, NULL, NULL, NULL, // private menu info members; do not touch 0, 0, 0, 0, 0 }; DEMOWinMenuInfo *control_menu_ptr; DEMOWinMenuItem number_menu_items[] = { { "255", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "0", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "1", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "2", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "3", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "4", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "5", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "6", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "7", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "8", DEMOWIN_ITM_EOF, MNU_pick_number, NULL }, { "", DEMOWIN_ITM_TERMINATOR, NULL, NULL } }; DEMOWinMenuInfo number_menu = { "Pick next disk number", // title NULL, // window handle number_menu_items, // list of menu items 10, // max num of items to display at a time DEMOWIN_MNU_NONE, // attribute flags? // user callbacks for misc menu operations NULL, NULL, NULL, NULL, // private menu info members; do not touch 0, 0, 0, 0, 0 }; /*---------------------------------------------------------------------------* * Debug and Status window stuff! *---------------------------------------------------------------------------*/ DEMOWinInfo *debug_win; // debug window DEMOWinInfo *status_win; // status window DEMOWinInfo *errmsg_win; // error message window /*---------------------------------------------------------------------------* Name: InitWindows Description: Initialize windows Arguments: none Returns: none *---------------------------------------------------------------------------*/ static void InitWindows(void) { DEMOWinInfo *p; control_menu_ptr = DEMOWinCreateMenuWindow(&control_menu, 20, 20); p = control_menu_ptr->handle; // Intialize a window for showing status of DVD commands // By passing "__status_refresh" as the last argument, the window system // calls "__status_refresh" once every frame. We use this function to // handle errors in this demo. status_win = DEMOWinCreateWindow((u16)(p->x2+5), p->y1, 620, (u16)(p->y1+100), "Status", 0, __status_refresh); // Initialize a window for debug output debug_win = DEMOWinCreateWindow((u16)(p->x2+5), (u16)(p->y1+105), 620, 434, "Debug", 1024, NULL); // Initialize a window for showing error message errmsg_win = DEMOWinCreateWindow(120, 150, 520, 250, "Error message", 0, NULL); // Open status and debug windows. We don't open error message window until // we hit an error. DEMOWinOpenWindow(debug_win); DEMOWinOpenWindow(status_win); // Tell the pointer to the debug window to the "file select" system InitSelectFile(debug_win); } /*---------------------------------------------------------------------------* Name: __status_refresh Description: This is the error handling part. This function is called once every frame. Arguments: handle Window handle for the status window Returns: none *---------------------------------------------------------------------------*/ static void __status_refresh(DEMOWinInfo *handle) { static u32 counter; s32 message; u32 i; CommandBlockData *data; // Clear status window (we only use the first two rows) DEMOWinClearRow(handle, 0); DEMOWinClearRow(handle, 1); // We use "user data" as the information of the command that was issued // last. data = DVDGetUserData((DVDCommandBlock*)&FileInfo); if (data) { // If it's a read command, show the progress if (data->command == COMMAND_READ) { DEMOWinPrintfXY(handle, 0, 0, "Now loading....%3d%%(%d/%d)", 100*DVDGetTransferredSize(&FileInfo)/data->readLength, DVDGetTransferredSize(&FileInfo), data->readLength); } } message = -1; // This part is for debugging purpose. Show the drive's status on status // window. switch(DVDGetDriveStatus()) { case DVD_STATE_END: FileInfoIsInUse = FALSE; DEMOWinPrintfXY(handle, 0, 1, "Command finished"); break; case DVD_STATE_FATAL_ERROR: DEMOWinPrintfXY(handle, 0, 1, "Fatal error occurred"); message = MESSAGE_FATAL_ERROR; break; case DVD_STATE_BUSY: break; case DVD_STATE_NO_DISK: DEMOWinPrintfXY(handle, 0, 1, "No disk"); message = MESSAGE_NO_DISK; break; case DVD_STATE_WRONG_DISK: DEMOWinPrintfXY(handle, 0, 1, "Wrong disk"); message = MESSAGE_WRONG_DISK; break; case DVD_STATE_RETRY: DEMOWinPrintfXY(handle, 0, 1, "Please retry"); message = MESSAGE_RETRY_ERROR; break; case DVD_STATE_MOTOR_STOPPED: DEMOWinPrintfXY(handle, 0, 1, "Ready to replace"); message = MESSAGE_CHANGE_DISK; break; } // If necessary, launch error message window to show the error message to // the user. if (message >= 0) { DEMOWinOpenWindow(errmsg_win); counter = (counter+1) % 60; for (i = 0; i < 6; i++) { if (counter < 45) { DEMOWinClearRow(errmsg_win, (u16)i); DEMOWinPrintfXY(errmsg_win, 0, (u16)i, ErrorMessages[message].line[i]); } else { DEMOWinClearRow(errmsg_win, (u16)i); } } } else { DEMOWinCloseWindow(errmsg_win); } if (OSGetResetSwitchState()) { OSReport("reset is pressed\n"); while (OSGetResetSwitchState()) ; OSReport("reset is released\n"); // Black out screen VISetBlack(TRUE); VIFlush(); VIWaitForRetrace(); OSRestart(3); } } // end __status_refresh() /*---------------------------------------------------------------------------* Name: MNU_cancel Description: Issue DVDCancel. This function is called when DVDCancel is selected in the control window. Arguments: menu, item, result unused Returns: none *---------------------------------------------------------------------------*/ static void MNU_cancel(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(menu, item, result) DVDCancelAsync((DVDCommandBlock*)&FileInfo, NULL); } static void readCallback(s32 result, DVDFileInfo* fileInfo) { #pragma unused(fileInfo) if (result == DVD_RESULT_FATAL_ERROR) return; if (result == DVD_RESULT_CANCELED) { OSReport("read canceled\n"); return; } OSReport("read finished\n"); } /*---------------------------------------------------------------------------* Name: MNU_read Description: Issue DVDRead, after letting the user to select a file to read. Arguments: menu Winmenuinfo for control window item, result unused Returns: none *---------------------------------------------------------------------------*/ static void MNU_read(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(item) #pragma unused(result) s32 length; char* file; // Avoid using the same FileInfo/CommandBlock at the same time. if (FileInfoIsInUse) { return; } DEMOWinLogPrintf(debug_win, "\nIssuing a read...\n"); DEMOWinLogPrintf(debug_win, "Press A to choose a file to read or change directory.\nPress B to exit.\n"); // Launch a window to let the user to select a file. // The return value is the pointer to the selected file. file = SelectFile(menu->handle); DVDOpen(file, &FileInfo); // If the size of the file is larger than the buffer size, we only read // the first DVD_BUFFER_SIZE bytes. length = (s32)OSRoundUp32B(MIN(DVDGetLength(&FileInfo), DVD_BUFFER_SIZE)); // Pass information to __status_refresh() Data.command = COMMAND_READ; Data.readLength = length; DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)&Data); FileInfoIsInUse = TRUE; DVDReadAsync(&FileInfo, Buffer, length, 0, readCallback); } /*---------------------------------------------------------------------------* Name: MNU_seek Description: Issue DVDSeek, after letting the user to select a file to seek to. Arguments: menu Winmenuinfo for control window item, result unused Returns: none *---------------------------------------------------------------------------*/ static void MNU_seek(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(item) #pragma unused(result) char* file; // Avoid using the same FileInfo/CommandBlock at the same time. if (FileInfoIsInUse) { return; } DEMOWinLogPrintf(debug_win, "\nIssuing a seek...\n"); DEMOWinLogPrintf(debug_win, "Press A to choose a file to seek to or change directory.\nPress B to exit.\n"); // Launch a window to let the user to select a file. // The return value is the pointer to the selected file. file = SelectFile(menu->handle); DVDOpen(file, &FileInfo); // Pass information to __status_refresh() Data.command = COMMAND_SEEK; DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)&Data); FileInfoIsInUse = TRUE; DVDSeekAsync(&FileInfo, 0, NULL); } static void MNU_pick_number(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused (menu) *result = (item == 0)? 0xff : item - 1; } // end __select_file static u32 PickNumber(DEMOWinInfo *handle) { u32 val = 0; DEMOWinSetWindowColor(handle, DEMOWIN_COLOR_CAPTION, 50, 50, 50, 255); DEMOWinCreateMenuWindow(&number_menu, (u16)(handle->x2-10), (u16)(handle->y1+24)); val = DEMOWinMenu(&number_menu); DEMOWinDestroyMenuWindow(&number_menu); DEMOWinSetWindowColor(handle, DEMOWIN_COLOR_RESET, 0, 0, 0, 0); return val; } /*---------------------------------------------------------------------------* Name: MNU_change_disk Description: Issue DVDChangeDisk Arguments: menu Winmenuinfo for control window item, result unused Returns: none *---------------------------------------------------------------------------*/ static void MNU_change_disk(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(menu, item, result) u32 n; // Avoid using the same FileInfo/CommandBlock at the same time. if (FileInfoIsInUse) { return; } // Pass information to __status_refresh() Data.command = COMMAND_CHANGE_DISK; DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)&Data); n = PickNumber(menu->handle); OSReport("number: %d\n", n); memcpy(&DiskID, DVDGetCurrentDiskID(), sizeof(DVDDiskID)); DiskID.diskNumber = (u8)n; // BCD (0x00 ... 1st disk, 0x01 ... 2nd disk) FileInfoIsInUse = TRUE; DVDChangeDiskAsync((DVDCommandBlock*)&FileInfo, &DiskID, NULL); } static void changeDiskCallback(s32 result, DVDCommandBlock* commandBlock) { #pragma unused(result, commandBlock) } /*---------------------------------------------------------------------------* Name: MNU_get_disk_id Description: Show disk id Arguments: menu Winmenuinfo for control window item, result unused Returns: none *---------------------------------------------------------------------------*/ static void MNU_get_disk_id(DEMOWinMenuInfo *menu, u32 item, u32 *result) { #pragma unused(menu, item, result) DVDDiskID* id; id = DVDGetCurrentDiskID(); DEMOWinLogPrintf(debug_win, "====Current disk ID====\n"); DEMOWinLogPrintf(debug_win, " Game Name ... %-4.4s\n", id->gameName); DEMOWinLogPrintf(debug_win, " Company ..... %-2.2s\n", id->company); DEMOWinLogPrintf(debug_win, " Disk # ...... %x\n", id->diskNumber); DEMOWinLogPrintf(debug_win, " Game ver .... %x\n", id->gameVersion); } /*---------------------------------------------------------------------------* Name: Run_Demo Description: Main loop of the demo. Arguments: none Returns: none *---------------------------------------------------------------------------*/ static void Run_Demo(void) { DEMOWinPadInfo pad; DEMOWinLogPrintf(debug_win, "-------------------------------\n"); DEMOWinLogPrintf(debug_win, "DVD error handling sample\n"); DEMOWinLogPrintf(debug_win, "-------------------------------\n"); DEMOWinLogPrintf(debug_win, "- Stick Up/Down to move cursor\n"); DEMOWinLogPrintf(debug_win, "- Button A to select an item\n"); DEMOWinLogPrintf(debug_win, "- Button B to exit a menu\n"); DEMOWinLogPrintf(debug_win, "While you are executing a command, open cover, make no disk,\n"); DEMOWinLogPrintf(debug_win, "put other disks to see how to handle errors\n"); while(1) { // Launch control window. This funcion returns when B is pressed. DEMOWinMenu(control_menu_ptr); DEMOWinLogPrintf(debug_win, "-------------------------------------------\n"); DEMOWinLogPrintf(debug_win, "\nUse Stick Up/Down to scroll debug buffer.\n"); DEMOWinLogPrintf(debug_win, "\nHit Start to resume the demo.\n"); DEMOBeforeRender(); DEMOWinRefresh(); DEMODoneRender(); DEMOWinPadRead(&pad); // Let the user to scroll the debug window. Press start button to // go to the top of the outer loop and open the control window again. while(1) { DEMOWinPadRead(&pad); if (pad.pads[0].stickY < -50) { DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_DOWN); if (pad.pads[0].triggerLeft > 150) { DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_DOWN); DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_DOWN); } } else if (pad.pads[0].stickY > 50) { DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_UP); if (pad.pads[0].triggerLeft > 150) { DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_UP); DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_UP); } } else if (pad.changed_button[0] & PAD_BUTTON_START) { DEMOWinScrollWindow(debug_win, DEMOWIN_SCROLL_HOME); // get out of the inner loop break; } DEMOBeforeRender(); DEMOWinRefresh(); DEMODoneRender(); } // debug buffer scroll loop } // forever loop } // end Init_Player_Windows() void main(void) { void* arenaLo; arenaLo = OSGetArenaLo(); Buffer = arenaLo; OSSetArenaLo((void*)((u32)arenaLo + DVD_BUFFER_SIZE)); // disabled the default disc fatal screen DVDSetAutoFatalMessaging(FALSE); // clear user data DVDSetUserData((DVDCommandBlock*)&FileInfo, (void*)NULL); DEMOInit(NULL); OSReport("Disk number is %x\n", DVDGetCurrentDiskID()->diskNumber); AIInit(NULL); OSReport("AIInit done\n"); DEMOWinInit(); OSReport("DEMOWinInit done\n"); InitWindows(); OSReport("InitWindows done\n"); Run_Demo(); } // end main