Androidでシリアル通信を利用する

#はじめに
Androidでシリアル通信をする方法があまり紹介されていないので記載します。

##対象機器
Android
REX-USB60MB (USB-シリアル変換)

##対象環境
Android6.0
AndroidStudio
Kotlin

##ダウンロード

FTDI社のホームページから**Java D2XX Update including FT4222H support**の項目にある**here**をクリックしてライブラリをダウンロードします。
[FTDI社のホームページ](https://www.ftdichip.com/Android.htm)

ダウンロードした圧縮ファイルを解凍します

**ルート**フォルダにある**d2xx.jar**ファイルのみ使用します。
**res/xml/**フォルダにある**device_filter.xml**は中身が古いので使わずに作ります。

##d2xx.jarをライブラリに追加
プロジェクトツリーの1番上**Android**と表示されている右の▼をクリックして表示される一覧から**プロジェクト**を選択します。
するとこれまでとは異なるツリー表示になります。

**app/libs** にd2xx.jarをドラッグアンドドロップで追加します。追加したd2xx.jarを右クリックして**ライブラリに追加**を実行します。
追加操作と言ってもbuild.grade(app)に**implementation files('libs/j2xx.jar')**が追加されるだけです。
ライブラリが不用になればこの1行を消して、libs/j2xx.jarを削除すれば元に戻ります。

d2xx.jarをライブラリに追加し終えたらプロジェクトツリーの1番上**プロジェクト**になっているのを右の▼をクリックして**Android**に戻しましょう。

##USBデバイスを使用する準備

Androidmanifest.xmlに

```manifest.xml
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
                <action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
            </intent-filter>
            <meta-data
                android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
                android:resource="@xml/device_filter" />
        </activity>
```
このようにしてUSBデバイスを使用するよう設定します。
**@xml/device_filter**は使っていませんが念のためです。

#認識されているか確認

```sample.kt
        var mFTDIManager = D2xxManager.getInstance(this.context)
        var deviceCount = mFTDIManager?.createDeviceInfoList(this.context) ?: 0
```

この2行で認識出来ているか確認します。
**deviceCount**が認識したデバイス数なので1以上が入っていれば成功です。

##REX-USB60MBが認識されない
サンプルを動作させた人はわかるかと思いますが、実はサンプルではREX-USB60MBを認識しません。
認識しない理由はさきほど古くて使うのを断念した**device_filter.xml**ファイルにあります。

```device-filter.xml
	<usb-device vendor-id="1412" product-id="45088" /> <!-- REX-USB60F -->
```

コメント通り**REX-USB60F**は登録されていますが**REX-USB60MB**はありません。
ではここにREX-USB60MBを定義すれば良いのでは？と思いましたがそれだとさらに上位の機種**RS-USB60FC**やタブレット用**REX-USB60MI**を使う時にまた変更が必要など使い勝手が悪くなります。

なので接続されているシリアル通信用デバイスを認識してそれを使うようにしようと思います。

```comm.kt
    var usbDevice = mutableMapOf<String,Any>()
    var usbDeviceList : MutableList<MutableMap<String,Any>> = mutableListOf()
        val manager = getSystemService<UsbManager>(context, UsbManager::class.java)
        usbDeviceList.clear()
        if (manager == null) return
        for(item in manager.deviceList) {
            val device: UsbDevice = item.value
            val str : String = device.manufacturerName ?: ""
            val vid = device.vendorId
            val pid = device.productId
            usbDevice = mutableMapOf("vid" to vid,"pid" to pid ,"key" to item.key,"name" to  str)
            usbDeviceList.add(usbDevice)
            mFTDIManager?.setVIDPID(vid,pid)
        }
```

USBのデバイスは**VendorID**と**ProductID**がわかれば動作するようですのでそれさえ得られれば大丈夫なのですが、そのデバイスが何なのかわからないと不安なので**manufacturerName**も取得出来るようにしています。

##使用するデバイスを登録する
使いたいデバイスが認識されないので手動で登録させます。

```sample.kt
        var mFTDIManager = D2xxManager.getInstance(this.context)
        mFTDIManager?.setVIDPID(1412,45115)
        var deviceCount = mFTDIManager?.createDeviceInfoList(this.context) ?: 0
```

**setVIDPID**の引数で**VendorID**と**ProductID**を渡すと強制的に認識させることができます。
**deviceCount**の値が1以上であれば成功です。
※1412,45115はREX-USB60MBの値です


##参考サイト
[参考サイト](
http://taizohobby.blog.fc2.com/blog-entry-89.html)