Communication Class and Controller Class (ControllerForMbed Class)

Dependencies:   SoftPWM

ControllerForMbed.cpp

Committer:
kikuchi8810
Date:
2021-12-22
Revision:
0:a33375289d79

File content as of revision 0:a33375289d79:

//宇井コンとの通信をmbedで行えるように変更を加えたクラスでプロジェクトに公開していない.
#include "ControllerForMbed.h"

ControllerForMbed::ControllerForMbed(PinName tx, PinName rx, int baudrate) : serial(tx, rx, baudrate)
{
    conData.ButtonState = 0;
    conData.RJoyX = 127, conData.RJoyY = 127, conData.LJoyX = 127, conData.LJoyY = 127;

    lastButtonState = 0;

    comCheck = false;
    conAvailable = false;
    time_out_ms = -1;
}

void ControllerForMbed::init(int _time_out_ms, int _int_time_ms)
{
    time_out_ms = _time_out_ms;
    int_time_ms = _int_time_ms;
    //serial.attach(this, &Controller::update, Serial::RxIrq);
    //timer.start();
}

bool ControllerForMbed::update()
{
    //receptionTime = timer.read();
    static int count_ms = time_out_ms, pre_count_ms = 0; //受信時刻と前回の受信時刻

    char receive_data[10];
    unsigned int checksum = 0x00;
    comCheck = false;

#if CON_TYPE == CON_ADACHI // 安達君開発のコントローラを使う場合の処理(どのコントローラを使うかはdefine.hで設定)

    //while (loop_count < 10 && serial.readable())
    while (serial.readable())
    {
        static int recv_num = 0;
        char c = serial.getc();

        //if (serial_recieve() == '\n')
        if (c == '\n')
        {
            if(recv_num == 8)
            {   
                //for (int i = 0; i < 8; i++)
                   // receive_data[i] = serial_recieve();
                for (int i = 0; i < 8; i++)
                    receive_data[i] -= 0x20;
                for (int i = 0; i < 7; i++)
                    checksum ^= receive_data[i];

                if (receive_data[7] == checksum & 0xFF)
                {
                    comCheck = true;

                    //pre_conData.ButtonState = conData.ButtonState;
                    lastButtonState = ((receive_data[0] & 0x3F) << 2) | ((receive_data[1] & 0x30) >> 4);
                    conData.ButtonState |= lastButtonState;

                    conData.RJoyX = ((receive_data[1] & 0x0F) << 4) | ((receive_data[2] & 0x3C) >> 2);
                    conData.RJoyY = ((receive_data[2] & 0x03) << 6) | (receive_data[3] & 0x3F);
                    conData.LJoyX = ((receive_data[4] & 0x3F) << 2) | ((receive_data[5] & 0x30) >> 4);
                    conData.LJoyY = ((receive_data[5] & 0x0F) << 4) | (receive_data[6] & 0x0F);

                    pre_count_ms = count_ms; //受信時間の更新
                    if(pre_count_ms > int_time_ms * 1000) pre_count_ms = count_ms = 0; //オーバーフロー対策
                }
            }
            recv_num = 0;
        }
        else
        {
            receive_data[recv_num] = c;
            recv_num++;
        }
        
    }

#elif CON_TYPE == CON_ELECOM // ELECOMのコントローラを使う場合の処理(どのコントローラを使うかはdefine.hで設定)
    // コントローラデータを取得する部分
    static int recv_num = 0;
    char c;
    while (serial.readable())
    {
        c = serial.getc();
        if (c == '\n')
        {
            if (recv_num == 10)
            { // チェックサムは無く,9個受信したら値を格納
                for (int i = 0; i < 9; i++)
                    checksum += (unsigned int)(receive_data[i] - 0x20); // チェックサムの計算
                if ((checksum & 0x3F) == (receive_data[9] - 0x20))
                { // チェックサムの計算が合っていた場合のみ値を格納
                    comCheck = true;

                    //conData.ButtonState = 0;
                    conData.LJoyX = 0, conData.LJoyY = 0, conData.RJoyX = 0, conData.RJoyY = 0;
                    lastButtonState = (unsigned int)(receive_data[0] - 0x20);
                    lastButtonState |= (unsigned int)(receive_data[1] - 0x20) << 6;
                    lastButtonState |= (unsigned int)(receive_data[2] - 0x20) << 12;

                    conData.LJoyX |= (unsigned int)(receive_data[3] - 0x20);
                    conData.LJoyX |= (unsigned int)((receive_data[4] - 0x20) & 0x03) << 6;
                    conData.LJoyX = abs(conData.LJoyX - 0xFF);

                    conData.LJoyY |= (unsigned int)((receive_data[4] - 0x20) & 0x3C) >> 2;
                    conData.LJoyY |= (unsigned int)((receive_data[5] - 0x20) & 0x0F) << 4;
                    conData.LJoyY = abs(conData.LJoyY - 0xFF);

                    conData.RJoyX |= (unsigned int)((receive_data[5] - 0x20) & 0x30) >> 4;
                    conData.RJoyX |= (unsigned int)((receive_data[6] - 0x20) & 0x3F) << 2;
                    conData.RJoyX = abs(conData.RJoyX - 0xFF);

                    conData.RJoyY |= (unsigned int)(receive_data[7] - 0x20);
                    conData.RJoyY |= (unsigned int)((receive_data[8] - 0x20) & 0x03) << 6;
                    conData.RJoyY = abs(conData.RJoyY - 0xFF);

                    int buttonPushNum = 0;
                    for (int i = 0; i < 16; i++)
                    {
                        buttonPushNum += (conData.ButtonState >> i) & 0x0001;
                    }
                    if (buttonPushNum > 5)
                    {
                        //conData.ButtonState = pre_conData.ButtonState;
                        comCheck = false;
                    }
                    else
                    {
                        conData.ButtonState |= lastButtonState;
                    }

                    pre_count_ms = count_ms; //受信時間の更新
                    if(pre_count_ms > int_time_ms * 1000) pre_count_ms = count_ms = 0; //オーバーフロー対策
                }
            }
            recv_num = 0;
        }
        else
        {
            receive_data[recv_num] = c;
            recv_num++;
        }
    }
#elif CON_TYPE == CON_DS4    // DualShock4を使う場合の処理(どのコントローラを使うかはdefine.hで設定)
    // コントローラデータを取得する部分
    static int recv_num = 0;
    char c;
    while (serial.readable())
    {
        c = serial.getc();
        //Serial.print(c);
        if (c == '\n')
        {
            if (recv_num == 10)
            { // データ数はチェックサム含めて10個(0~9)
                checksum = 0;
                for (int i = 0; i < 9; i++)
                    checksum ^= (unsigned int)(receive_data[i] - 0x20); // チェックサムの計算
                if ((checksum & 0x3F) == (receive_data[9] - 0x20))
                { // チェックサムの計算が合っていた場合のみ値を格納
                    comCheck = true;

                    //conData.ButtonState = 0;
                    conData.LJoyX = 0, conData.LJoyY = 0, conData.RJoyX = 0, conData.RJoyY = 0;
                    lastButtonState = (unsigned int)(receive_data[0] - 0x20) & 0x3F;
                    lastButtonState |= (unsigned int)((receive_data[1] - 0x20) & 0x3F) << 6;
                    lastButtonState |= (unsigned int)((receive_data[2] - 0x20) & 0x0F) << 12;

                    conData.LJoyX |= (unsigned int)(receive_data[3] - 0x20);
                    conData.LJoyX |= (unsigned int)((receive_data[4] - 0x20) & 0x03) << 6;
                    conData.LJoyX = abs(conData.LJoyX - 0xFF);

                    conData.LJoyY |= (unsigned int)((receive_data[4] - 0x20) & 0x3C) >> 2;
                    conData.LJoyY |= (unsigned int)((receive_data[5] - 0x20) & 0x0F) << 4;
                    conData.LJoyY = abs(conData.LJoyY - 0xFF);

                    conData.RJoyX |= (unsigned int)((receive_data[5] - 0x20) & 0x30) >> 4;
                    conData.RJoyX |= (unsigned int)((receive_data[6] - 0x20) & 0x3F) << 2;
                    conData.RJoyX = abs(conData.RJoyX - 0xFF);

                    conData.RJoyY |= (unsigned int)(receive_data[7] - 0x20);
                    conData.RJoyY |= (unsigned int)((receive_data[8] - 0x20) & 0x03) << 6;
                    conData.RJoyY = abs(conData.RJoyY - 0xFF);

                    // 通信ミスであり得ない数のボタン数押されていた場合に無視する処理
                    int buttonPushNum = 0;
                    for (int i = 0; i < 16; i++)
                    {
                        buttonPushNum += (lastButtonState >> i) & 0x0001;
                    }
                    if (buttonPushNum > 5)
                    {
                        //conData.ButtonState = pre_conData.ButtonState;
                        comCheck = false;
                    }
                    else
                    {
                        conData.ButtonState = lastButtonState & 0xFFFF;
                    }

                    pre_count_ms = count_ms; //受信時間の更新
                    if(pre_count_ms > int_time_ms * 1000) pre_count_ms = count_ms = 0; //オーバーフロー対策
                }
            }
            recv_num = 0;
        }
        else
        {
            receive_data[recv_num] = c;
            recv_num++;
        }
    }

#endif
    if(!(time_out_ms == -1)) conAvailable = (time_out_ms > (count_ms - pre_count_ms)); //タイムアウトとインターバルの比較
    else conAvailable = true;
    count_ms += int_time_ms; //経過時間の更新

    return comCheck;
}

