/*---------------------------------------------------------------------------* Project: Dolphin Demo Library File: DEMOPad.c Copyright 1998-2001 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: DEMOPad.c,v $ Revision 1.2 02/20/2006 04:37:44 mitu changed include path from dolphin/ to revolution/. Revision 1.1.1.1 2005/05/12 02:15:48 yasuh-to transitioned from the Dolphin source tree 10 8/09/01 9:47 Shiki Fixed to clear pad delta status if PAD_ERR_TRANSFER is occurred. 9 01/03/27 13:21 Shiki Detabbed. 8 01/03/23 6:06p Yasu Change commented code to introduce pad-queue. 7 01/03/22 21:44:00 Shiki Fixed DEMOPadRead() to conform to GameCube controller spec. Also refer to '/Dolphin/build/demos/paddemo/src/cont.c'. 6 2/14/01 1:48a Hirose Deleted first call check for DEMOPadInit( ). Now PadInit( ) can be called more than once. 5 10/27/00 3:47p Hirose fixed build flags 4 6/12/00 4:39p Hirose reconstructed structure and interface 3 4/26/00 4:59p Carl CallBack -> Callback 2 3/25/00 12:50a Hirose added some portion from cmn-pad.c added pad connection check 1 3/23/00 1:21a Hirose Initial version $NoKeywords: $ *---------------------------------------------------------------------------*/ #include #include /*---------------------------------------------------------------------------* Global Variables *---------------------------------------------------------------------------*/ DEMOPadStatus DemoPad[PAD_MAX_CONTROLLERS]; u32 DemoNumValidPads; /*---------------------------------------------------------------------------* Local Variables *---------------------------------------------------------------------------*/ static PADStatus Pad[PAD_MAX_CONTROLLERS]; // internal use only /*---------------------------------------------------------------------------*/ static u32 PadChanMask[PAD_MAX_CONTROLLERS] = { PAD_CHAN0_BIT, PAD_CHAN1_BIT, PAD_CHAN2_BIT, PAD_CHAN3_BIT }; /*---------------------------------------------------------------------------* Name: DEMOPadCopy Description: This function copies information of PADStatus into DEMOPadStatus structure. Also attaches some extra information such as down/up, stick direction. This function is internal use only. Keeps previous state if PAD_ERR_TRANSFER is returned. Arguments: pad : copy source. (PADStatus) dmpad : copy destination. (DEMOPadStatus) Returns: None *---------------------------------------------------------------------------*/ static void DEMOPadCopy( PADStatus* pad, DEMOPadStatus* dmpad ) { u16 dirs; if ( pad->err != PAD_ERR_TRANSFER ) { // Detects which direction is the stick(s) pointing. // This can be used when we want to use a stick as direction pad. dirs = 0; if ( pad->stickX < - DEMO_STICK_THRESHOLD ) dirs |= DEMO_STICK_LEFT; if ( pad->stickX > DEMO_STICK_THRESHOLD ) dirs |= DEMO_STICK_RIGHT; if ( pad->stickY < - DEMO_STICK_THRESHOLD ) dirs |= DEMO_STICK_DOWN; if ( pad->stickY > DEMO_STICK_THRESHOLD ) dirs |= DEMO_STICK_UP; if ( pad->substickX < - DEMO_STICK_THRESHOLD ) dirs |= DEMO_SUBSTICK_LEFT; if ( pad->substickX > DEMO_STICK_THRESHOLD ) dirs |= DEMO_SUBSTICK_RIGHT; if ( pad->substickY < - DEMO_STICK_THRESHOLD ) dirs |= DEMO_SUBSTICK_DOWN; if ( pad->substickY > DEMO_STICK_THRESHOLD ) dirs |= DEMO_SUBSTICK_UP; // Get the direction newly detected / released dmpad->dirsNew = PADButtonDown(dmpad->dirs, dirs); dmpad->dirsReleased = PADButtonUp(dmpad->dirs, dirs); dmpad->dirs = dirs; // Get DOWN/UP status of all buttons dmpad->buttonDown = PADButtonDown(dmpad->pst.button, pad->button); dmpad->buttonUp = PADButtonUp(dmpad->pst.button, pad->button); // Get delta of analogs dmpad->stickDeltaX = (s16)(pad->stickX - dmpad->pst.stickX); dmpad->stickDeltaY = (s16)(pad->stickY - dmpad->pst.stickY); dmpad->substickDeltaX = (s16)(pad->substickX - dmpad->pst.substickX); dmpad->substickDeltaY = (s16)(pad->substickY - dmpad->pst.substickY); // Copy current status into DEMOPadStatus field dmpad->pst = *pad; } else { // Get the direction newly detected / released dmpad->dirsNew = dmpad->dirsReleased = 0; // Get DOWN/UP status of all buttons dmpad->buttonDown = dmpad->buttonUp = 0; // Get delta of analogs dmpad->stickDeltaX = dmpad->stickDeltaY = 0; dmpad->substickDeltaX = dmpad->substickDeltaY = 0; } } /*---------------------------------------------------------------------------* Name: DEMOPadRead Description: Calls PADRead() and perform clamping. Get information of button down/up and sets them into extended field. This function also checks whether controllers are actually connected. Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOPadRead( void ) { s32 i; u32 ResetReq = 0; // for error handling // Read current PAD status PADRead( Pad ); // Clamp analog inputs PADClamp( Pad ); DemoNumValidPads = 0; for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ ) { // Connection check if ( Pad[i].err == PAD_ERR_NONE || Pad[i].err == PAD_ERR_TRANSFER ) { ++DemoNumValidPads; } else if ( Pad[i].err == PAD_ERR_NO_CONTROLLER ) { ResetReq |= PadChanMask[i]; } DEMOPadCopy( &Pad[i], &DemoPad[i] ); } // Try resetting pad channels which have been not valid if ( ResetReq ) { // Don't care return status // If FALSE, then reset again in next DEMOPadRead. PADReset( ResetReq ); } return; } /*---------------------------------------------------------------------------* Name: DEMOPadInit Description: Initialize PAD library and exported status Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOPadInit( void ) { s32 i; // Initialize pad interface PADInit(); // Reset exported pad status for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i++ ) { DemoPad[i].pst.button = 0; DemoPad[i].pst.stickX = 0; DemoPad[i].pst.stickY = 0; DemoPad[i].pst.substickX = 0; DemoPad[i].pst.substickY = 0; DemoPad[i].pst.triggerLeft = 0; DemoPad[i].pst.triggerRight = 0; DemoPad[i].pst.analogA = 0; DemoPad[i].pst.analogB = 0; DemoPad[i].pst.err = 0; DemoPad[i].buttonDown = 0; DemoPad[i].buttonUp = 0; DemoPad[i].dirs = 0; DemoPad[i].dirsNew = 0; DemoPad[i].dirsReleased = 0; DemoPad[i].stickDeltaX = 0; DemoPad[i].stickDeltaY = 0; DemoPad[i].substickDeltaX = 0; DemoPad[i].substickDeltaY = 0; } } #if 0 // Currently this stuff is not used. //============================================================================ // PAD-QUEUE Functions: NOW WORKS // // This set of functions helps the game engine with constant animation // rate. // // [Sample Code] // // BOOL isRetraced; // while ( !gameDone ) // { // do // { // isQueued = DEMOPadQueueRead( OS_MESSAGE_BLOCK ); // Do_animation( ); // } // while ( isQueued ); // // Do_rendering( ); // } // //============================================================================ #define DEMO_PADQ_DEPTH 8 void DEMOPadQueueInit ( void ); BOOL DEMOPadQueueRead ( s32 ); void DEMOPadQueueFlush ( void ); static PADStatus PadQueue[DEMO_PADQ_DEPTH][PAD_MAX_CONTROLLERS]; static OSMessageQueue PadValidMsgQ; static OSMessage PadValidMsg[DEMO_PADQ_DEPTH]; static OSMessageQueue PadEmptyMsgQ; static OSMessage PadEmptyMsg[DEMO_PADQ_DEPTH]; /*---------------------------------------------------------------------------* Name: DEMOPadViCallback Description: This function should be called once every frame. Arguments: None Returns: None *---------------------------------------------------------------------------*/ static void DEMOPadViCallback( u32 retraceCount ) { #pragma unused (retraceCount) PADStatus *padContainer; #ifdef _DEBUG static BOOL caution = FALSE; #endif // Get empty container. if ( OSReceiveMessage( &PadEmptyMsgQ, (OSMessage *)&padContainer, OS_MESSAGE_NOBLOCK ) ) { // Read the latest pad status into pad container PADRead( padContainer ); // Send result as message if ( !OSSendMessage( &PadValidMsgQ, (OSMessage)padContainer, OS_MESSAGE_NOBLOCK ) ) { // The valid queue never be full. ASSERTMSG( 0, "Logical Error: Valid QUEUE is full." ); } #ifdef _DEBUG caution = FALSE; #endif } else { #ifdef _DEBUG ASSERTMSG( caution, "Pad Queue is full." ); caution = TRUE; #endif } return; } /*---------------------------------------------------------------------------* Name: DEMOPadQueueRead Description: Read gamepad state and set to DemoPad[]. No need to care controller error. (When error, PADState is set to zero in PADRead.) Arguments: s32 flag: control block/noblock mode. when flag == OS_MESSAGE_BLOCK, wait next padinput if queue is empty. when flag == OS_MESSAGE_NOBLOCK, return immediately if queue is empty. Returns: BOOL: FALSE if queue was empty. TRUE if get queued data. *---------------------------------------------------------------------------*/ BOOL DEMOPadQueueRead( s32 flag ) { PADStatus *padContainer; BOOL isQueued; u32 i; // Get pad data from valid data queue isQueued = OSReceiveMessage( &PadValidMsgQ, (OSMessage *)&padContainer, OS_MESSAGE_NOBLOCK ); // If queue is empty, wait and sleep until coming pad input on v-retrace if ( !isQueued ) { if ( flag == OS_MESSAGE_BLOCK ) { OSReceiveMessage( &PadValidMsgQ, (OSMessage *)&padContainer, OS_MESSAGE_BLOCK ); } else { return FALSE; } } // Copy status to DemoPad for ( i = 0 ; i < PAD_MAX_CONTROLLERS ; i ++ ) { DEMOPadCopy( &padContainer[i], &DemoPad[i] ); } // Release pad container if ( !OSSendMessage( &PadEmptyMsgQ, (OSMessage)padContainer, OS_MESSAGE_NOBLOCK ) ) { // The valid queue never be full. ASSERTMSG( 0, "Logical Error: Empty QUEUE is full." ); } return isQueued; } /*---------------------------------------------------------------------------* Name: DEMOPadQueueFlush Description: Flush Pad-Queue Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOPadQueueFlush( void ) { OSMessage msg; while ( OSReceiveMessage( &PadValidMsgQ, &msg, OS_MESSAGE_NOBLOCK ) ) { OSSendMessage( &PadEmptyMsgQ, msg, OS_MESSAGE_BLOCK ); } return; } /*---------------------------------------------------------------------------* Name: DEMOPadQueueInit Description: Initialize Pad-Queue utility routines Arguments: None Returns: None *---------------------------------------------------------------------------*/ void DEMOPadQueueInit( void ) { u32 i; // Initialize basic pad function DEMOPadInit(); OSInitMessageQueue( &PadValidMsgQ, &PadValidMsg[0], DEMO_PADQ_DEPTH ); OSInitMessageQueue( &PadEmptyMsgQ, &PadEmptyMsg[0], DEMO_PADQ_DEPTH ); // Entry pad container for ( i = 0; i < DEMO_PADQ_DEPTH; i ++ ) { if ( !OSSendMessage( &PadEmptyMsgQ, (OSMessage)&PadQueue[i][0], OS_MESSAGE_NOBLOCK ) ) { ASSERTMSG( 0, "Logical Error: Send Message." ); } } // Reset pad queue and initialize pad HW DEMOPadQueueFlush(); // Register vi Callback function VISetPostRetraceCallback( DEMOPadViCallback ); return; } /*---------------------------------------------------------------------------*/ #endif // 0 /*===========================================================================*/