First Release

Dependencies:   USBDevice

In_CyberStick/In_CyberStick.cpp

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

File content as of revision 1:6c392ebcd4d4:

#include "In_CyberStick.h"
#include "NiseKabuto.h"

DigitalOut led11(LED1); 
DigitalOut led22(LED2); 
DigitalOut dbgPin(p8); 

//
// Constructor
//
In_CyberStick::In_CyberStick(
    PinName pn_D0, PinName pn_D1, PinName pn_D2, PinName pn_D3, 
    PinName pn_LH, PinName pn_ACK, PinName pn_REQ,
    InputStatus *inputStatus
)  : _IN_D0(pn_D0), _IN_D1(pn_D1), _IN_D2(pn_D2), _IN_D3(pn_D3), _IN_LH(pn_LH), _IN_ACK(pn_ACK), _OUT_REQ(pn_REQ)
{
    _InputStatus = inputStatus;
    _InputStatus->Reset();  // ボタンなどリセット
    _InputStatus->InputDeviceType = NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG;    //とりあえずアナログにしておく

    _AnalogReadFailCounter = 0;

    Initialize();
}


void In_CyberStick::StartReading(void)
{
    //printf("In_CyberStick::StartReading()\r\n");
    if(!_ReadEnable)
    {
        _ReadEnable = 1;
        Initialize();
    }
}
void In_CyberStick::StopReading(void)
{
    //printf("In_CyberStick::StopReading()\r\n");
    if(_ReadEnable)
    {
        _ReadEnable = 0;
        DisablePolling();
    }
}



//
// Initialize
//
void In_CyberStick::Initialize()
{
    // Pin Setting
    _IN_D0.mode(PullUp);
    _IN_D1.mode(PullUp);
    _IN_D2.mode(PullUp);
    _IN_D3.mode(PullUp);
    _IN_LH.mode(PullUp);
    _IN_ACK.mode(PullUp);

    // Class Variable Setting
    _ReadEnable = 1;

    // Interrupt Setting
    // Initialize pin status
    _OUT_REQ = 1;   // output REQ = H

    // Ticker Setting
    EnablePolling();
}



//
// Enable polling
//
void In_CyberStick::EnablePolling(void)
{
    _PollingTicker.attach_us(this, &In_CyberStick::PollingMethod, REQUESTINTERVAL__MICROSEC);

    // FCAB 入力乱れ対策
    _ReadEnable = 1;
    _OUT_REQ = 1;  
}


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

    if(_ReadEnable)
    {

        // 割り込み停止しない
        //__disable_irq();  
        
        int waitLoop = 8000; //8000;//11300;//22600;
        char state = 1;
        char phase = 0;
        char cycle = 0;
        
        // Req下げ
        _OUT_REQ = 0;
        //wait_us(2);
        //_OUT_REQ = 1;

        cycle = 0;
        while( cycle<6 )
        {
            // LH=1の間待つ
            if(state)
            {
                while( _IN_LH )
                {
                    waitLoop--;
                    if(!waitLoop)
                    {
                        // TimeOut !
                        state = 0;
                        break;
                    }
                }
            }
            
            // ACK=1の間待つ
            if(state)
            {
                while( _IN_ACK )
                {
                    waitLoop--;
                    if(!waitLoop)
                    {
                        // TimeOut !
                        state = 0;
                        break;
                    }
                }
                
            }
            
            if(state)
            {
                // データ読み出し
                ReadPhase(phase++);
            }
            
            // LH=0の間待つ
            if(state)
            {
                while( !(_IN_LH) )
                {
                    waitLoop--;
                    if(!waitLoop)
                    {
                        // TimeOut !
                        state = 0;
                        break;
                    }
                }
            }
            
            // ACK=1の間待つ
            if(state)
            {
                // REQ立ち上げ
                // (最速モードのため、2回目のAck立下りまでに行う。このあたり?)
                _OUT_REQ = 1;

                while( _IN_ACK )
                {
                    waitLoop--;
                    if(!waitLoop)
                    {
                        // TimeOut !
                        state = 0;
                        break;
                    }
                }
            }

            if(state)
            {
                // データ読み出し
                ReadPhase(phase++);
            }
        
            if(!state)
            {
                break;
            }
            cycle++;
        }

        // 割り込み禁止しない
        //__enable_irq();
        
        if(state)
        {
            // ここまでstate==1のままで終わったら、完全にアナログスティックといえる
            _InputStatus->InputDeviceType = NiseKabuto::CONFIG_INMODE_CYBERSTICK_ANALOG;
            led11 = 1;

            // Analog読み失敗カウンタリセット
            _AnalogReadFailCounter = 0;

            //データ確定
            CommitAnalogData();
        }
        else
        {
        //  printf("_AnalogReadFailCounter: %d\r\n",_AnalogReadFailCounter);
            // 数回のAnalog読み失敗を許容
            //
            // 出力処理側のISRなどに割り込まれ、失敗するケースもある
            //
            //
            _AnalogReadFailCounter++;
            
            // この値を大きくすると、一時的なデジタルスティック化は避けられるが
            // DIGITAL/ANALOG切り替えスイッチへの追従が遅れる
            if(_AnalogReadFailCounter > 10)
            {
                // この時点でstate==0なら、未接続/デジタルモード
                _InputStatus->InputDeviceType = NiseKabuto::CONFIG_INMODE_CYBERSTICK_DIGITAL;
                led11 = 0;
                DigitalModeReader();
                
                if(_AnalogReadFailCounter>1000)
                {
                    _AnalogReadFailCounter = 10;
                }
            }
        }
    }
}