bool ControllerForMbed::getComCheck(void)
{
    return comCheck;
}

bool ControllerForMbed::available(void)
{
    return conAvailable;
}

bool ControllerForMbed::readButton_bin(unsigned int ButtonNum)
{ //放しているときは0,押しているときは1
    return ((conData.ButtonState & (0x0001 << (ButtonNum - 1))) == (0x0001 << (ButtonNum - 1))) ? true : false;
}

int ControllerForMbed::readButton(unsigned int ButtonNum)
{ //放しているときは0,押しているときは1,押した瞬間は2,放した瞬間は-1
    int result = 0;
    if ((conData.ButtonState & (0x0001 << (ButtonNum - 1))) == (0x0001 << (ButtonNum - 1)))
        result += 2;
    if ((pre_conData.ButtonState & (0x0001 << (ButtonNum - 1))) == (0x0001 << (ButtonNum - 1)))
        result -= 1;
    return result;
}

unsigned int ControllerForMbed::getButtonState()
{
    return conData.ButtonState;
}

void ControllerForMbed::clearButtonState()
{
    pre_conData.ButtonState = conData.ButtonState;
}

ControllerData ControllerForMbed::getConData()
{
    return conData;
}

double ControllerForMbed::readJoyRX()
{
    if (conData.RJoyX == 127)
        return 0;
    return ((double)conData.RJoyX - 127.5) / 127.5;
}

