Jetson TX1でPS3コントローラーを無線で利用する

# ツールのインストールと初期設定

以下はすべてJetsonのコンソールで行う。

依存関係をインストールしておく。

```bash
$ sudo apt-get install libusb-dev
```


ペアリング用ツールのソースコードをダウンロードして、コンパイルする。

```bash
$ wget http://www.pabr.org/sixlinux/sixpair.c
$ gcc -o sixpair sixpair.c -lusb
```
PS3コントローラーをJetsonに接続し、sixpairを実行する。

```bash
$ sudo ./sixpair 
Current Bluetooth master: 00:04:4b:79:99:55
Setting master bd_addr to 00:04:4b:79:99:55
```

qtsixaをビルドする。

```bash
$ git clone https://github.com/falkTX/qtsixa.git
$ cd qtsixa
```

依存関係のインストール。

```bash
$ sudo apt install python-qt4 pyqt4-dev-tools qt4-designer libjack-jackd2-dev libbluetooth-dev
```

ビルド＆インストール。

```bash
$ make
$ sudo make install
```
ペアリングする。
USBケーブルを抜いて、PS3コントローラを無線状態にする。
PS3コントローラーの後ろのリセットボタンを長押しして初期化する。
その後、下記コマンドを実行。

```bash
 $ sudo sixad -start &
sixad-bin[5850]: started
sixad-bin[5850]: sixad started, press the PS button now
```

PSボタンを押す。以下のメッセージが出て、PS3コントローラーが震えればペアリング成功。

```bash
sixad-sixaxis[6027]: Connected 'PLAYSTATION(R)3 Controller (04:98:F3:90:88:3A)' [Battery 04]
```

以下のコマンドを実行し、ボタンを押して何らかの出力があればOK。

```bash
$ sudo cat /dev/input/js0
```

sixadを起動時に常駐するようにする。

```bash
$ sudo vi /etc/rc.local
一番下に追加
sudo sixad -start &
```

# 検出処理

Qtでの使用例。

```joystick.h
#include <thread>
#include <QObject>

class JoyStick : public QObject
{
    Q_OBJECT

public:
    explicit JoyStick(std::string dev);
    ~JoyStick();
    enum ButtonEvent{
        Up = 4, Down = 6, Left = 7, Right = 5, Triangle = 12, X = 14, Square = 15, Circle = 13,
        L1 = 10, L2 = 8, L3 = 1, R1 = 11, R2 = 9, R3 = 2, Start = 0, Select = 3, PS = 16
    };
    enum AXISEvent{
        LStick_X = 0, LStick_Y, RStick_X, RStick_Y, Acc_X, Acc_Y, Acc_Z,
        UpPressure = 8, RightPressure, DownPressure, LeftPressure, L2Pressure, R2Pressure,
        L1Pressure, R1Pressure, TrianglePressure, CirclePressure, XPressure, SquarePressure
    };

private:
    void polling();
    void checkButton(unsigned char number, short value, ButtonEvent event);
    void checkAxis(unsigned char number, short value, AXISEvent event);
    int fd;
    std::thread th;

signals:
    void buttonPushed(ButtonEvent event);
    void buttonReleased(ButtonEvent event);
    void axisValueChanged(AXISEvent event, short value);
};
```

```joystick.cpp
#include <fcntl.h>
#include <unistd.h>
#include <linux/joystick.h>

JoyStick::JoyStick(std::string dev)
{
    fd = open(dev.c_str(), O_RDONLY);
    if(fd != -1)
    {
        // using non-blocking mode
        fcntl(fd, F_SETFL, O_NONBLOCK);

        th = std::thread(&JoyStick::polling, this);
        th.detach();
    }
}

JoyStick::~JoyStick()
{
    if(fd != -1) close(fd);
}

void JoyStick::checkButton(unsigned char number, short value, ButtonEvent event) {
    if(number == event)
    {
        if(value == 1)
        {
            emit buttonPushed(event);
        }
        else
        {
            emit buttonReleased(event);
        }
    }
}

void JoyStick::checkAxis(unsigned char number, short value, AXISEvent event) {
    if(number == event)
    {
        emit axisValueChanged(event, value);
    }
}

void JoyStick::polling()
{
    while(true)
    {
        js_event js;
        read(fd, &js, sizeof(js_event));
        switch (js.type & ~JS_EVENT_INIT)
        {
        case JS_EVENT_AXIS:
            checkAxis(js.number, js.value, AXISEvent::LStick_Y);
            checkAxis(js.number, js.value, AXISEvent::RStick_Y);
            break;
        case JS_EVENT_BUTTON:
            checkButton(js.number, js.value, ButtonEvent::Up);
            checkButton(js.number, js.value, ButtonEvent::Down);
            checkButton(js.number, js.value, ButtonEvent::Left);
            checkButton(js.number, js.value, ButtonEvent::Right);
            checkButton(js.number, js.value, ButtonEvent::Triangle);
            checkButton(js.number, js.value, ButtonEvent::X);
            checkButton(js.number, js.value, ButtonEvent::Square);
            checkButton(js.number, js.value, ButtonEvent::Circle);
            checkButton(js.number, js.value, ButtonEvent::L1);
            checkButton(js.number, js.value, ButtonEvent::L2);
            checkButton(js.number, js.value, ButtonEvent::L3);
            checkButton(js.number, js.value, ButtonEvent::R1);
            checkButton(js.number, js.value, ButtonEvent::R2);
            checkButton(js.number, js.value, ButtonEvent::R3);
            checkButton(js.number, js.value, ButtonEvent::Start);
            checkButton(js.number, js.value, ButtonEvent::Select);
            checkButton(js.number, js.value, ButtonEvent::PS);
            break;
        default:
            break;
        }
        usleep(1000);
    }
}
```


# 参考サイト

http://booting-rpi.blogspot.com/2012/08/dualshock-3-and-raspberry-pi.html
https://github.com/dusty-nv/turbo2
https://qiita.com/KurokoSin/items/f0f2de392d52821e7fa6
https://www.usagi1975.com/27jul172303/