/*--------------------------------------------------------------------------* Project: WPAD demo program File: wpadsample.c Copyright (C) 2007 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: wpadsample.c,v $ Revision 1.3.2.3 2007/12/11 01:49:03 tojo (none) Revision 1.3.2.2 2007/12/11 01:34:09 tojo Fixed syntax error. Revision 1.3.2.1 2007/12/11 01:31:47 tojo Modified to handle the error code of WPADStatus. Revision 1.3 2007/07/19 08:59:54 tojo Cleared string buffer before getting the game title. Revision 1.2 2007/07/11 11:42:55 tojo Added the distance calculation and introduction on serial output. Revision 1.1 2007/07/11 09:06:40 tojo Initial check-in. *---------------------------------------------------------------------------*/ #include #include #include #include #include #define DEMO_USE_MEMLIB=1 // This turns on the DEMO library's MEM heaps. #include /*---------------------------------------------------------------------------* * Local Definitions *---------------------------------------------------------------------------*/ #define SCRN_WIDTH 640 #define SCRN_HEIGHT 480 #define FONT_HEIGHT 10 #define CLMN_WIDTH 20 * FONT_HEIGHT #define CHAN_INDENT 140 #define ITEM_WIDTH 80 #define X_START 10 #define Y_START 16 enum { MNU_RUMBLE = 0, MNU_INFO, MNU_DISCN, MNU_ACC, MNU_DPD, MNU_DPD_FULL, MNU_EXTGMK, MNU_RDMEM, MNU_WRMEM, MNU_DMEXT }; #define SMPBUF_SIZE 120 #define SEPARATION 0.20f // Meter unit. // You must modify this value according to your environment. /*---------------------------------------------------------------------------* * Local Data *---------------------------------------------------------------------------*/ static WPADCLStatus cl_ringbuffer[WPAD_MAX_CONTROLLERS][SMPBUF_SIZE+4]; static WPADFSStatus fs_ringbuffer[WPAD_MAX_CONTROLLERS][SMPBUF_SIZE+4]; static WPADStatus co_ringbuffer[WPAD_MAX_CONTROLLERS][SMPBUF_SIZE+4]; static WPADStatusEx ex_ringbuffer[WPAD_MAX_CONTROLLERS][SMPBUF_SIZE+4]; static WPADInfo infos[WPAD_MAX_CONTROLLERS]; static int rb [WPAD_MAX_CONTROLLERS]; static int rbCount [WPAD_MAX_CONTROLLERS]; static int acc [WPAD_MAX_CONTROLLERS]; static int dpd [WPAD_MAX_CONTROLLERS]; static int dpd_full[WPAD_MAX_CONTROLLERS]; static int extGmk [WPAD_MAX_CONTROLLERS]; static int dummyExt[WPAD_MAX_CONTROLLERS]; static u8 readBuf [WPAD_MAX_CONTROLLERS][4096]; static u8 writeBuf[WPAD_MAX_CONTROLLERS][4096]; static int col; static int row; static u8 smp_pair; static u8 std_pair; static u8 reset; static u8 power; static u8 rbPattern[64] = {1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0}; u8 fmt_core1[] = "CORE "; u8 fmt_core2[] = "CORE_ACC "; u8 fmt_core3[] = "CORE_ACC_DPD "; u8 fmt_nun1[] = "FREESTYLE "; u8 fmt_nun2[] = "FREESTYLE_ACC "; u8 fmt_nun3[] = "FREESTYLE_ACC_DPD"; u8 fmt_clas1[] = "CLASSIC "; u8 fmt_clas2[] = "CLASSIC_ACC "; u8 fmt_clas3[] = "CLASSIC_ACC_DPD "; u8 fmt_full[] = "CORE_ACC_DPD_FULL"; u8 str_dev_core [] = "CORE "; u8 str_dev_extn [] = "NCHKU"; u8 str_dev_cl [] = "CLSIC"; u8 str_dev_future [] = "FTURE"; u8 str_dev_notsup [] = "UNSPT"; u8 str_dev_unknown[] = "UNKWN"; u8 str_dev_notfound[]= "NTFND"; u8 str_status_ok [] = "OK "; u8 str_status_none[] = "NONE "; u8 str_status_busy[] = "BUSY "; u8 str_status_xfer[] = "TRANS"; u8 str_status_inv [] = "INVLD"; u8 str_status_crpt[] = "CRPTD"; u8 str_status_unk [] = "UNKWN"; u8 dpd_fmt_off [] = "OFF "; u8 dpd_fmt_std [] = "STD "; u8 dpd_fmt_exp [] = "EXP "; u8 dpd_fmt_full [] = "FULL"; u8 sync_std[] = "STD"; u8 sync_smp[] = "SMP"; u8 sync_unk[] = "NONE"; /*---------------------------------------------------------------------------* * Function prototypes *---------------------------------------------------------------------------*/ static void *myAlloc ( u32 size ); static u8 myFree ( void *ptr ); static void sysInit ( void ); static void sysShutdown ( void ); static void appInit ( void ); static void wpadInit ( void ); static void resetCallback ( void ); static void powerCallback ( void ); static void samplingCallback ( s32 chan ); static void connectCallback ( s32 chan, s32 reason ); static void extensionCallback ( s32 chan, s32 result ); static void syncButtonCallback ( s32 result, s32 num ); static void syncSimpleCallback ( s32 result, s32 num ); static void update ( void ); static void operate ( void ); static void moveCursor ( void ); static void resetController ( s32 chan, u32 type ); static void renderScreen ( void ); static void renderAimings ( void ); static void renderStatus ( void ); static void renderDots ( void *ptr ); static u8 *getDevName ( u32 type ); static u8 *getErrName ( s8 err ); static u8 *getDpdFmt ( u8 fmt ); static u8 *getSyncName ( u8 sync ); static u8 *getFormat ( u32 fmt ); static f32 getDistance ( const WPADStatus *stat ); static void printIntro ( void ); /*===========================================================================* * F U N C T I O N D E F I N I T I O N S *===========================================================================*/ /*---------------------------------------------------------------------------* Name: main Description: None. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ void main( void ) { sysInit(); appInit(); wpadInit(); printIntro(); // main loop while( reset && power ) { DEMOBeforeRender(); renderScreen(); renderStatus(); renderAimings(); DEMODoneRender(); DEMOPadRead(); update(); operate(); moveCursor(); } sysShutdown(); } /*---------------------------------------------------------------------------* Name: sysInit Description: Initializes system. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void sysInit( void ) { const GXColor DARKBLUE = { 0, 0, 80, 255 }; // Initialize OS OSInit(); // Initialize reset and power process. reset = power = 1; OSSetResetCallback(resetCallback); OSSetPowerCallback(powerCallback); // Initialize DEMO DEMOInit( &GXNtsc480IntDf ); DEMOPadInit(); // Initialize screen setting GXSetCopyClear( DARKBLUE, GX_MAX_Z24 ); GXCopyDisp( DEMOGetCurrentBuffer(), GX_TRUE ); DEMOInitCaption( DM_FT_XLU, SCRN_WIDTH, SCRN_HEIGHT ); GXSetZMode( GX_ENABLE, GX_ALWAYS, GX_ENABLE ); // Set pixel processing mode GXSetBlendMode( GX_BM_BLEND, GX_BL_ONE, GX_BL_ONE, GX_LO_CLEAR ); // Translucent mode } /*---------------------------------------------------------------------------* Name: sysShutdown Description: Shutdown system. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void sysShutdown( void ) { int i; // Make screen black. VISetBlack(TRUE); VIFlush(); for(i=0; i<8; i++) { VIWaitForRetrace(); } // reset or shutdown. if (!reset) { OSRestart(0); } if (!power) { OSShutdownSystem(); } } /*---------------------------------------------------------------------------* Name: resetCallback Description: Function to be called when reset button is pressed. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void resetCallback( void ) { reset = 0; } /*---------------------------------------------------------------------------* Name: powerCallback Description: Function to be called when power button on wii console is pressed or power button on wii remote registered by standard pairing. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void powerCallback( void ) { power = 0; } /*---------------------------------------------------------------------------* Name: appInit Description: Initializes application. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void appInit( void ) { int i; col = 0; row = 0; for(i=0; i 0) ? col - 1 : 0; } if (trig & PAD_BUTTON_DOWN) { col = (col < MNU_DMEXT) ? col + 1 : col; } if (trig & PAD_BUTTON_LEFT) { row = (row > 0) ? row - 1 : 0;; } if (trig & PAD_BUTTON_RIGHT) { row = (row < WPAD_MAX_CONTROLLERS) ? row + 1 : row; } } /*---------------------------------------------------------------------------* Name: operate Description: None. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void operate() { int i; u32 trig = DEMOPadGetButtonDown(0); u32 type; u8 chan[4] = {0,0,0,0}; if (trig & PAD_BUTTON_A) { if (row == 4) { chan[0] = chan[1] = chan[2] = chan[3] = 1; } else { chan[row] = 1; } for(i=0; iobj[0].x - wpad->obj[1].x; yDiff = wpad->obj[0].y - wpad->obj[1].y; dpdDist = (f32)sqrt(xDiff * xDiff + yDiff * yDiff); if ((wpad->obj[0].size > 0) && (wpad->obj[1].size > 0)) { return (f32)(SEPARATION / 2 / tan(TH) * WPAD_DPD_IMG_RESO_WX / dpdDist); } else { return -1.0f; } } /*---------------------------------------------------------------------------* Name: renderScreen Description: Draw the items of controller status and menu. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void renderScreen( void ) { s16 x = X_START; s16 y = Y_START; s16 i; DEMOPrintf(x, y, 0, "WPAD Demo -- WPADSAMPLE"); y+=FONT_HEIGHT*2; for(i=0; i' : '_'); btn[4] = (char)((wpad.button & WPAD_BUTTON_A) ? 'A' : '_'); btn[5] = (char)((wpad.button & WPAD_BUTTON_B) ? 'B' : '_'); btn[6] = (char)((wpad.button & WPAD_BUTTON_1) ? '1' : '_'); btn[7] = (char)((wpad.button & WPAD_BUTTON_2) ? '2' : '_'); btn[8] = (char)((wpad.button & WPAD_BUTTON_PLUS) ? '+' : '_'); btn[9] = (char)((wpad.button & WPAD_BUTTON_MINUS)? '-' : '_'); btn[10]= (char)((wpad.button & WPAD_BUTTON_HOME) ? 'H' : '_'); } DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", btn); // acc on wii remote. if (wpad.err == WPAD_ERR_NONE || wpad.err == WPAD_ERR_CORRUPTED) { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), (s16)(y+FONT_HEIGHT), 0, "%1.2lf", (f32)((f32)wpad.accX/(f32)acc.x)); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), (s16)(y+FONT_HEIGHT), 0, "%1.2lf", (f32)((f32)wpad.accY/(f32)acc.y)); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 90), y+=FONT_HEIGHT, 0, "%1.2lf", (f32)((f32)wpad.accZ/(f32)acc.z)); } else { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), (s16)(y+FONT_HEIGHT), 0, "---"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), (s16)(y+FONT_HEIGHT), 0, "---"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 90), y+=FONT_HEIGHT, 0, "---"); } // dpd. for(j=0; j> j) & 0x1u) { led[j] = 'o'; } } DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%d, %s", infos[i].battery, led); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", game[i]); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%02d/%02d %02d:%02d", ct.mon+1, ct.mday, ct.hour, ct.min); switch(type) { case WPAD_DEV_FREESTYLE: { WPADFSStatus *fs = (WPADFSStatus*)&wpad; char cz[] = "__"; // Get the acc calibration for each axis on nunchaku. WPADGetAccGravityUnit(i, WPAD_DEV_FREESTYLE, &acc); // button. if (fs->err == WPAD_ERR_NONE) { cz[0] = (char)((fs->button & WPAD_BUTTON_C) ? 'C' : '_'); cz[1] = (char)((fs->button & WPAD_BUTTON_Z) ? 'Z' : '_'); } DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", cz); // stick if (fs->err == WPAD_ERR_NONE) { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "%04d", fs->fsStickX); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "%04d", fs->fsStickY); } else { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "----"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "----"); } // acc on nunchaku. if (fs->err == WPAD_ERR_NONE) { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), (s16)(y+FONT_HEIGHT), 0, "%1.2lf", (f32)((f32)fs->fsAccX/(f32)acc.x)); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), (s16)(y+FONT_HEIGHT), 0, "%1.2lf", (f32)((f32)fs->fsAccY/(f32)acc.y)); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 90), y+=FONT_HEIGHT, 0, "%1.2lf", (f32)((f32)fs->fsAccZ/(f32)acc.z)); } else { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), (s16)(y+FONT_HEIGHT), 0, "----"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), (s16)(y+FONT_HEIGHT), 0, "----"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 90), y+=FONT_HEIGHT, 0, "----"); } } y+=FONT_HEIGHT; break; case WPAD_DEV_CLASSIC: { WPADCLStatus *cl = (WPADCLStatus*)&wpad; char clb[] = "_______________"; // button. if (cl->err == WPAD_ERR_NONE) { clb[0] = (char)((cl->clButton & WPAD_CL_BUTTON_LEFT) ? '<' : '_'); clb[1] = (char)((cl->clButton & WPAD_CL_BUTTON_UP) ? '^' : '_'); clb[2] = (char)((cl->clButton & WPAD_CL_BUTTON_DOWN) ? 'v' : '_'); clb[3] = (char)((cl->clButton & WPAD_CL_BUTTON_RIGHT)? '>' : '_'); clb[4] = (char)((cl->clButton & WPAD_CL_BUTTON_A) ? 'A' : '_'); clb[5] = (char)((cl->clButton & WPAD_CL_BUTTON_B) ? 'B' : '_'); clb[6] = (char)((cl->clButton & WPAD_CL_BUTTON_X) ? 'X' : '_'); clb[7] = (char)((cl->clButton & WPAD_CL_BUTTON_Y) ? 'Y' : '_'); clb[8] = (char)((cl->clButton & WPAD_CL_TRIGGER_L) ? 'L' : '_'); clb[9] = (char)((cl->clButton & WPAD_CL_TRIGGER_R) ? 'R' : '_'); clb[10]= (char)((cl->clButton & WPAD_CL_TRIGGER_ZL) ? 'z' : '_'); clb[11]= (char)((cl->clButton & WPAD_CL_TRIGGER_ZR) ? 'Z' : '_'); clb[12]= (char)((cl->clButton & WPAD_CL_BUTTON_PLUS) ? '+' : '_'); clb[13]= (char)((cl->clButton & WPAD_CL_BUTTON_MINUS)? '-' : '_'); clb[14]= (char)((cl->clButton & WPAD_CL_BUTTON_HOME) ? 'H' : '_'); } DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", clb); // stick. if (cl->err == WPAD_ERR_NONE) { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "%04d", cl->clLStickX); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "%04d", cl->clLStickY); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "%04d", cl->clRStickX); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "%04d", cl->clRStickY); } else { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "----"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "----"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "----"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "----"); } // trigger. if (cl->err == WPAD_ERR_NONE) { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "%04d", cl->clTriggerL); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "%04d", cl->clTriggerR); } else { DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH) , (s16)(y+FONT_HEIGHT), 0, "----"); DEMOPrintf((s16)(x + CHAN_INDENT * i + ITEM_WIDTH + 45), y+=FONT_HEIGHT, 0, "----"); } } break; default: y+=FONT_HEIGHT*3; break; } } y = Y_START + FONT_HEIGHT * 25; DEMOPrintf((s16)(x + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%d", WPADGetWorkMemorySize()); DEMOPrintf((s16)(x + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%02d, %02d", WPADGetRegisteredDevNum(), WPADGetTemporaryDevNum()); DEMOPrintf((s16)(x + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", WPADGetSensorBarPosition() ? "TOP" : "BOTTOM"); DEMOPrintf((s16)(x + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", WPADIsMotorEnabled() ? "ENABLE" : "DISABLE"); DEMOPrintf((s16)(x + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", WPADGetAcceptConnection() ? "OK" : "NG"); DEMOPrintf((s16)(x + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", (std_pair) ? "STOP" : "START"); DEMOPrintf((s16)(x + ITEM_WIDTH), y+=FONT_HEIGHT, 0, "%s", (smp_pair) ? "STOP" : "START"); } /*---------------------------------------------------------------------------* Name: renderDots Description: Draw a dot at the center of the coordinates of two objects. Arguments: ptr point to the controller data. Returns: None. *---------------------------------------------------------------------------*/ static void renderDots( void *ptr ) { s16 x; s16 y; WPADStatus *wpad = (WPADStatus*)ptr; // Check the error type of the controller data. // The data from dpd is available if the type is WPAD_ERR_NONE or WPAD_ERR_CORRUPTED. if (wpad->err == WPAD_ERR_NONE || wpad->err == WPAD_ERR_CORRUPTED) { x = (s16)(SCRN_WIDTH - (wpad->obj[0].x + wpad->obj[1].x) / 2 * SCRN_WIDTH / WPAD_DPD_IMG_RESO_WX); y = (s16)(SCRN_HEIGHT - (wpad->obj[0].y + wpad->obj[1].y) / 2 * SCRN_HEIGHT / WPAD_DPD_IMG_RESO_WY); DEMOPrintf(x, y, 0, "."); } } /*---------------------------------------------------------------------------* Name: renderAimings Description: Draw dots using sampled controller data. Arguments: None. Returns: None. *---------------------------------------------------------------------------*/ static void renderAimings( void ) { u32 latest; u32 index; int i; int j; u8 *ptr; u32 size; for (j=0; j