First Release
Out_FC/C_Out_FC.cpp
- Committer:
- sankichi
- Date:
- 2013-07-27
- Revision:
- 1:6c392ebcd4d4
- Parent:
- 0:e1265f6b3565
File content as of revision 1:6c392ebcd4d4:
#include "mbed.h" #include "NiseKabuto.h" // InputDeviceType #include "C_Out_FC.h" // mbed pins DigitalOut led2_FC(LED2); DigitalOut led3_FC(LED3); InterruptIn *_INTR_LATCH; DigitalOut *_OUT_DATA; InterruptIn *_INTR_CLOCK; InterruptIn *_INTR_POWDETECT; // File local variables static volatile int *_pButtons; //PhaseData[12] static volatile char *_pCh0; static volatile char *_pCh1; static volatile char *_pCh2; static volatile char *_pInputDeviceType; static volatile char _Flag_NowOutput; static volatile char _PhaseCounter; static volatile char _SpeedType; static FunctionPointer *_fp_EnableInput; static FunctionPointer *_fp_DisableInput; static volatile char _RapidFireValue; static Ticker _RapidStateTicker; // Const variables static const int DIGITALPAD_SPEED_STARFORCE = 120; static const int DIGITALPAD_SPEED_RECCA = 75; static const int RAPIDFIRE_PER_SEC = 15; // 高橋名人連射速度-1 // File local functions static void ISR_Rise_LATCH_STARFORCE(void); // 遅い読み取りルーチン for スターフォース static void ISR_Rise_LATCH(void); // フツー static void ISR_Rise_LATCH_RECCA(void); // 速い読み取りルーチン for サマーカーニバル'92 烈火 //static void ISR_Rise_POWERDETECT(void); static void RenewData(void); static char CheckSpeedType(void); static int CheckOneReadTime(void); static void ConfigureSpeed(void); static void RapidStateTickerMethod(void); void C_Out_FC_Initialize( InterruptIn *intr_LATCH, DigitalOut *out_DATA, InterruptIn *intr_CLOCK, InterruptIn *intr_POWDETECT, volatile int *pButtons, volatile char *pCh0, volatile char *pCh1, volatile char *pCh2, volatile char *pInputDeviceType, FunctionPointer *pFunc_InputEnable, FunctionPointer *pFunc_InputDisable ) { // 入出力pin _INTR_LATCH = intr_LATCH; _OUT_DATA = out_DATA; _INTR_CLOCK = intr_CLOCK; _INTR_POWDETECT = intr_POWDETECT; // 割り込み設定 //_INTR_POWDETECT->rise(&ISR_Rise_POWERDETECT); // 電源ON/OFFでスピード切り替え判定を行う場合 led2_FC.write(0); // 初期:フツー led3_FC.write(1); // _INTR_LATCH->rise(&ISR_Rise_LATCH); // // 出力速度設定 ConfigureSpeed(); // ポインタ _pButtons = pButtons; _pCh0 = pCh0; _pCh1 = pCh1; _pCh2 = pCh2; _pInputDeviceType = pInputDeviceType; _fp_EnableInput = pFunc_InputEnable; _fp_DisableInput = pFunc_InputDisable; _Flag_NowOutput = 0; _RapidFireValue = 1; //_pTemp = pTemp; // 連射ステータス変更設定 _RapidStateTicker.attach_us(&RapidStateTickerMethod, (int)(1000000/(RAPIDFIRE_PER_SEC*2))); // Initialize pin status _PhaseCounter = 0; RenewData(); } void ISR_Rise_LATCH(void) { int loopCounter; // 止める if( (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG || (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL ) { (*_fp_DisableInput).call(); } // この関数開始時点で、phase0読み取り(DATAの立下り1回分)は // 終了しているものと仮定する // (mbedのピン割り込み時の反応速度は7usくらい) // // ただしMetalMaxでは。Latch立ち上がりから初回DATA立下りの間が // 6.5-7.0usくらいで微妙なので、 // 絶対にphase0から開始することを保証するため、ちょっと待つ wait_us(1); // Phase1に移行 _PhaseCounter=1; RenewData(); // Lの間待つ while( !(_INTR_CLOCK->read()) ) { loopCounter = 400; loopCounter--; if( !loopCounter ) { break; } } // 開始 for(int i=1; i<8; i++ ) { // Hの間待つ loopCounter = 5000; while( _INTR_CLOCK->read() ) { loopCounter--; if( !loopCounter ) { break; } } // Set data for current phase _PhaseCounter++; RenewData(); // Lの間待つ loopCounter = 200; while( !(_INTR_CLOCK->read()) ) { loopCounter--; if( !loopCounter ) { break; } } } _PhaseCounter = 0; RenewData(); // 再開 if( (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG || (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL ) { (*_fp_EnableInput).call(); } } void ISR_Rise_LATCH_RECCA(void) { // おまじない(Phase0を長引かせる) wait_us(2); // Phase1に移行 _PhaseCounter=1; RenewData(); // 開始 for(int i=1; i<8; i++ ) { wait_us(6); // Set data for current phase _PhaseCounter++; RenewData(); } _PhaseCounter = 0; RenewData(); } // 遅い読み取りルーチン void ISR_Rise_LATCH_STARFORCE(void) { int loopCounter; // 止める if( (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG || (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL ) { (*_fp_DisableInput).call(); } // Hの間待つ loopCounter = 5000; while( _INTR_CLOCK->read() ) { loopCounter--; if( !loopCounter ) { break; } } // Phase1に移行 _PhaseCounter=1; RenewData(); // Lの間待つ while( !(_INTR_CLOCK->read()) ) { loopCounter = 400; loopCounter--; if( !loopCounter ) { break; } } // 開始 for(int i=1; i<8; i++ ) { // Hの間待つ loopCounter = 5000; while( _INTR_CLOCK->read() ) { loopCounter--; if( !loopCounter ) { break; } } // Set data for current phase _PhaseCounter++; RenewData(); // Lの間待つ loopCounter = 200; while( !(_INTR_CLOCK->read()) ) { loopCounter--; if( !loopCounter ) { break; } } } _PhaseCounter = 0; RenewData(); // 再開 if( (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG || (*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL ) { (*_fp_EnableInput).call(); } } void RenewData(void) { switch(_PhaseCounter) { case 0: // // A // if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write(((*_pButtons) & 0x0100) ? 1 : 0); // Digital B } else if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_MD6B) //2:MD6B { // Zが押されてたら連射、押されてなかったらCの結果 if( ((*_pButtons) & 0x010000) ) // Z { // 真:押されてない _OUT_DATA->write(((*_pButtons) & 0x0020) ? 1 : 0); // Digital C } else { // 偽:押されてる _OUT_DATA->write(_RapidFireValue&1); } } else { _OUT_DATA->write(((*_pButtons) & 0x0100) ? 1 : 0); // Digital B } break; case 1: // // B // if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write(((*_pButtons) & 0x0200) ? 1 : 0); // Digital A } else if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_MD6B) //2:MD6B { // Yが押されてたら連射、押されてなかったらBの結果 if( ((*_pButtons) & 0x020000) ) // Y { // 真:押されてない _OUT_DATA->write(((*_pButtons) & 0x0100) ? 1 : 0); // Digital B } else { // 偽:押されてる _OUT_DATA->write(_RapidFireValue&1); } } else { _OUT_DATA->write(((*_pButtons) & 0x0200) ? 1 : 0); // Digital A } break; case 2: // // Select // if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write(((*_pButtons) & 0x0001) ? 1 : 0); // G(Sel,Mode) } else if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_MD6B) //2:MD6B { _OUT_DATA->write(((*_pButtons) & 0x0001) ? 1 : 0); // G(Sel,Mode) } else { _OUT_DATA->write(((*_pButtons) & 0x0020) ? 1 : 0); // Digital C } break; case 3: // // Start // if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write( ( ((*_pButtons) & 0x0002) ? 1 : 0) & // F(Start) ( (*_pCh2)>0xf0? 0:1 ) // スロットル引く ); //_OUT_DATA->write( ((*_pButtons) & 0x0002) ? 1 : 0) ); } else if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_MD6B) //2:MD6B { _OUT_DATA->write(((*_pButtons) & 0x0002) ? 1 : 0); // F(Start) } else { _OUT_DATA->write(((*_pButtons) & 0x0010) ? 1 : 0); // Digital C } break; case 4: // // Up // // ch1>0xf0? 0:1, // 右 // ch1<0x0f? 0:1, // 左 // ch0>0xf0? 0:1, // 下 // ch0<0x0f? 0:1 // 上 // ch2>0xf0? 0:1, // スロットル引く if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write((*_pCh0)<0x40? 0:1); } else { _OUT_DATA->write(((*_pButtons) & 0x2000) ? 1 : 0); } break; case 5: // // Down // if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write((*_pCh0)>0xb0? 0:1); } else { _OUT_DATA->write(((*_pButtons) & 0x1000) ? 1 : 0); } break; case 6: // // Left // if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write((*_pCh1)<0x40? 0:1); } else { _OUT_DATA->write(((*_pButtons) & 0x0800) ? 1 : 0); } break; case 7: // // Right // if((*_pInputDeviceType) == NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG) //サイバースティック(アナログ) { _OUT_DATA->write((*_pCh1)>0xb0? 0:1); } else { _OUT_DATA->write(((*_pButtons) & 0x0400) ? 1 : 0); } break; default: _OUT_DATA->write(1); // H } } // // ファミコンからの読み取り処理の長さを得る(1回分) // // return: // 0 = 読み取りが行えない(烈火の可能性がある) // 0以外 = 読み取り処理長さ[us] int CheckOneReadTime(void) { int retVal = 0; char stat = 1; int intLoopCounter; // ZanacはGunnac&MMに比べて2倍 Timer t; // Latch = Hまで待つ intLoopCounter = 500000; while( !(_INTR_LATCH->read()) ) { intLoopCounter--; if( !intLoopCounter ) { stat = 0; break; } } if(stat) { // 時刻計測開始 t.start(); // Clockが8回Lになることを確認 for(int i=0; i<8; i++ ) { intLoopCounter = 1000; while( _INTR_CLOCK->read() ) { intLoopCounter--; if( !intLoopCounter ) { stat = 0; break; } } intLoopCounter = 100; while( !(_INTR_CLOCK->read()) ) { intLoopCounter--; if( !intLoopCounter ) { break; } } } } if(stat) { t.stop(); retVal = t.read_us(); } return retVal; } // // SpeedTypeを判定する // // return: // 0 = 普通モード(普通のゲーム) // 1 = 高速モード(烈火) // 2 = 低速モード(スターフォース) // よくわからないときは0を返す char CheckSpeedType(void) { char retVal = 0; int readTime[8]; char counter_recca = 0; char counter_starforce = 0; // Dataは常にH _OUT_DATA->write(1); // 8回くらいチェックする for(int i=0; i<8; i++ ) { readTime[i] = CheckOneReadTime(); printf("readTime[%d]: %d\r\n",i,readTime[i]); } // 個別の結果判定 for(int i=0; i<8; i++ ) { if( readTime[i]>DIGITALPAD_SPEED_STARFORCE ) { counter_starforce++; } else if( readTime[i]<DIGITALPAD_SPEED_RECCA ) { counter_recca++; } else { } } // 判定 if(counter_starforce >= 4) { retVal = 2; } else if(counter_recca >= 4) { retVal = 1; } return retVal; } // // Configure speed setting // void ConfigureSpeed(void) { char speed; // ISR登録解除 _INTR_LATCH->rise(0); // ちょっと待つ wait_ms(500); speed = CheckSpeedType(); // Interrupt Setting if( speed==1 ) { led2_FC.write(1); led3_FC.write(1); _INTR_LATCH->rise(&ISR_Rise_LATCH_RECCA); } else if( speed==2 ) { led2_FC.write(0); led3_FC.write(0); _INTR_LATCH->rise(&ISR_Rise_LATCH_STARFORCE); } else { led2_FC.write(0); led3_FC.write(1); _INTR_LATCH->rise(&ISR_Rise_LATCH); } } // // ISR for POWERDETECT L->H // void ISR_Rise_POWERDETECT(void) { ConfigureSpeed(); } void RapidStateTickerMethod(void) { _RapidFireValue = !_RapidFireValue; }