First Release

Dependencies:   USBDevice

Out_PCE/Out_PCE.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_PCEDigital.h"

volatile char test = 0;

//extern "C" void mbed_reset();

//
// Constructor
//
Out_PCE::Out_PCE(
    PinName pn_1Y, PinName pn_2Y, PinName pn_3Y, PinName pn_4Y, 
    PinName pn_DSEL, PinName pn_ST, PinName pn_POWDETECT,
    InputStatus *inputStatus)
    : _OUT_1Y(pn_1Y), _OUT_2Y(pn_2Y), _OUT_3Y(pn_3Y), _OUT_4Y(pn_4Y), 
      _INTR_DSEL(pn_DSEL), _INTR_ST(pn_ST), _INTR_POWDETECT(pn_POWDETECT)
{
    _InputStatus = inputStatus;
    
    // OutputMode Initialize
    _OutputMode = _InputStatus->InputDeviceType;

    //printf("_OutputMode: %d(constructor)\r\n",_OutputMode);

//    InitInterruptPriority();
    Initialize();

}

//
// Initialize
//
void Out_PCE::Initialize()
{
    
    // Pin Setting
    _INTR_ST.mode(PullUp);
    _INTR_DSEL.mode(PullUp);
    _INTR_POWDETECT.mode(PullUp);

    // Class Variable Setting
    _PhaseCounter = 0;
    _NowWriting = 0;
    _DataSelectStatus = 1;
    _TransferSpeed = TRANSFERSPEED_MAX__MICROSEC;
    _RapidFireValue = 1;
    
    // Reset Interrupt Settings
    _INTR_ST.fall(NULL);
    _INTR_ST.rise(NULL);
    _INTR_DSEL.fall(NULL);
    _INTR_DSEL.rise(NULL);
    _PhaseChangeTicker.detach();
    _DigitalPadPhase0SetTicker.detach();
    _ModeCheckTicker.detach();

    // 入力デバイスにより場合わけ
    _OutputMode = _InputStatus->InputDeviceType;
    //printf("_OutputMode: %d(init)\r\n",_OutputMode);

    // ModeCheckTicker Setting
    _ModeCheckTicker.attach_us(this, &Out_PCE::ModeChecker, MODECHECKPERIOD__MICROSEC);

    switch(_OutputMode)
    {
        //
        // Input: CyberStick DIGITAL mode
        // Input: FightingPad 6B
        //
        case NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL:
        case NiseKabuto::CONFIG_INMODE_MD6B:
            Cfunc_PCEDigital_Initialize(
                &_OUT_1Y, 
                &_OUT_2Y, 
                &_OUT_3Y, 
                &_OUT_4Y, 
                &_INTR_DSEL, 
                &_INTR_ST, 
                _PhaseData, 
                &_RapidFireValue,
                &(_InputStatus->Temp[4])
            );
            
            
            // Ticker Setting
            _DigitalPadPhase0SetTicker.attach_us(
                this, 
                &Out_PCE::Digital_TickerMethod, 
                DIGITALPAD_STATERENEWINTERVAL__MICROSEC
            );
            
            EnableInput();
            
            SetOutputPinsValue(0x00);
            wait_us(5000);  // PCエンジンに気づかせる
            break;

        //
        // Input: CyberStick ANALOG mode
        //
        default:
        case NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG:

            // Interrupt Setting
            _INTR_ST.fall(this, &Out_PCE::StrobeFallISR);

            // Initialize pin status
            //SetOutputPinsValue(0x0f); // AfterBurner Boot時にRUN押されちゃう
            SetOutputPinsValue(0x02);   // 
            break;
        
    }
}


//
// Set Pins
//
void Out_PCE::SetOutputPinsValue(char dat)
{
    _OUT_1Y = dat & 1;
    _OUT_2Y = (dat & 2) >> 1;
    _OUT_3Y = (dat & 4) >> 2;
    _OUT_4Y = (dat & 8) >> 3;
}

//
// Set Pins2
//
void Out_PCE::SetOutputPinsValue2(char dat)
{
    // D0
    _OUT_1Y = dat & 1;          // D0
    // D1
    _OUT_2Y = (dat & 8) >> 3;   // D3
    // D2
    _OUT_3Y = (dat & 2) >> 1;   // D1
    // D3
    _OUT_4Y = (dat & 4) >> 2;   // D2
}