//
// Disable polling
//
void In_CyberStick::DisablePolling(void)
{
    _PollingTicker.detach();
    
    //Enable/DisableInput()を頻繁に呼ぶと、デジアナモード判定が乱れる問題対策
    if( _ReadEnable )
    {
    }
}



//
// デジタルモードでの読み取り処理
//
void In_CyberStick::DigitalModeReader(void)
{
    int btnData = _InputStatus->Buttons;
    
    // PC4=“0”
    _OUT_REQ = 0;
    wait_us(1);

    btnData = 
        (_IN_D0?   0x02000 : 0) |   // Up
        (_IN_D1?   0x01000 : 0) |   // Down
        (_IN_D2?   0x00800 : 0) |   // Left
        (_IN_D3?   0x00400 : 0) |   // Right
        (_IN_LH?   0x00200 : 0) |   // A
        (_IN_ACK?  0x00100 : 0) |   // B
        ((_IN_D2==0 && _IN_D3==0)? 0 : 0x02) |  // F(Start)
        ((_IN_D0==0 && _IN_D1==0)? 0 : 0x01) ;  // G(Select)

    /*
    // デジタルモードのとき、サイバースティックは
    // Start,Selectの情報は得られない。
    // カブトガニのF(Start),G(Select)については、
    // F=LR同時押し、G=UD同時押しとして認識される。
    */
    
    // PC4=“1”
    _OUT_REQ = 1;
    wait_us(1);

    btnData = btnData           |
        (_IN_D0?   0x08000 : 0) |   // Throt Up
        (_IN_D1?   0x04000 : 0) |   // Throt Down
        (_IN_D2?   0x00020 : 0) |   // C
        (_IN_D3?   0x00010 : 0) |   // D
        (_IN_LH?   0x00008 : 0) |   // E1
        (_IN_ACK?  0x00004 : 0) |   // E2
        0xc0;                       //A'B'は常にOFF

    _InputStatus->Buttons = btnData;
}

//
//ReadPinValue (Pin status -> Class value)
//
int In_CyberStick::ReadPinValue()
{
    return ( _IN_D0 | (_IN_D1<<1) | (_IN_D2<<2) | (_IN_D3<<3) );
}







//
// あるデータフェーズのデータを読み取り、格納
//
void In_CyberStick::ReadPhase(char phase)
{
    int readVal = ReadPinValue();
    
    switch(phase)
    {
        case 0:
            // Ack No.1
            _Buttons = 
                (_Buttons & 0xfffffccf) |       // mask bit9,8,5,4
                ((readVal & 0x0c)<<6) |         // AB(bit3 & 2)
                ((readVal & 0x03)<<4) ;         // CD(bit1 & 0)
            break;

        case 1:
            // Ack No.2
            _Buttons = 
                (_Buttons & 0xfffffff0) |       // mask bit3,2,1,0
                (readVal & 0x0f)      ;         // E1E2FG(bit3 & 2 & 1 & 0)
            break;

        case 2:
            // Ack No.3
            _Ch0 = 
                (_Ch0 & 0x0f) |                 // mask upper 4 bits
                (readVal & 0x0f)<<4   ;         // 1H(bit3 & 2 & 1 & 0)
            break;

        case 3:
            // Ack No.4
            _Ch1 = 
                (_Ch1 & 0x0f) |                 // mask upper 4 bits
                (readVal & 0x0f)<<4   ;         // 2H(bit3 & 2 & 1 & 0)
            break;

        case 4:
            // Ack No.5
            _Ch2 = 
                (_Ch2 & 0x0f) |                 // mask upper 4 bits
                (readVal & 0x0f)<<4   ;         // 3H(bit3 & 2 & 1 & 0)
            break;

        case 5:
            // Ack No.6
            _Ch3 = 
                (_Ch3 & 0x0f) |                 // mask upper 4 bits
                (readVal & 0x0f)<<4   ;         // 4H(bit3 & 2 & 1 & 0)
            break;

        case 6:
            // Ack No.7
            _Ch0 = 
                (_Ch0 & 0xf0) |                 // mask lower 4 bits
                (readVal & 0x0f)      ;         // 1L(bit3 & 2 & 1 & 0)
            break;

        case 7:
            // Ack No.8
            _Ch1 = 
                (_Ch1 & 0xf0) |                 // mask lower 4 bits
                (readVal & 0x0f)      ;         // 2L(bit3 & 2 & 1 & 0)
            break;

        case 8:
            // Ack No.9
            _Ch2 = 
                (_Ch2 & 0xf0) |                 // mask lower 4 bits
                (readVal & 0x0f)      ;         // 3L(bit3 & 2 & 1 & 0)
            break;

        case 9:
            // Ack No.10
            _Ch3 = 
                (_Ch3 & 0xf0) |                 // mask lower 4 bits
                (readVal & 0x0f)      ;         // 4L(bit3 & 2 & 1 & 0)
            break;

        case 10:
            // Ack No.11
            _Buttons = 
                (_Buttons & 0xffffff3f) |       // mask bit7,6
                ((readVal & 0x03)<<6) ;         // A+A', B+B'(bit1 & 0)
            break;

        default:
            break;
    }
}


//
// Analogスティック情報を確定
//
void In_CyberStick::CommitAnalogData(void)
{
    //サイバースティックアナログモードで使わないボタンをビット強制ON
    // ThrotUp |ThrotDw |   Up   |   Dw   ||   Lf   |   Rg
    _Buttons = (_Buttons) | 0x0000fc00;

    _InputStatus->Buttons = _Buttons;
    _InputStatus->Ch0 = _Ch0;
    _InputStatus->Ch1 = _Ch1;
    _InputStatus->Ch2 = _Ch2;
    _InputStatus->Ch3 = _Ch3;
}