/******************************************************************************** Ultra 64 MARIO Brothers motor pack control module Copyright 1996,1997 Nintendo co., ltd. All rights reserved June 2, 1997 ********************************************************************************/ #include "headers.h" #define NUM_SISEMAPHORES 1 #define NUM_MOTORMESGS 1 #define PRIORITY_MOTOR 30 static OSThread motorThread; static OSPfs pfs; static OSMesg siSemaphoreBuf[NUM_SISEMAPHORES]; static OSMesgQueue siSemaphoreQue; static OSMesg motorMessageBuf[NUM_MOTORMESGS]; static OSMesgQueue motorMessageQue; #define MTR_EVENT_NOMESG 0 #define MTR_EVENT_CONSTON 1 #define MTR_EVENT_LEVELON 2 typedef struct { uchar comm; uchar level; short time; short decay; } MotorEvent; typedef struct { short event; short level; short timer; short count; short start; short slip; short viblate; short decay; } MotorCtrl; static int motorActive = FALSE; static int motorPackOk = FALSE; static int motorError = 0; static MotorEvent motorEvent[3]; static MotorCtrl motorCtrl; int motorCounter = 0; ////////////////////////////////////////////////////////////////////////////////// // // // // SI semaphore control routines // // // /********************************************************************************/ /* */ /* Create si semaphore. */ /* */ /********************************************************************************/ extern void InitSiSemaphore(void) { osCreateMesgQueue(&siSemaphoreQue, siSemaphoreBuf, NUM_SISEMAPHORES); osSendMesg(&siSemaphoreQue, (OSMesg)0L, OS_MESG_NOBLOCK); } /********************************************************************************/ /* */ /* Get si access permission. */ /* */ /********************************************************************************/ extern void GetSiPermission(void) { OSMesg message; osRecvMesg(&siSemaphoreQue, &message, OS_MESG_BLOCK); } /********************************************************************************/ /* */ /* release si access permission. */ /* */ /********************************************************************************/ extern void RelSiPermission(void) { osSendMesg(&siSemaphoreQue, (OSMesg)0L, OS_MESG_NOBLOCK); } ////////////////////////////////////////////////////////////////////////////////// // // // // Motor control routines // // // /********************************************************************************/ /* */ /* Do motor on. */ /* */ /********************************************************************************/ static void DoMotorON(void) { if (motorPackOk) { GetSiPermission(); if (osMotorStart(&pfs) == 0) motorError = 0; else motorError += 1; RelSiPermission(); } } /********************************************************************************/ /* */ /* Do motor off. */ /* */ /********************************************************************************/ static void DoMotorOFF(void) { if (motorPackOk) { GetSiPermission(); if (osMotorStop(&pfs) == 0) motorError = 0; else motorError += 1; RelSiPermission(); } } /********************************************************************************/ /* */ /* Control motor on/off. */ /* */ /********************************************************************************/ static void ControlMotor(void) { if (sysHardwareReset > 0) { DoMotorOFF(); return; } if (motorCtrl.start > 0) { motorCtrl.start -= 1; DoMotorON(); } else if (motorCtrl.timer > 0) { motorCtrl.timer -= 1; if ((motorCtrl.level -= motorCtrl.decay) < 0) motorCtrl.level = 0; if (motorCtrl.event == MTR_EVENT_CONSTON) { DoMotorON(); } else { if (motorCtrl.count >= 0x100) { motorCtrl.count -= 0x100; DoMotorON(); } else { motorCtrl.count += (motorCtrl.level * motorCtrl.level * motorCtrl.level) / 512 + 4; DoMotorOFF(); } } } else { motorCtrl.timer = 0; if (motorCtrl.slip >= 5) { DoMotorON(); } else if (motorCtrl.slip >= 2 && (videoFrame % motorCtrl.viblate) == 0) { DoMotorON(); } else { DoMotorOFF(); } } if (motorCtrl.slip > 0) motorCtrl.slip -= 1; } /********************************************************************************/ /* */ /* Get motor event. */ /* */ /********************************************************************************/ static void GetMotorEvent(void) { if (motorEvent[0].comm != MTR_EVENT_NOMESG) { motorCtrl.count = 0; motorCtrl.start = 4; motorCtrl.event = motorEvent[0].comm; motorCtrl.timer = motorEvent[0].time; motorCtrl.level = motorEvent[0].level; motorCtrl.decay = motorEvent[0].decay; } motorEvent[0] = motorEvent[1]; motorEvent[1] = motorEvent[2]; motorEvent[2].comm = 0; } /********************************************************************************/ /* */ /* Send motor event. */ /* */ /********************************************************************************/ extern void SendMotorEvent(short time, short level) { if (autoDemoPtr == NULL) { if (level > 70) motorEvent[2].comm = MTR_EVENT_CONSTON; else motorEvent[2].comm = MTR_EVENT_LEVELON; motorEvent[2].level = level; motorEvent[2].time = time; motorEvent[2].decay = 0; } } /********************************************************************************/ /* */ /* Send motor event. */ /* */ /********************************************************************************/ extern void SendMotorDecay(short level) { motorEvent[2].decay = level; } /********************************************************************************/ /* */ /* Check motor event. */ /* */ /********************************************************************************/ extern int CheckMotorNoEvent(void) { if (motorCtrl.start + motorCtrl.timer > 3 ) return(FALSE); if (motorEvent[0].comm != MTR_EVENT_NOMESG) return(FALSE); if (motorEvent[1].comm != MTR_EVENT_NOMESG) return(FALSE); if (motorEvent[2].comm != MTR_EVENT_NOMESG) return(FALSE); return(TRUE); } /********************************************************************************/ /* */ /* Send motor event. */ /* */ /********************************************************************************/ extern void SendMotorSlip(void) { if (autoDemoPtr == NULL) { if (motorCtrl.slip == 0) motorCtrl.slip = 7; if (motorCtrl.slip <= 3) motorCtrl.slip = 4; motorCtrl.viblate = 7; } } /********************************************************************************/ /* */ /* Send motor event. */ /* */ /********************************************************************************/ extern void SendMotorVib(int level) { if (autoDemoPtr == NULL) { if (motorCtrl.slip == 0) motorCtrl.slip = 7; if (motorCtrl.slip <= 3) motorCtrl.slip = 4; if (level == 4) motorCtrl.viblate = 1; if (level == 3) motorCtrl.viblate = 2; if (level == 2) motorCtrl.viblate = 3; if (level == 1) motorCtrl.viblate = 4; if (level == 0) motorCtrl.viblate = 5; } } /********************************************************************************/ /* */ /* Send motor event. */ /* */ /********************************************************************************/ extern void SendMotorSwim(void) { if (autoDemoPtr == NULL) { motorCtrl.slip = 4; motorCtrl.viblate = 4; } } /********************************************************************************/ /* */ /* Motor main process. */ /* */ /********************************************************************************/ static void MotorProcess(void *arg) { OSMesg message; osSyncPrintf("start motor thread\n"); ResetMotorPack(); motorActive = TRUE; osSyncPrintf("go motor thread\n"); while (1) { osRecvMesg(&motorMessageQue, &message, OS_MESG_BLOCK); GetMotorEvent(); ControlMotor(); if (motorPackOk) { if (motorError >= 30) motorPackOk = FALSE; } else { if ((videoFrame % 60) == 0) { motorPackOk = (osMotorInit(&padMessageQ, &pfs, cont1p->contNo) == 0); motorError = 0; } } if (motorCounter > 0) motorCounter--; } } /********************************************************************************/ /* */ /* Motor main process. */ /* */ /********************************************************************************/ extern void ResetMotorPack(void) { motorPackOk = (osMotorInit(&padMessageQ, &pfs, cont1p->contNo) == 0); if (motorPackOk) osMotorStop(&pfs); motorEvent[0].comm = 0; motorEvent[1].comm = 0; motorEvent[2].comm = 0; motorCtrl.timer = 0; motorCtrl.slip = 0; motorCounter = 0; } /********************************************************************************/ /* */ /* Motor main process. */ /* */ /********************************************************************************/ extern void CreateMotorProcess(void) { osCreateMesgQueue(&motorMessageQue, motorMessageBuf, 1); osCreateThread(&motorThread, 6, MotorProcess, NULL, motorThreadStack+MAIN_STACKSIZE64, PRIORITY_MOTOR); osStartThread(&motorThread); } /********************************************************************************/ /* */ /* Send a retrace message to the motor thread. */ /* */ /********************************************************************************/ extern void SendMotorMessage(void) { if (motorActive) osSendMesg(&motorMessageQue, (OSMesg)'VRTC', OS_MESG_NOBLOCK); }