//
// ISR for Strobe=L
//
void Out_PCE::StrobeFallISR(void)
{
    //_PCEActiveCounter++;
    
    if( _NowWriting == 0)
    {
        _INTR_ST.fall(NULL);
        
        
        
        // Disableしないと、入力にまれにノイズがのる
        // Disable/Enable有る場合も無い場合も、しばらくすると入力が受け付けられなくなる
        // EnableInput()時にInitialize()を実行させるように修正
        
        //wait_us(_TransferSpeed>>1);   //AfterBurnerはこれで良かった.OutRun動かないかも?
                                    //wait_us(10);  //Outrun対策

        _NowWriting = 1;

        // データフェーズごとのデータ用意
        int buttons = _InputStatus->Buttons;
        char ch0    = _InputStatus->Ch0;
        char ch1    = _InputStatus->Ch1;
        char ch2    = _InputStatus->Ch2;
        char ch3    = _InputStatus->Ch3;

        // DisableInput();

        // |A|B|C|D
        _PhaseData[0] =
            (
                (((buttons) & 0x0200)?1:0)<<3 | // A
                (((buttons) & 0x0100)?1:0)<<2 | // B
                (((buttons) & 0x0020)?1:0)<<1 | // C
                (((buttons) & 0x0010)?1:0)      // D
            );
            
        // |E1|E2|F|G
        _PhaseData[1] =
            (
                (((buttons) & 0x0008)?1:0)<<3 | // E1
                (((buttons) & 0x0004)?1:0)<<2 | // E2
                (((buttons) & 0x0002)?1:0)<<1 | // F
                (((buttons) & 0x0001)?1:0)      // G
            );
            
        // 1H
        _PhaseData[2] = 
            ( ((ch0)>>4) & 0x0f );
            
        // 2H
        _PhaseData[3] = 
            ( ((ch1)>>4) & 0x0f );
            
        // 3H
        _PhaseData[4] = 
            ( ((ch2)>>4) & 0x0f );
            
        // 4H
        _PhaseData[5] = 
            ( 0x010 );
            
        // 1L
        _PhaseData[6] = 
            ( ch0 );
            
        // 2L
        _PhaseData[7] = 
            ( ch1 );
            
        // 3L
        _PhaseData[8] = 
            ( ch2 );
            
        // 4L
        _PhaseData[9] = 
            ( 0 );
            
        _PhaseData[10] = 
            // |A|B|A'|B'|
            (
                (((buttons) & 0x0200)?1:0)<<3 | // A
                (((buttons) & 0x0100)?1:0)<<2 | // B
                (((buttons) & 0x0080)?1:0)<<1 | // A'
                (((buttons) & 0x0040)?1:0)      // B'
            );
            
        _PhaseData[11] = (0x0f);

//      DisableInput();
        _PhaseChangeTicker.attach_us(this, &Out_PCE::ChangePhase, _TransferSpeed>>1);
    }
}


//
// Tickerにより呼ばれる処理
// PhaseCounterを変化
//
void Out_PCE::ChangePhase(void)
{
    int loopCounter=0;
    char state=1;
    
    // 一瞬だけ2Yを下げて
    SetOutputPinsValue( _PhaseCounter&1 );
    wait_us(2); //PCEがアナログモードになるwait_us値:10, 5, 3, 2

    // すぐデータ変更
    SetOutputPinsValue2( _PhaseData[_PhaseCounter] );

    // DSELがHになるまで待つ
    loopCounter=100;
    while(!(_INTR_DSEL))
    {
        loopCounter--;
        if(loopCounter<0)
        {
            state=0;
            break;
        }
    }
    
    if(state)
    {
        // DSELがLになるまで待つ
        loopCounter=100;
        while(_INTR_DSEL)
        {
            loopCounter--;
            if(loopCounter<0)
            {
                state=0;
                break;
            }
        }
    }

    if(state)
    {
        
        // その後、Ack出力に戻す
        SetOutputPinsValue( _PhaseCounter&1 | 0x02);

        _PhaseCounter++;
        
        //if(_PhaseCounter==12)
        if(_PhaseCounter>=11)
        {
            _PhaseCounter = 0;
            _PhaseChangeTicker.detach();
            SetOutputPinsValue(0x02);
            _NowWriting = 0;
//          EnableInput();
            _INTR_ST.fall(this, &Out_PCE::StrobeFallISR);
        }
    }
    else
    {
        _PhaseCounter = 0;
        _PhaseChangeTicker.detach();
        SetOutputPinsValue(0x02);
        _NowWriting = 0;
//      EnableInput();
        _INTR_ST.fall(this, &Out_PCE::StrobeFallISR);
    }

}



