First Release

Dependencies:   USBDevice

Revision:
0:e1265f6b3565
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Out_MD/Out_MD.cpp	Sat Jul 27 14:05:47 2013 +0000
@@ -0,0 +1,755 @@
+#include "NiseKabuto.h"
+#include "CFunc_Out_MD.h"
+
+// 32Xスペハリのタイトルがおかしい問題
+// ・デジタルモードのとき、発生しない
+//   サイバースティック読み取りに原因??
+// ・Ack=Hのときにウェイトを入れても効果なし
+// ・Start押しっぱなし現象?
+// ⇒In_CSの読み取り中に割り込み禁止にすることで解決?
+
+// (Analog)ハングアップ問題;
+// この関数はメガドラからの要求の都度、呼ばれているのに、
+// _NowWritingが1のため、関数内に入らない問題
+// if(_AckCounter < 13) で直った?->だめ
+// (Analog)勝手にポーズ押しちゃう問題
+// 32Xスペハリ6面くらいまで進んだとき発生/何も操作しない状態で放置しても発生しない
+// ACK立ち上げ後のwait変えても効果なし
+// 入力クラスからは送られていない->メガドラへの送信フェーズずれた?
+//
+//  ⇒2件への対策として、Analog処理作り直し。データSetにTickerを使用しないようにする。
+//
+// (Analog)武者アレスタの動作がおかしい
+// サイバースティック読み取りルーチンの割り込み禁止のせいかも?
+
+//
+// Constructor
+//
+Out_MD::Out_MD(
+    PinName pn_D0, PinName pn_D1, PinName pn_D2, PinName pn_D3, 
+    PinName pn_LH, PinName pn_REQ, PinName pn_ACK,
+    InputStatus *inputStatus)
+      : _OUT_D0(pn_D0), _OUT_D1(pn_D1), _OUT_D2(pn_D2), _OUT_D3(pn_D3), _OUT_LH(pn_LH), _INTR_REQ(pn_REQ), _OUT_ACK(pn_ACK),
+        _DataBus(pn_D0, pn_D1, pn_D2, pn_D3)
+{
+    _InputStatus = inputStatus;
+    
+    Initialize();
+}
+
+//
+// Initialize
+//
+void Out_MD::Initialize()
+{
+    // Class Variable Setting
+    
+    // Pin Setting
+    _INTR_REQ.mode(PullUp);
+
+    // Reset Interrupt Setting
+    DisableModeChecker();
+    _INTR_REQ.fall(NULL);
+    _DigitalStateRenewTicker.detach();
+    _DigitalPeriodicPollingTicker.detach();
+    _InputMode = _InputStatus->InputDeviceType;
+    _SwapAC = 0;
+    _AnalogMUSHAMethod = 0;
+//  InitInterruptPriority();
+
+    switch(_InputMode)
+    {
+        //
+        // Input: CyberStick ANALOG mode
+        //
+        case NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG:
+            // Class Variable Setting
+            _TransferSpeed = TRANSFERSPEED_1_4__MICROSEC;   // もっとも遅い速度から開始
+        //  _TransferSpeed = TRANSFERSPEED_MAX__MICROSEC;   // 最速速度から開始
+            /*
+            if(
+                !((_InputStatus->Buttons) & 0x00003)    // Start+Selectが押されてる
+            )
+            {
+                _AnalogMUSHAMethod = 1;     // 武者アレスタ向けAnalog処理 有効
+            }
+            */
+
+            // Interrupt Setting
+            _INTR_REQ.fall(this, &Out_MD::ISR_Analog_ReqFall);
+
+            
+            // Initialize pin status
+            _OUT_D0  = 1;   
+            _OUT_D1  = 1;   
+            _OUT_D2  = 1;   
+            _OUT_D3  = 1;   
+            _OUT_LH  = 0;
+        //  _OUT_LH  = 1;   // 常にH版
+            _OUT_ACK = 1;   // output ACK = H
+            break;
+
+        //
+        // Input: CyberStick DIGITAL mode
+        // Input: MD6B
+        //
+        case NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL:
+        case NiseKabuto::CONFIG_INMODE_MD6B:
+        default:
+            if(
+                !((_InputStatus->Buttons) & 0x00020)    // Cが押されてる
+            )
+            {
+                _SwapAC = 1;
+            }
+
+            Cfunc_Out_MD_Initialize(
+                &_OUT_D0, &_OUT_D1, &_OUT_D2, &_OUT_D3,
+                &_OUT_LH, &_INTR_REQ, &_OUT_ACK,
+                &_ButtonStatus,
+                _SwapAC
+            );
+
+            EnableDigitalStateRenew();
+            RestartDigitalPeriodicPolling();
+            break;
+    }
+    
+    EnableModeChecker();
+}
+/*
+void Out_MD::InitInterruptPriority(void)
+{
+    // http://mbed.org/users/earlz/code/MbedConsole/file/370b9e559f92/main.cpp
+    
+    NVIC_SetPriority(NonMaskableInt_IRQn, 100 ); 
+    NVIC_SetPriority(MemoryManagement_IRQn, 100);
+    
+    NVIC_SetPriority(BusFault_IRQn, 100);
+    NVIC_SetPriority(UsageFault_IRQn, 100);
+    NVIC_SetPriority(SVCall_IRQn, 100);
+    NVIC_SetPriority(DebugMonitor_IRQn, 100);
+    NVIC_SetPriority(PendSV_IRQn, 100);
+    NVIC_SetPriority(SysTick_IRQn, 50);
+    NVIC_SetPriority(WDT_IRQn, 100);
+    NVIC_SetPriority(TIMER0_IRQn, 85);
+    NVIC_SetPriority(TIMER1_IRQn, 85);
+    NVIC_SetPriority(TIMER2_IRQn, 85);
+    NVIC_SetPriority(TIMER3_IRQn, 85);
+    NVIC_SetPriority(UART0_IRQn, 75);
+    NVIC_SetPriority(UART1_IRQn, 100);
+    NVIC_SetPriority(UART2_IRQn, 100);
+    NVIC_SetPriority(UART3_IRQn, 100);
+    
+    NVIC_SetPriority(PWM1_IRQn, 100);
+    NVIC_SetPriority(I2C0_IRQn, 100);
+    NVIC_SetPriority(I2C1_IRQn, 100);
+    NVIC_SetPriority(I2C2_IRQn, 100);
+    NVIC_SetPriority(SPI_IRQn, 100);
+    NVIC_SetPriority(SSP0_IRQn, 100);
+    NVIC_SetPriority(SSP1_IRQn, 100);
+    NVIC_SetPriority(PLL0_IRQn, 100);
+    NVIC_SetPriority(RTC_IRQn, 100);
+    NVIC_SetPriority(EINT0_IRQn, 100);
+    NVIC_SetPriority(EINT1_IRQn, 100);
+    
+    NVIC_SetPriority(EINT2_IRQn, 100);
+    NVIC_SetPriority(EINT3_IRQn, 0);    // 最高
+    NVIC_SetPriority(ADC_IRQn, 100);
+    NVIC_SetPriority(BOD_IRQn, 100);
+    NVIC_SetPriority(USB_IRQn, 100);
+    NVIC_SetPriority(CAN_IRQn, 100);
+    NVIC_SetPriority(DMA_IRQn, 100);
+    
+    NVIC_SetPriority(I2S_IRQn, 100);
+    NVIC_SetPriority(ENET_IRQn, 100);
+    NVIC_SetPriority(RIT_IRQn, 100);
+    NVIC_SetPriority(MCPWM_IRQn, 100);
+    NVIC_SetPriority(QEI_IRQn, 100);
+    NVIC_SetPriority(PLL1_IRQn, 100);
+    
+}
+*/
+
+
+//
+// Set output pin status
+//
+// Input:
+//   val: status of pins.  
+//   (MSB) ...|D3|D2|D1|D0| (LSB)
+//
+void Out_MD::SetPinValue(int val)
+{
+    // 意味ない
+    /*
+    _DataBus = val & 0x0f;
+    */
+    
+    _OUT_D0  = val & 0x01? 1 : 0;
+    _OUT_D1  = val & 0x02? 1 : 0;
+    _OUT_D2  = val & 0x04? 1 : 0;
+    _OUT_D3  = val & 0x08? 1 : 0;
+}
+
+
+
+
+
+//
+// 出力更新Ticker処理
+//
+void Out_MD::DigitalStateRenewMethod(void)
+{
+    
+    _ButtonStatus = _InputStatus->Buttons;
+
+    if( (_INTR_REQ) )
+    {
+        RenewDigitalPadStatus(1);
+    }
+    else
+    {
+        RenewDigitalPadStatus(0);
+    }
+
+}
+
+//
+// デジタルパッドの該当phaseのデータを出力
+//
+void Out_MD::RenewDigitalPadStatus(char phase)
+{
+
+    switch( phase )
+    {
+        case 0:
+            // phase0出力
+
+            // サイバースティックのデジタルモードではStartボタンは読み取れない
+            // (カブトガニは可能)
+            // MD Start
+            _OUT_ACK = ( (_ButtonStatus & 0x00010) ? 1 : 0 ); // Digital "D"
+
+            // MD A
+            if(_SwapAC)
+            {
+                _OUT_LH =( (_ButtonStatus & 0x00020) ? 1 : 0 ); // Digital "C"
+            }
+            else
+            {
+                _OUT_LH = ( (_ButtonStatus & 0x00200) ? 1 : 0 ); // Digital "A"
+            }
+            _OUT_D3 = ( 0 );
+            _OUT_D2 = ( 0 );
+
+            // MD Down
+            _OUT_D1 = ( (_ButtonStatus & 0x01000) ? 1 : 0 ); // Digital "Down"
+            // MD Up
+            _OUT_D0 = ( (_ButtonStatus & 0x02000) ? 1 : 0 ); // Digital "Up"
+            break;
+
+        case 1:
+            // phase1出力
+            
+            // MD C
+            if(_SwapAC)
+            {
+                _OUT_ACK = ( (_ButtonStatus & 0x00200) ? 1 : 0 ); // Digital "A"
+            }
+            else
+            {
+                _OUT_ACK =( (_ButtonStatus & 0x00020) ? 1 : 0 ); // Digital "C"
+            }
+            // MD B
+            _OUT_LH = ( (_ButtonStatus & 0x00100) ? 1 : 0 ); // Digital "B"
+            // MD Right
+            _OUT_D3 = ( (_ButtonStatus & 0x00400) ? 1 : 0 ); // Digital "Right"
+            // MD Left
+            _OUT_D2 = ( (_ButtonStatus & 0x00800) ? 1 : 0 ); // Digital "Left"
+            // MD Down
+            _OUT_D1 = ( (_ButtonStatus & 0x01000) ? 1 : 0 ); // Digital "Down"
+            // MD Up
+            _OUT_D0 = ( (_ButtonStatus & 0x02000) ? 1 : 0 ); // Digital "Up"
+            break;
+
+        default:
+            break;
+    }
+}
+
+
+
+//
+// 周期ポーリングの休みの間、デジタルパッド更新を行う/行わない
+//
+void Out_MD::EnableDigitalStateRenew(void)
+{
+    _DigitalStateRenewTicker.attach_us(
+        this, 
+        &Out_MD::DigitalStateRenewMethod, 
+        DIGITAL_STATE_RENEW_INTERVAL__MICROSEC
+    );
+}
+void Out_MD::DisableDigitalStateRenew(void)
+{
+    _DigitalStateRenewTicker.detach();
+}
+
+//
+// 周期ポーリングの開始(周期?のリセット)
+//
+void Out_MD::RestartDigitalPeriodicPolling(void)
+{
+    _DigitalPeriodicPollingTicker.detach();
+    
+    _DigitalPeriodicPollingTicker.attach_us(
+        this,
+        &Out_MD::DigitalPeriodicPollingMethod,
+        DIGITAL_PERIODICPOLLING_INTERVAL__MICROSEC
+    );
+}
+
+//
+// 周期ポーリング処理
+//
+void Out_MD::DigitalPeriodicPollingMethod(void)
+{
+    // 入力タイマ処理&休みの間の更新処理 止める
+    //  DisableInput();
+    //  DisableDigitalStateRenew();
+
+    // 割り込み禁止
+    __disable_irq();
+
+    Cfunc_DigitalPeriodicPollingMethod();
+
+    // 割り込み再開
+    __enable_irq();
+
+    
+    // 入力タイマ処理&休みの間の更新処理 再開
+    //  EnableDigitalStateRenew();
+    //  EnableInput();
+
+    RestartDigitalPeriodicPolling();
+
+}
+
+
+// 
+// InputStatusのデジタルモード・アナログモード切替を見張る
+//
+void Out_MD::EnableModeChecker(void)
+{
+    _ModeChecker.detach();
+    _ModeChecker.attach_us(
+        this,
+        &Out_MD::ModeCheckerMethod,
+        MODECHECK_INTERVAL__MICROSEC
+    );
+}
+
+void Out_MD::DisableModeChecker(void)
+{
+    _ModeChecker.detach();
+}
+
+void Out_MD::ModeCheckerMethod(void)
+{
+    // デジタル・アナログモードチェック
+    if(_InputStatus->InputDeviceType != _InputMode)
+    {
+        // モード変わってたら再Initialize
+        Initialize();
+    }
+}
+
+//
+// アナログスティック用:指定Phaseのデータを出力する
+//
+// 関数内部で_TransferSpeedを変化させている
+// 
+//
+void Out_MD::SetData_Analog_PhaseOf(char phase)
+{
+    // Get InputStatus
+    InputStatus *inp = _InputStatus;
+
+    // Set Data
+    switch(phase)
+    {
+        case 0:
+        // このとき、まだ1回目のAck立ち下げは行っていない
+            SetPinValue(
+                (((inp->Buttons) & 0x000c)) |       // E1E2
+                (((inp->Buttons) & 0x0003))         // FG
+            );
+            break;
+
+        case 1:
+        // 1回目のAck立ち下げ終了済み
+            SetPinValue(
+                (((inp->Buttons) & 0x0300) >> 6) |  // AB
+                (((inp->Buttons) & 0x0030) >> 4)    // CD
+            );
+            break;
+            
+        case 2:
+        // 2回目のAck立ち下げ終了済み
+            SetPinValue(
+                ((inp->Ch1) & 0x0f0) >> 4           // 2H
+//              0xff
+            );
+            // 最速モード
+            if(_INTR_REQ==1)
+            {
+                if(_TransferSpeed > TRANSFERSPEED_MAX__MICROSEC)
+                {
+                //  printf("MAX!!!");
+                    _TransferSpeed = TRANSFERSPEED_MAX__MICROSEC;
+                }
+            }
+            break;
+            
+        case 3:
+            SetPinValue(
+                ((inp->Ch0) & 0x0f0) >> 4           // 1H
+//              0xff
+            );
+            break;
+
+        case 4:
+            SetPinValue(
+                ((inp->Ch3) & 0x0f0) >> 4           // 4H
+            );
+
+            // 1/2倍速
+            if(_INTR_REQ==1)
+            {
+                if(_TransferSpeed > TRANSFERSPEED_1_2__MICROSEC)
+                {
+                //  printf("1/2!!!");
+                    _TransferSpeed = TRANSFERSPEED_1_2__MICROSEC;
+                }
+            }
+            break;
+
+        case 5:
+            SetPinValue(
+                ((inp->Ch2) & 0x0f0) >> 4           // 3H
+            );
+            break;
+
+        case 6:
+            SetPinValue(
+                (inp->Ch1) & 0x00f                  // 2L
+            );
+            // 1/3倍速
+            if(_INTR_REQ==1)
+            {
+                if(_TransferSpeed > TRANSFERSPEED_1_3__MICROSEC)
+                {
+                //  printf("1/3!!!");
+                    _TransferSpeed = TRANSFERSPEED_1_3__MICROSEC;
+                }
+            }
+            break;
+
+        case 7:
+            SetPinValue(
+                (inp->Ch0) & 0x00f                  // 1L
+            );
+            break;
+
+        case 8:
+            SetPinValue(
+                (inp->Ch3) & 0x00f                  // 4L
+            );
+
+            // 1/4倍速
+            // いらない気もする
+            if(_INTR_REQ==1)
+            {
+                if(_TransferSpeed >= TRANSFERSPEED_1_4__MICROSEC)
+                {
+                //  printf("1/4!!!");
+                    _TransferSpeed = TRANSFERSPEED_1_4__MICROSEC;
+                }
+            }
+            break;
+
+        case 9:
+            SetPinValue(
+                (inp->Ch2) & 0x00f                  // 3L
+                //カブトガニは固定値送ってるかも?
+                //0x0a
+            );
+            break;
+
+        case 10:
+            SetPinValue(0xff);
+            break;
+
+        case 11:
+            SetPinValue(
+                (((inp->Buttons) & 0x0300)  >> 6) |  // AB
+                (((inp->Buttons) & 0x00c0)) >>6     // A+A' B+B'
+            );
+            break;
+        
+        
+        default:
+            SetPinValue(0xff);
+            break;
+
+    }
+}
+
+//
+// ISR for REQ=L from Megadrive
+//
+void Out_MD::ISR_Analog_ReqFall()
+{
+    // 全体が間延び数現象の原因?
+    //  __disable_irq();    
+    
+    // デバッグ用:この関数が呼ばれるたび+1される
+    (_InputStatus->Temp[2])++;
+    
+    //
+    // from AJOY_SUB.DOC:
+    // --------------
+    //◆転送速度(各サイクルタイム)
+    //
+    //  ┌──────┬────┐
+    //  │ 最速モード │   50 │
+    //  │ 1/2倍速 │   96 │
+    //  │ 1/3倍速 │ 144 │
+    //  │ 1/4倍速 │ 192 │
+    //  └──────┴────┘
+    //      (単位:μsec)
+    // --------------
+    //  ジョイコンはデータ転送要求(割り込み)により
+    //  データ転送サイクルを6回繰り返す。
+    // --------------
+    //  
+    //  ↑ 以下のようなことを言いたかったのか?
+    //     ・サイバースティックは12回Ackが下がり、1回~11回目に
+    //       『◆アナログモード時のデータ』に沿ったデータを送る。
+    //       (12回目のデータは不明)
+    //     ・『データ転送サイクル』はAck2回分である(LHピンのLとHの組が1サイクル)
+    //     ・サイクルタイム=『データ転送サイクル』の周期
+    //
+    //  このように仮定すると、Ack1回分のデータは
+    //  サイクルタイム/2の間、保持していなければならないことになる。
+    //  なので、Ack1回分のデータを、サイクルタイム/2の周期で出力することとする。
+    //
+    // --------------
+    // AJOY.DOC
+    //※通信速度を最高速に設定した場合、アナログジョイスティックを
+    //  リセットしないかぎり、遅い速度への変更は行われない。
+    // --------------
+    // 本物は遅い方向には速度を変えさせない
+
+    char phase = 0;     // データPhase: 0からスタート
+    char savePhase;
+    int  us_Int1, us_Int2, us_Int3, us_Int4;
+
+    int time10, time1, time20, time2, time3, time4, time5, time6;
+
+    // 32Xスペハリ対策
+    // 待つ
+//  wait_us(40);
+    NiseKabuto::WaitUs(20);
+
+    // 現在の_TransferSpeedを元に、各時間を算出
+    us_Int1 = (int)(_TransferSpeed /12.5 );     // 速度MAX時:  4us
+    us_Int2 = (int)(_TransferSpeed / 8.3 );     // 速度MAX時:  6us
+    us_Int3 = (int)(_TransferSpeed / 4.17);     // 速度MAX時: 12us
+    us_Int4 = (int)(_TransferSpeed / 3.57);     // 速度MAX時: 14us
+
+    time10= us_Int1;
+    time20= us_Int4;
+
+    time1 = us_Int2;
+    time2 = us_Int3;
+    time3 = us_Int3;
+    time4 = us_Int1;
+    time5 = us_Int3;
+    time6 = us_Int1;
+    
+    // AckはHから開始
+    // LHはLから開始
+    _OUT_ACK = 1;
+    _OUT_LH = 0;
+    
+    
+    
+    // サイクルタイム6回分=phase0-12
+    
+    // 武者アレスタにおいて、サイクル2(phase2,3)のみ、値を送ると
+    // タイトル画面でボタンが押されてしまう不具合あり。
+    // このため、サイクル2は別のタイミングでデータを送付する。
+    // その直前のサイクル1も改める。
+
+
+
+    // サイクル1-6
+    for(int i=0; i<6; i++)
+    {
+        if(i==0)
+        {
+            // No1
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time10);
+
+            // No2
+            savePhase = phase;
+            SetData_Analog_PhaseOf(phase++);
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time20);
+        }
+        else
+        {
+            // No1
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time1-5);
+
+            // No2
+            savePhase = phase;
+            SetData_Analog_PhaseOf(phase++);
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time2);
+        }
+        
+        // No3
+        _OUT_ACK = 0;
+        _OUT_LH = 0;
+        NiseKabuto::WaitUs(time3);
+
+        // No4
+        _OUT_ACK = 1;
+        _OUT_LH = 1;
+        SetData_Analog_PhaseOf(phase++);
+        NiseKabuto::WaitUs(time4-3);
+
+        // No5
+        _OUT_ACK = 0;
+        _OUT_LH = 1;
+        NiseKabuto::WaitUs(time5);
+
+        // No6
+        _OUT_ACK = 1;
+        _OUT_LH = 1;
+        NiseKabuto::WaitUs(time6-1);
+        
+        // No7
+        _OUT_LH = 0;
+        SetData_Analog_PhaseOf(savePhase);
+    }
+/*  
+    // サイクル1-6
+    for(int i=0; i<6; i++)
+    {
+        if(i==0)
+        {
+            // No1
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time10-2);
+
+            // No2
+            savePhase = phase;
+            SetData_Analog_PhaseOf(phase++);
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time20-2);
+        }
+        else
+        {
+            // No1
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time1-3);
+
+            // No2
+            savePhase = phase;
+            SetData_Analog_PhaseOf(phase++);
+            _OUT_ACK = 1;
+            _OUT_LH = 0;
+            NiseKabuto::WaitUs(time2-2);
+        }
+        
+        // No3
+        _OUT_ACK = 0;
+        _OUT_LH = 0;
+        NiseKabuto::WaitUs(time3-1);
+
+        // No4
+        _OUT_ACK = 1;
+        _OUT_LH = 1;
+        SetData_Analog_PhaseOf(phase++);
+        NiseKabuto::WaitUs(time4-3);
+
+        // No5
+        _OUT_ACK = 0;
+        _OUT_LH = 1;
+        NiseKabuto::WaitUs(time5);
+
+        // No6
+        _OUT_ACK = 1;
+        _OUT_LH = 1;
+        NiseKabuto::WaitUs(time6-1);
+        
+        // No7
+        _OUT_LH = 0;
+        SetData_Analog_PhaseOf(savePhase);
+    }
+*/
+    _OUT_LH = 0;
+
+    // __enable_irq();  
+
+}
+
+
+
+
+
+
+
+void Out_MD::SetupInputControll(void (*startInputFunction)(void), void (*stopInputFunction)(void))
+{
+    StartInputFunction = startInputFunction;
+    StopInputFunction  = stopInputFunction;
+}
+
+void Out_MD::EnableInput(void)
+{
+    if(_InputInstance && StartInputMethod)
+    {
+        (_InputInstance->*StartInputMethod)();
+    }
+    else if(StartInputFunction)
+    {
+        StartInputFunction();
+    }
+}
+
+void Out_MD::DisableInput(void)
+{
+    if(_InputInstance && StopInputMethod)
+    {
+        (_InputInstance->*StopInputMethod)();
+    }
+    else if(StopInputFunction)
+    {
+        StopInputFunction();
+    }
+}
+