はじめに
Unityでシリアル通信を行う時、だいたいの人はトラブルにぶつかるらしい。しかしどうもトラブルの原因や対処方法はOS、Unityのバージョン、通信対象の機器によって変わってくるように思える。
トラブルにぶつかった人が冷静に自分の状況を把握する助けになるよう、このページにいくつかの事項をまとめる。
ここに挙げられていないUnityのシリアル通信における事実をご存知の方は、ぜひ@tnayukiまでメンションしてほしい。
確定的な事項
いくつか確定的な事項をあげる。
API Compatibility Levelの変更
Unityからシリアル通信を行うSystem.IO.Ports.SerialPortクラスを使うためには、Player SettingsにあるAPI Compatibility Levelを.NET 2.0 Subsetから.NET 2.0に変更する必要がある。
これは.NET 2.0 SubsetにはSystem.IO.Ports.SerialPortクラスが含まれないため。
SerialPortクラスのOnDataReceivedイベントは呼ばれない
データを受信した場合に呼ばれるはずのOnDataReceivedイベントは決して呼ばれない。
これはUnityが使っているmonoのソースコードを検索するとわかる。誰もOnDataReceivedを呼んでいない。
未確定な事項
SerialPortクラスのBytesToReadプロパティはWindowsで正しい値を返さない
自分自身では確認していないが、SerialPortクラスのBytesToReadプロパティはWindowsでは正しい値を返さない、らしい。これと上の「OnDataReceivedイベントは呼ばれない」件が組み合わさることによって、別スレッドでポーリングする、短めのタイムアウトを設定してReadするなどのつらみが発生しているようだ。
Arduinoのシリアル通信はハードウェアフロー制御に対応していない
調査した限り、Arduinoのシリアル通信はハードウェアフロー制御(RTS/CTS)に対応していない。そのため、Arduino側の受信バッファを超えるデータをPCから送信/PC側の受信バッファを超えるデータをArduinoから送信するとデータが失われる(文字落ち)可能性があるのではないか。
ソフトウェアフロー制御(Xon/Xoff)に対応しているかは不明(自前で実装する必要がある?)。
また、DTRはファームウェア書き込み時にArduinoをリセットするために用いられているようだ。これだとうっかりPC側でDTRをオン(Lowレベル)にしてしまった場合、Arduinoがリセットされ、不安定な挙動になるのではないだろうか。