First Release

Dependencies:   USBDevice

Out_SSMulCon/Out_SSMulCon.cpp

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

File content as of revision 1:6c392ebcd4d4:

#include "NiseKabuto.h"

DigitalOut led1(LED1); 

//
// Constructor
//
Out_SSMulCon::Out_SSMulCon(
    PinName pn_D0, PinName pn_D1, PinName pn_D2, PinName pn_D3, 
    PinName pn_TL, PinName pn_TR, PinName pn_TH, 
    InputStatus *inputStatus)
    : _OUT_D0(pn_D0), _OUT_D1(pn_D1), _OUT_D2(pn_D2), _OUT_D3(pn_D3), 
      _INTR_TL(pn_TL), _INTR_TR(pn_TR), _OUT_TH(pn_TH)
{
    _InputStatus = inputStatus;
    Initialize();
}

//
// Initialize
//
void Out_SSMulCon::Initialize()
{
    
    // Pin Setting
    _INTR_TL.mode(PullUp);
    _INTR_TR.mode(PullUp);

    // Class Variable Setting
    RenewOutputMode();//_OutputMode = 0;
    _PhaseCounter = 0;
    _NowWriting = 0;
    _RapidFireValue = 1;
    
    // Interrupt Setting
    _INTR_TL.fall(this, &Out_SSMulCon::StrobeFallISR);
    _INTR_TL.rise(this, &Out_SSMulCon::StrobeRiseISR);
    _INTR_TR.fall(this, &Out_SSMulCon::ClockFallISR);
    _INTR_TR.rise(this, &Out_SSMulCon::ClockRiseISR);
    
    // Initialize pin status
    InitializePinStatus();

}

//
// Initialize pin status
//
void Out_SSMulCon::InitializePinStatus()
{
    SetD3D2D1D0(0,0,0,1);

    _OUT_TH = 1;
    
}

//
// ISR for S0/Strobe=L
//
void Out_SSMulCon::StrobeFallISR(void)
{
    if( _NowWriting != 1 )
    {
        /*
        // デジタル出力・アナログ出力を_IN_CONFIGによって決める
        _OutputMode = _IN_CONFIG;
        led1 = _OutputMode;
        */
        
        // データフェーズカウンタ初期化
        _PhaseCounter = 0;

        // ピン状態の設定(phase0向けデータ)
        //SetPinStatus();
        InitializePinStatus();
        SetPinStatus();
        
        // データ出力中
        _NowWriting = 1;
        
        DisableInput();
    }

    RenewOutputMode();
}

//
// ISR for S0/Strobe=H
//
void Out_SSMulCon::StrobeRiseISR(void)
{
    led1 = 0;
    
    // データフェーズカウンタ初期化
    _PhaseCounter = 0;
    
    // データ出力終了
    _NowWriting = 0;
    
    // ピン状態戻す
    InitializePinStatus();

    EnableInput();

    RenewOutputMode();
    
    _RapidFireValue=!_RapidFireValue;
}

//
// ISR for S1/Clock=L
//
void Out_SSMulCon::ClockFallISR(void)
{
    // データ出力中の場合のみ処理する
    if(_NowWriting==1)
    {
        // アナログ出力モード
        if( _OutputMode==OUTPUTMODE_ANALOG )
        {
            switch(_PhaseCounter)
            {
                case 0:
                case 2:
                case 4:
                case 6:
                case 8:
                case 10:
                case 12:
                case 14:
                    _PhaseCounter++;
                    break;
            }
        }
        // デジタル出力モード
        else
        {
            switch(_PhaseCounter)
            {
                case 0:
                case 2:
                case 4:
                case 6:
                    _PhaseCounter++;
                    break;
            }
        }
        SetPinStatus();
        _OUT_TH = 0;
    }
}