double ControllerForMbed::readJoyRY()
{
    if (conData.RJoyY == 127)
        return 0;
    return ((double)conData.RJoyY - 127.5) / 127.5;
}

double ControllerForMbed::readJoyLX()
{
    if (conData.LJoyX == 127)
        return 0;
    return ((double)conData.LJoyX - 127.5) / 127.5;
}

double ControllerForMbed::readJoyLY()
{
    if (conData.LJoyY == 127)
        return 0;
    return ((double)conData.LJoyY - 127.5) / 127.5;
}

uint8_t ControllerForMbed::readJoyRXbyte()
{
    return conData.RJoyX;
}

uint8_t ControllerForMbed::readJoyRYbyte()
{
    return conData.RJoyY;
}

uint8_t ControllerForMbed::readJoyLXbyte()
{
    return conData.LJoyX;
}

uint8_t ControllerForMbed::readJoyLYbyte()
{
    return conData.LJoyY;
}

unsigned int ControllerForMbed::getButtonFlagRise()
{
    // 立ち上がり,立下りのフラッギング処理 (フラグクリアは別関数で)
    unsigned int buttonFlagRise = 0;
    if (pre_conData.ButtonState != conData.ButtonState)
    {
        for (int i = 0; i < 16; i++)
        {
            int mask = 0x01 << i;
            if ((conData.ButtonState & mask) != (pre_conData.ButtonState & mask))
            {
                if ((conData.ButtonState & mask) == mask)
                    buttonFlagRise |= (conData.ButtonState & mask);
            }
        }
    }
    return buttonFlagRise;
}

unsigned int ControllerForMbed::getButtonFlagFall()
{
    unsigned int buttonFlagFall = 0;
    if (pre_conData.ButtonState != conData.ButtonState)
    {
        for (int i = 0; i < 16; i++)
        {
            int mask = 0x01 << i;
            if ((conData.ButtonState & mask) != (pre_conData.ButtonState & mask))
            {
                if ((pre_conData.ButtonState & mask) == mask)
                    buttonFlagFall |= (pre_conData.ButtonState & mask);
            }
        }
    }
    return buttonFlagFall;
}