#include "common.h" #include "dolphin.h" #include "game/msm.h" typedef struct pad_rumble { s16 duration; s16 off; s16 on; s16 time; } PadRumble; void HuPadRead(void); static void PadReadVSync(u32 retraceCount); static void PadADConv(s16 pad, PADStatus *status); static int padStatErrOld[4]; static PadRumble rumbleData[4]; u16 HuPadBtn[4]; u16 HuPadBtnDown[4]; u16 HuPadBtnRep[4]; s8 HuPadStkX[4]; s8 HuPadStkY[4]; s8 HuPadSubStkX[4]; s8 HuPadSubStkY[4]; u8 HuPadTrigL[4]; u8 HuPadTrigR[4]; u8 HuPadDStk[4]; u8 HuPadDStkRep[4]; s8 HuPadErr[4]; u16 _PadBtn[4]; u16 _PadBtnDown[4]; static u16 _PadRepCnt[4]; static s8 _PadStkX[4]; static s8 _PadStkY[4]; static s8 _PadSubStkX[4]; static s8 _PadSubStkY[4]; static u8 _PadTrigL[4]; static u8 _PadTrigR[4]; static u8 _PadDStk[4]; static u8 _PadDStkRep[4]; static u8 _PadDStkRepCnt[4]; static u8 _PadDStkRepOld[4]; static s8 _PadErr[4]; static u32 RumbleBit; u32 VCounter; u32 chanTbl[4] = { PAD_CHAN0_BIT, PAD_CHAN1_BIT, PAD_CHAN2_BIT, PAD_CHAN3_BIT }; extern int HuDvdErrWait; void HuPadInit(void) { int i; BOOL int_level; PADSetSpec(PAD_SPEC_5); PADInit(); SISetSamplingRate(0); int_level = OSDisableInterrupts(); VISetPostRetraceCallback(PadReadVSync); OSRestoreInterrupts(int_level); for(i=0; i<4; i++) { padStatErrOld[i] = PAD_ERR_NOT_READY; } VIWaitForRetrace(); VIWaitForRetrace(); HuPadRead(); for(i=0; i<4; i++) { if(_PadErr[i] == PAD_ERR_NONE) { PADControlMotor(i, PAD_MOTOR_STOP_HARD); } rumbleData[i].duration = 0; _PadRepCnt[i] = 0; } } void HuPadRead(void) { s16 i; for(i=0; i<4; i++) { HuPadBtn[i] = _PadBtn[i] & ~(PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_UP | PAD_BUTTON_DOWN); HuPadBtnDown[i] = _PadBtnDown[i] & ~(PAD_BUTTON_LEFT | PAD_BUTTON_RIGHT | PAD_BUTTON_UP | PAD_BUTTON_DOWN); HuPadStkX[i] = _PadStkX[i]; HuPadStkY[i] = _PadStkY[i]; HuPadSubStkX[i] = _PadSubStkX[i]; HuPadSubStkY[i] = _PadSubStkY[i]; HuPadTrigL[i] = _PadTrigL[i]; HuPadTrigR[i] = _PadTrigR[i]; HuPadDStk[i] = _PadDStk[i]; HuPadDStkRep[i] = _PadDStkRep[i]; HuPadErr[i] = _PadErr[i]; _PadBtnDown[i] = 0; } } static void PadReadVSync(u32 retraceCount) { u32 chan; s16 i; PADStatus status[4]; if(!HuDvdErrWait) { RumbleBit = PADRead(status); PADClamp(status); chan = 0; for(i=0; i<4; i++) { PADStatus *curr_status = &status[i]; PadRumble *rumble = &rumbleData[i]; if(padStatErrOld[i] && curr_status->err == PAD_ERR_NONE) { PADControlMotor(i, PAD_MOTOR_STOP_HARD); rumble->duration = 0; } padStatErrOld[i] = curr_status->err; if(curr_status->err != PAD_ERR_NONE) { _PadErr[i] = curr_status->err; if(curr_status->err != PAD_ERR_TRANSFER && curr_status->err != PAD_ERR_NOT_READY) { chan |= chanTbl[i]; } _PadBtnDown[i] = _PadBtn[i] = _PadStkX[i] = _PadStkY[i] = _PadSubStkX[i] = _PadSubStkY[i] = _PadTrigL[i] = _PadTrigR[i] = _PadDStkRep[i] = _PadDStk[i] = HuPadBtnRep[i] = 0; } else { u16 button = curr_status->button; if(curr_status->triggerL & 0xC0) { button |= 0x4000; } if(curr_status->triggerR & 0xC0) { button |= 0x2000; } if(button && _PadBtn[i] == button) { if(_PadRepCnt[i] > 20) { HuPadBtnRep[i] = button; } else { HuPadBtnRep[i] = 0; _PadRepCnt[i]++; } } else { _PadRepCnt[i] = 0; HuPadBtnRep[i] = button; } PadADConv(i, curr_status); _PadBtnDown[i] |= PADButtonDown(_PadBtn[i], button); _PadBtn[i] = button; _PadStkX[i] = curr_status->stickX; _PadStkY[i] = curr_status->stickY; _PadSubStkX[i] = curr_status->substickX; _PadSubStkY[i] = curr_status->substickY; _PadTrigL[i] = curr_status->triggerL; _PadTrigR[i] = curr_status->triggerR; _PadErr[i] = curr_status->err; if(rumble->duration) { s16 time = rumble->time%(rumble->off+rumble->on); if(time == 0) { PADControlMotor(i, PAD_MOTOR_RUMBLE); } else { if(time == rumble->off) { PADControlMotor(i, PAD_MOTOR_STOP); } } rumble->time++; if(rumble->time > rumble->duration) { PADControlMotor(i, PAD_MOTOR_STOP_HARD); rumble->duration = 0; } } } } if(chan) { PADReset(chan); } } msmSysRegularProc(); VCounter++; } static void PadADConv(s16 pad, PADStatus *status) { s16 stickX, stickY; s16 spA, sp8; spA = 0; sp8 = 0; stickX = abs(status->stickX); stickY = abs(status->stickY); _PadDStk[pad] = 0; if(stickY > 20) { if(status->stickY > 0) { _PadDStk[pad] |= PAD_BUTTON_UP; } else { _PadDStk[pad] |= PAD_BUTTON_DOWN; } } if(stickX > 30) { if(status->stickX < 0) { _PadDStk[pad] |= PAD_BUTTON_LEFT; } else { _PadDStk[pad] |= PAD_BUTTON_RIGHT; } } if(stickX+stickY < 20) { _PadDStkRepOld[pad] =0; } if(_PadDStkRepCnt[pad]) { _PadDStkRepCnt[pad]--; if(stickX+stickY < 20) { _PadDStkRepCnt[pad] = 0; } _PadDStkRep[pad] = 0; } else { _PadDStkRep[pad] = _PadDStk[pad]; if(_PadDStkRep[pad]) { if(_PadDStkRepOld[pad] == _PadDStkRep[pad]) { _PadDStkRepCnt[pad] = 2; } else { _PadDStkRepCnt[pad] = 20; } _PadDStkRepOld[pad] = _PadDStkRep[pad]; } } } void HuPadRumbleSet(s16 pad, s16 duration, s16 off, s16 on) { PadRumble *rumble = &rumbleData[pad]; if(_PadErr[pad] == PAD_ERR_NONE) { rumble->duration = duration; rumble->off = off; rumble->on = on; rumble->time = 0; } } void HuPadRumbleStop(s16 pad) { PadRumble *rumble = &rumbleData[pad]; if(_PadErr[pad] == PAD_ERR_NONE) { rumble->duration = 0; PADControlMotor(pad, PAD_MOTOR_STOP_HARD); } } void HuPadRumbleAllStop(void) { int i; for(i=0; i<4; i++) { rumbleData[i].duration = 0; if(_PadErr[i] == PAD_ERR_NONE) { PADControlMotor(i, PAD_MOTOR_STOP_HARD); } } } int HuPadStatGet(s16 pad) { return _PadErr[pad]; } u32 HuPadRumbleGet(void) { return RumbleBit; }