//
// ISR for S1/Clock=H
//
void Out_SSMulCon::ClockRiseISR(void)
{
    // データ出力中の場合のみ処理する
    if(_NowWriting==1)
    {
        // アナログ出力モード
        if( _OutputMode==OUTPUTMODE_ANALOG )
        {
            switch(_PhaseCounter)
            {
                case 1:
                case 3:
                case 5:
                case 7:
                case 9:
                case 11:
                case 13:
                    _PhaseCounter++;
                    break;
                case 15:
                    _PhaseCounter=0;
                    break;
            }
        }
        // デジタル出力モード
        else
        {
            switch(_PhaseCounter)
            {
                case 1:
                case 3:
                case 5:
                    _PhaseCounter++;
                    break;
                case 7:
                    _PhaseCounter=0;
                    break;
            }
        }

        SetPinStatus();
        _OUT_TH = 1;
    }
}


//
// Set Pin D3,D2,D1,D0 Status
//
void Out_SSMulCon::SetD3D2D1D0(char d3, char d2, char d1, char d0)
{
    _OUT_D0  = d0;
    _OUT_D1  = d1;
    _OUT_D2  = d2;
    _OUT_D3  = d3;
}

//
// Set Pin D3,D2,D1,D0 Status (bus)
//
void Out_SSMulCon::SetBus(char data)
{
    _OUT_D0  = data      & 0x01;
    _OUT_D1  = (data>>1) & 0x01;
    _OUT_D2  = (data>>2) & 0x01;
    _OUT_D3  = (data>>3) & 0x01;
}



