検証環境まとめ
windows8.1 64bit
jSCC 2.6 / Java1.7
仮想シリアルポート com0com 2.2.2.0
実シリアルポート USB-serial変換器
やりたいこと
シリアルポートを使ったアプリ+シリアル機器が、実際に送っている通信内容を覗き見したい。
具体的にはこのロボです。
KHR-2HV | 近藤科学
専用アプリからロボットを操作する方法と、コマンドリファレンス(通信プロトコル)は公開されているのですが、なかなか理解しずらいので、通信内容を覗いて理解を深めたい。(ということになりました、関わっている工業高校の研究にて。)
シリアル通信のモニタは、ソフトウェアにしてもハードウェアにしても結構お高い。自作できないのか考えてたところ Null-modem emulator(com0com)というよく知られた仮想シリアルポートがあることを知りました。これを利用して、仮想シリアルポートと実シリアルポートの間をのぞき見するプログラムを作ってみました。

仮想シリアルケーブル com0com をインストール
Null-modem emulator (com0com)
http://sourceforge.net/projects/com0com/
最新版のcom0com-3.0は全くインストールがうまくいかないので、version 2.2.2を使いました。
http://sourceforge.net/projects/com0com/files/com0com/2.2.2.0/
インストールはちょっと面倒で、Windows OS自体をテストモードにしないとcom0comがインストールできません。
こちらの手順どおりにインストールしました。設定方法なども参考になります。
NonSoft - com0comのインストールと設定方法(Windows8)
インストール後のシリアルポートはこうなります。

こっちがリアル。

仮想シリアルと実シリアルをつなぐ
次に COM12(仮想) と COM3(リアル) 間のシリアル通信プログラムをJavaで書きます。
古くからJavaのハードウェア通信といえばJava Communication API とその実装RXTXがありました(※)が、シリアル通信に限れば今はjava-simple-serial-connectorがかなりイケてるようです。
java-simple-serial-connector
APIがすっきりしていて、Java Native InterfaceにありがちなJRE環境汚染もなく、インストールは使いたいプロジェクトのCLASSPATHにjarを入れるだけ。
通信プログラムといっても、とりあえずは、それぞれのポートで受けたbyteを相手側に流してやるだけなので、こんな感じのコードになります。
import jssc.*;
public class SerialMonitor {
static SerialPort serialPort1;
static SerialPort serialPort2;
public static void main(String[] args) {
serialPort1 = new SerialPort("COM3");
serialPort2 = new SerialPort("COM12");
try {
serialPort1.openPort();
serialPort1.setParams(9600, 8, 1, 0);
serialPort1.addEventListener(new SerialPortReader1());
serialPort2.openPort();
serialPort2.setParams(9600, 8, 1, 0);
serialPort2.addEventListener(new SerialPortReader2());
} catch (SerialPortException ex) {
ex.printStackTrace();
}
}
// COM3 -> COM12 にデータを流す
static class SerialPortReader1 implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
try {
byte[] buffer = serialPort1.readBytes();
System.out.println(bin2hex(buffer));
serialPort2.writeBytes(buffer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
// COM12 -> COM3 にデータを流す
static class SerialPortReader2 implements SerialPortEventListener {
public void serialEvent(SerialPortEvent event) {
try {
byte buffer[] = serialPort2.readBytes();
serialPort1.writeBytes(buffer);
} catch (Exception e) {
e.printStackTrace();
}
}
}
static String bin2hex(byte[] data) {
StringBuffer sb = new StringBuffer();
for (byte b : data) {
String s = Integer.toHexString(0xff & b);
if (s.length() == 1) sb.append("0");
sb.append(s);
}
return sb.toString();
}
}
COM3 -> COM12 のデータを簡単にHEXダンプしてみました。
手元にあったシリアル機器として、Ciscoルーターがあったので、つないで、PuttyからCOM11を相手にコマンドたたいてみたところ。

正常に動いて、ダンプもうまくとれました。
ポート接続以外はただのI/Oプログラムなので、データ整形、マクロ化、ネットワークからシリアル叩く、シリアル機器の異常をメール通知する、などいろんなことができるはず。
(※)古くからRXTXというJava Communication APIの実装がありましたが、今は
本家がメンテされておらず、Fork版がこちらからダウンロードできるようです。
mfizz:RXTX for Java