//
// Ticker method for digital pad output
//
// 1. 全phase用のデータを集め、クラス変数に保存
// 2. Phase0データを出力する
void Out_PCE::Digital_TickerMethod(void)
{
    // デバッグ用:この関数が呼ばれるたび+1される
    (_InputStatus->Temp[2])++;
    
    //printf("I\r\n");  // これがあるとhungup起きない?(1)
//  _InputStatus->Temp[0] = 1;
//  wait_us(14000);
    
    volatile int idx;

    // データフェーズごとのデータ用意
    __disable_irq();
    volatile int buttons = _InputStatus->Buttons;
    volatile char type = _InputStatus->InputDeviceType;
    __enable_irq();

    volatile int val_1a=0x0f;
    volatile int val_1b=0x0f;
    volatile int trgState_I  = 1;
    volatile int trgState_II = 1;

    if( type == NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL)
    {
        // 入力デバイス=サイバースティック/カブトガニ デジタルモード

        //  4Y  3Y  2Y 1Y
        //  L   D   R  U
        val_1a =
            (
                ((buttons & 0x0800) ? 0x08 : 0) |   // L
                ((buttons & 0x1000) ? 0x04 : 0) |   // D
                ((buttons & 0x0400) ? 0x02 : 0) |   // R
                ((buttons & 0x2000) ? 0x01 : 0)     // U
            );

        //  4Y  3Y  2Y 1Y
        // |Run|Sel|II|I
        val_1b =
            (
                ((buttons & 0x0002) ? 0x08 : 0)&((buttons & 0x0010) ? 0x08 : 0) |   // F(Start) & D
                ((buttons & 0x0001) ? 0x04 : 0)&((buttons & 0x0020) ? 0x04 : 0) |   // G(Sel,Mode) & C
                ((buttons & 0x0100) ? 0x02 : 0) |   // B
                ((buttons & 0x0200) ? 0x01 : 0)     // A
            );

    }
    else if (type == NiseKabuto::CONFIG_INMODE_MD6B)
    {
        // 入力デバイス=6B

        if( !(buttons & 0x020000) ) //Y
        {
            trgState_II = ((_RapidFireValue) ? 0x02 : 0);
        }
        else
        {
            trgState_II = ((buttons & 0x0100) ? 0x02 : 0); // B
        }
        if( !(buttons & 0x010000) ) //Z
        {
            trgState_I  = ((_RapidFireValue) ? 0x01 : 0);
        }
        else
        {
            trgState_I  = ((buttons & 0x0020) ? 0x01 : 0); // C
        }
            
        //  4Y  3Y  2Y 1Y
        //  L   D   R  U
        val_1a =
            (
                ((buttons & 0x0800) ? 0x08 : 0) |   // L
                ((buttons & 0x1000) ? 0x04 : 0) |   // D
                ((buttons & 0x0400) ? 0x02 : 0) |   // R
                ((buttons & 0x2000) ? 0x01 : 0)     // U
            );

        //  4Y  3Y  2Y 1Y
        // |Run|Sel|II|I
        val_1b =
            (
                ((buttons & 0x0002) ? 0x08 : 0) |   // F(Start)
                ((buttons & 0x0001) ? 0x04 : 0) |   // G(Sel,Mode)
                trgState_II |
                trgState_I
            );
        
        
    }
    
    __disable_irq();
    for(idx=0; idx<12; idx+=2)
    {
        //printf("idx:%d\r\n",idx);
        _PhaseData[idx  ] = val_1a;
        _PhaseData[idx+1] = val_1b;
    }
    __enable_irq();
    
    
//    //phase0データをset
//    Digital_SetDataOfPhase(0);
    

    //printf("O\r\n");  // これがあるとhungup起きない?(2)
//  _InputStatus->Temp[0] = 0;
//  wait_us(14000);

}


void Out_PCE::Digital_SetDataOfPhase(char phaseCounter)
{
    if( phaseCounter < 10 )
    {
        SetOutputPinsValue(_PhaseData[phaseCounter]);
    }
    else
    {
        SetOutputPinsValue(0x0f);
    }
    
}

void Out_PCE::ModeChecker(void)
{
    // デバッグ用:この関数が呼ばれるたび+1される
    (_InputStatus->Temp[5])++;

    __disable_irq();
    char curOutMode = _InputStatus->InputDeviceType;
    __enable_irq();
    
    // Analog/Digital切り替え判定
    if(_OutputMode != curOutMode)
    {
        _OutputMode = curOutMode;
    //  printf("InputDeviceType changed. Calling Initialize().\r\n");
        Initialize();
    }
}



void Out_PCE::SetupInputControll(void (*startInputFunction)(void), void (*stopInputFunction)(void))
{
    StartInputFunction = startInputFunction;
    StopInputFunction  = stopInputFunction;
}

void Out_PCE::EnableInput(void)
{
    //printf("Out_PCE::EnableInput() called!!");
    if(_InputInstance && StartInputMethod)
    {
        (_InputInstance->*StartInputMethod)();
    }
    else if(StartInputFunction)
    {
        StartInputFunction();
    }
}

void Out_PCE::DisableInput(void)
{
    //printf("Out_PCE::DisableInput() called!!");
    
    if(_InputInstance && StopInputMethod)
    {
        (_InputInstance->*StopInputMethod)();
    }
    else if(StopInputFunction)
    {
        StopInputFunction();
    }
}