//
// Set Pin Status
//
void Out_SSMulCon::SetPinStatus(void)
{
    // データ出力中の場合のみ処理する
    if(_NowWriting==1)
    {
        // Get InputStatus
        InputStatus *inp = _InputStatus;
        char chDat = 0;
        
        int buttons = _InputStatus->Buttons;
        char ch0 = _InputStatus->Ch0;
        char ch1 = _InputStatus->Ch1;
        char ch2 = _InputStatus->Ch2;
        char ch3 = _InputStatus->Ch3;
        
        char trigR;
        char trigL;
        
        // サイバースティック アナログ出力モード
        if( _OutputMode==OUTPUTMODE_ANALOG )
        {
            switch(_PhaseCounter)
            {
                case 0:
                case 1:
                    SetD3D2D1D0(0,0,0,1);
                    break;

                case 2:
                    SetD3D2D1D0(0,1,1,0);
                    break;

                case 3:
                    if(!(buttons & 0x01))   // G(SELECT)ボタンが押されてたら、アナログスティックで十字キー操作
                    {
                        SetD3D2D1D0
                        (
                            ch1>0xf0? 0:1,
                            ch1<0x0f? 0:1,
                            ch0>0xf0? 0:1,
                            ch0<0x0f? 0:1
                        );
                    }
                    else
                    {
                        SetD3D2D1D0(1,1,1,1);
                    }
                    break;

                case 4:
                    SetD3D2D1D0(
                        ((inp->Buttons) & 0x0002)?1:0,  // Start
                        ((inp->Buttons) & 0x0200)?1:0,  // A
                        ((inp->Buttons) & 0x0020)?1:0,  // C
                        ((inp->Buttons) & 0x0100)?1:0   // B
                    );
                    break;

                case 5:
                    trigR = 1;
                    if(!(buttons & 0x01))   // G(SELECT)ボタンが押されてたら、スロットルでRキー操作
                    {
                        trigR = ch2<0x0f? 0:1;  //スロットル引く
                    }

                    SetD3D2D1D0(
                        trigR,                          // R-Trigger
                        ((inp->Buttons) & 0x0010)?1:0,  // D is X
                        ((inp->Buttons) & 0x0008)?1:0,  // E1 is Y
                        ((inp->Buttons) & 0x0004)?1:0   // E2 is Z
                    );
                    break;

                case 6:
                    trigL = 1;
                    if(!(buttons & 0x01))   // G(SELECT)ボタンが押されてたら、スロットルでLキー操作
                    {
                        trigL = ch2>0xf0? 0:1;  //スロットル押す
                    }

                    SetD3D2D1D0(
                        trigL,  // L-Trigger
                        1,  // (H)
                        1,  // (H)
                        1   // (H)
                    );
                    break;

                case 7:
                    chDat = inp->Ch1;       // Upper4bits of axis-X
                    SetBus(chDat>>4);
                    break;

                case 8:
                    chDat = inp->Ch1;       // Lower4bits of axis-X
                    SetBus(chDat);
                    break;

                case 9:
                    chDat = inp->Ch0;       // Upper4bits of axis-Y
                    SetBus(chDat>>4);
                    break;

                case 10:
                    chDat = inp->Ch0;       // Lower4bits of axis-Y
                    SetBus(chDat);
                    break;

                case 11:
                    chDat = inp->Ch2;       // Upper4bits of throttle
                    SetBus(chDat>>4);
                    break;
                                    
                case 12:
                    chDat = inp->Ch2;       // Lower4bits of throttle
                    SetBus(chDat);
                    break;

                case 13:
                    SetD3D2D1D0(0,0,0,0);   // L Trigger Upper 4bits
                    break;

                case 14:
                    SetD3D2D1D0(0,0,0,0);   // L Trigger Lower 4bits
                    break;

                case 15:
                    SetD3D2D1D0(0,0,0,0);   // final phase
                    break;

            }
        }
        // サイバースティック デジタル出力モード
        else if( _OutputMode==OUTPUTMODE_DIGITAL )
        {
            switch(_PhaseCounter)
            {
                case 0:
                    SetD3D2D1D0(0,0,0,1);
                    break;
                    
                case 1:
                    SetD3D2D1D0(0,0,0,0);
                    break;

                case 2:
                    SetD3D2D1D0(0,0,1,0);
                    break;

                case 3:
                    SetD3D2D1D0(
                        ((inp->Buttons) & 0x0400)? 1 : 0,   // Right
                        ((inp->Buttons) & 0x0800)? 1 : 0,   // Left
                        ((inp->Buttons) & 0x1000)? 1 : 0,   // Down
                        ((inp->Buttons) & 0x2000)? 1 : 0    // Up
                    );

                    break;

                case 4:
                    // サイバースティックはStartボタンが無い縺ョで、Dで代用
                    SetD3D2D1D0(
                        (((inp->Buttons) & 0x0002)?1:0) & (((inp->Buttons) & 0x0010)?1:0),  // Start & D
                        ((inp->Buttons) & 0x0200)?1:0,  // A
                        ((inp->Buttons) & 0x0020)?1:0,  // C
                        ((inp->Buttons) & 0x0100)?1:0   // B
                    );
                    break;

                case 5:
                    SetD3D2D1D0(
                        ((inp->Buttons) & 0x8000)?1:0,  // R-Trigger(=ThrotUp)
                        ((inp->Buttons) & 0x0010)?1:0,  // X
                        ((inp->Buttons) & 0x0008)?1:0,  // Y
                        ((inp->Buttons) & 0x0004)?1:0   // Z
                    );
                    break;

                case 6:
                    SetD3D2D1D0(
                        ((inp->Buttons) & 0x4000)?1:0,  // L-Trigger
                        1,  // (H)
                        1,  // (H)
                        1   // (H)
                    );
                    break;

                case 7:
                    SetD3D2D1D0(0,0,0,0);
                    break;
            }
        }
        // 6B
        else if( _OutputMode==OUTPUTMODE_6B )
        {
            switch(_PhaseCounter)
            {
                case 0:
                    SetD3D2D1D0(0,0,0,1);
                    break;
                    
                case 1:
                    SetD3D2D1D0(0,0,0,0);
                    break;

                case 2:
                    SetD3D2D1D0(0,0,1,0);
                    break;

                case 3:
                    SetD3D2D1D0(
                        ((inp->Buttons) & 0x0400)? 1 : 0,   // Right
                        ((inp->Buttons) & 0x0800)? 1 : 0,   // Left
                        ((inp->Buttons) & 0x1000)? 1 : 0,   // Down
                        ((inp->Buttons) & 0x2000)? 1 : 0    // Up
                    );

                    break;

                case 4:
                    // modeキーが押されてたら、_RapidFireValue値を有効に
                    if( !((inp->Buttons) & 0x0001) )
                    {
                        SetD3D2D1D0(
                            ((inp->Buttons) & 0x0002)?1:0,  // Start
                            ((inp->Buttons) & 0x0200)?1:_RapidFireValue,    // A
                            ((inp->Buttons) & 0x0020)?1:_RapidFireValue,    // C
                            ((inp->Buttons) & 0x0100)?1:_RapidFireValue     // B
                        );
                    }
                    else
                    {
                        SetD3D2D1D0(
                            ((inp->Buttons) & 0x0002)?1:0,  // Start
                            ((inp->Buttons) & 0x0200)?1:0,  // A
                            ((inp->Buttons) & 0x0020)?1:0,  // C
                            ((inp->Buttons) & 0x0100)?1:0   // B
                        );
                    }
                    break;

                case 5:
                    // modeキーが押されてたら、_RapidFireValue値を有効に
                    if( !((inp->Buttons) & 0x0001) )
                    {
                        // Rトリガはmode+右
                        SetD3D2D1D0(
                            ((inp->Buttons) & 0x0401)?1:0,  // R-Trigger
                            ((inp->Buttons) & 0x0010)?1:_RapidFireValue,    // X
                            ((inp->Buttons) & 0x0008)?1:_RapidFireValue,    // Y
                            ((inp->Buttons) & 0x0004)?1:_RapidFireValue // Z
                        );
                    }
                    else
                    {
                        // Rトリガはmode+右  <-おかしい?
                        SetD3D2D1D0(
                            ((inp->Buttons) & 0x0401)?1:0,  // R-Trigger
                            ((inp->Buttons) & 0x0010)?1:0,  // X
                            ((inp->Buttons) & 0x0008)?1:0,  // Y
                            ((inp->Buttons) & 0x0004)?1:0   // Z
                        );
                    }
                    break;

                case 6:
                    // Lトリガはmode+左
                    SetD3D2D1D0(
                        ((inp->Buttons) & 0x0801)?1:0,  // L-Trigger
                        1,  // (H)
                        1,  // (H)
                        1   // (H)
                    );
                    break;

                case 7:
                    SetD3D2D1D0(0,0,0,0);
                    break;
            }
        }

    }
}


//
// Set output mode
//
void Out_SSMulCon::RenewOutputMode(void)
{
    switch(_InputStatus->InputDeviceType)
    {
        //
        // Input: CyberStick ANALOG mode
        //
        case NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG:
            _OutputMode = OUTPUTMODE_ANALOG;
            break;
            
        //
        // Input: CyberStick DIGITAL mode
        //        6B
        //
        case NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL:
            _OutputMode = OUTPUTMODE_DIGITAL;
            break;
            
        case NiseKabuto::CONFIG_INMODE_MD6B:
            _OutputMode = OUTPUTMODE_6B;
            break;

        default:
            _OutputMode = OUTPUTMODE_ANALOG;
            break;
    }
}


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

void Out_SSMulCon::EnableInput(void)
{
    if(_InputInstance && StartInputMethod)
    {
        (_InputInstance->*StartInputMethod)();
    }
    else if(StartInputFunction)
    {
        StartInputFunction();
    }
}

void Out_SSMulCon::DisableInput(void)
{
    if(_InputInstance && StopInputMethod)
    {
        (_InputInstance->*StopInputMethod)();
    }
    else if(StopInputFunction)
    {
        StopInputFunction();
    }
}