First Release

Dependencies:   USBDevice

Out_MD/Out_MD.cpp

Committer:
sankichi
Date:
2013-07-27
Revision:
1:6c392ebcd4d4
Parent:
0:e1265f6b3565

File content as of revision 1:6c392ebcd4d4:

#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();
    }
}