Javaのシリアルポート送受信を、イベントを用いた場合と、ユーザが無限ループを組んで行った場合、それぞれのCPU負荷を比較してみた。
検証環境
・Ubuntu 14.0 4LTS
・Java 8
・rxtxライブラリ version 2.1
CPU負荷測定結果
無限ループを用いた場合で、Readlineを用いた場合のCPU負荷
やはり、イベントを用いたほうが遥かにCPU負荷が低く、好ましい結果となっている
イベント serialEvent を用いた場合
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
/**
* シリアルポート送受信のテスト・クラス。受信イベントを用いてCPU負荷を低減した版
*
*/
public class main_class implements SerialPortEventListener {
private static CommPortIdentifier comID;
private static SerialPort commPort;
BufferedReader in;
private static BufferedReader br;
Boolean flagDispDisable = false;
/**
* このmain_classのコンストラクタ。 シリアルポートのデバイス名と通信速度のユーザ入力と、シリアルポートを開く処理
*/
public main_class() {
// シリアルポートのデバイス名と通信速度のユーザ入力
String commDeviceName = "/dev/ttyUSB0";
int commSpeed = 9600;
br = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.print("comデバイス名 (/dev/ttyUSB0) : ");
commDeviceName = br.readLine();
if (commDeviceName.length() < 1)
commDeviceName = "/dev/ttyUSB0";
System.out.print("通信速度 bps (9600) : ");
String strTemp = br.readLine();
if (strTemp.length() < 1)
commSpeed = 9600;
else
commSpeed = Integer.parseInt(strTemp);
if (commSpeed != 2400 && commSpeed != 4800 && commSpeed != 9600
&& commSpeed != 14400 && commSpeed != 19200)
commSpeed = 9600;
} catch (IOException e) {
e.printStackTrace();
System.out.println("\nkeyboard input error");
return;
}
// シリアルポートを開き、通信速度等を設定する
try {
comID = CommPortIdentifier.getPortIdentifier(commDeviceName);
commPort = (SerialPort) comID.open("dummy_app_name", 2000);
commPort.setSerialPortParams(commSpeed, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
commPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
} catch (Exception e) {
e.printStackTrace();
System.out.print("\ncomm port open error\n");
if (commPort != null)
commPort.close();
return;
}
// シリアルポートで発生するイベント処理の初期設定
try {
commPort.addEventListener(this);
commPort.notifyOnDataAvailable(true);
commPort.notifyOnBreakInterrupt(true);
// 指定したバイト以上受信したらEventを発生させる
commPort.enableReceiveThreshold(5);
// 指定したミリ秒が経過すれば強制的にEventを発生させる
commPort.enableReceiveTimeout(500);
} catch (Exception e) {
e.printStackTrace();
}
// シリアルポート受信側ストリームを開く
try {
in = new BufferedReader(new InputStreamReader(
commPort.getInputStream()));
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* ユーザのキーボード入力でシリアルポートに送信するループ
*/
private void main_loop() {
OutputStream outStream;
try {
// シリアルポート送信側ストリームを開く
outStream = commPort.getOutputStream();
while (true) {
// 端末で1行入力
String tmpStr = br.readLine();
// このプログラムを終了する
if (tmpStr.equalsIgnoreCase("quit")
|| tmpStr.equalsIgnoreCase("exit")
|| tmpStr.equalsIgnoreCase("q"))
break;
else if (tmpStr.length() < 1) {
// シリアルポートで受信したデータを表示するかどうかのトグル
flagDispDisable = !flagDispDisable;
if (flagDispDisable)
System.out
.println("(disp off) command -> quit, spdNNNN");
} else if (tmpStr.equalsIgnoreCase("spd4800")) {
// シリアルポートへの送信(通信速度設定)
outStream.write("spd4800\r".getBytes());
System.out.println("Send command \"speed 4800 bps\"");
} else if (tmpStr.equalsIgnoreCase("spd9600")) {
outStream.write("spd9600\r".getBytes());
System.out.println("Send command \"speed 9600 bps\"");
} else if (tmpStr.equalsIgnoreCase("spd19200")) {
outStream.write("spd19200\r".getBytes());
System.out.println("Send command \"speed 19200 bps\"");
} else if (tmpStr.equalsIgnoreCase("stop")) {
// シリアルポートへの送信(一時停止コマンド)
outStream.write("stop\r".getBytes());
System.out.println("Send command \"stop\"");
} else
System.out.println("command error");
}
System.out.print("exit read loop\n");
// シリアルポートの受信側ストリームを閉じる
in.close();
System.out.print("commPort BufferedReader is closed\n");
// シリアルポートの送信側ストリームを閉じる
outStream.close();
System.out.print("commPort OutputStream is closed\n");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
// シリアルポートを閉じる
commPort.close();
System.out.print("commPort is closed\n");
// キーボード入力を閉じる
br.close();
System.out.print("Keyboard input stream is closed\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* Javaプログラムの開始関数 main
*
* @param args
*/
public static void main(String[] args) {
System.out.println("シリアル通信(送受信) イベント利用版");
// クラスを初期化(シリアルポートを開く)
main_class serial_main = new main_class();
// ユーザのキーボード入力でシリアルポートに送信するループ
serial_main.main_loop();
}
/*
* シリアルポートで発生するイベント受信
*
* @see gnu.io.SerialPortEventListener#serialEvent(gnu.io.SerialPortEvent)
*/
@Override
public void serialEvent(SerialPortEvent arg0) {
if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
try {
// シリアルポートから1行(末尾改行)テキストを読み込み画面表示
String inputLine;
if ((in.ready()) && (inputLine = in.readLine()) != null) {
if (!flagDispDisable)
System.out.println(inputLine);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
無限ループを用いた場合
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import gnu.io.CommPortIdentifier;
import gnu.io.SerialPort;
/**
* シリアルポート送受信のテスト・クラス。受信イベントを用いず、ループ処理でCPU負荷が高い版
*
*/
public class main_class {
private static CommPortIdentifier comID;
private static SerialPort commPort;
private static BufferedReader br;
/**
* Javaプログラムの開始関数 main
*
* @param args
*/
public static void main(String[] args) {
System.out.println("シリアル通信(送受信) 受信無限ループ待ち版");
// シリアルポートのデバイス名と通信速度のユーザ入力
String commDeviceName = "/dev/ttyUSB0";
int commSpeed = 9600;
br = new BufferedReader(new InputStreamReader(System.in));
try {
System.out.print("comデバイス名 (/dev/ttyUSB0) : ");
commDeviceName = br.readLine();
if (commDeviceName.length() < 1)
commDeviceName = "/dev/ttyUSB0";
System.out.print("通信速度 bps (9600) : ");
String strTemp = br.readLine();
if (strTemp.length() < 1)
commSpeed = 9600;
else
commSpeed = Integer.parseInt(strTemp);
if (commSpeed != 2400 && commSpeed != 4800 && commSpeed != 9600
&& commSpeed != 14400 && commSpeed != 19200)
commSpeed = 9600;
} catch (IOException e) {
e.printStackTrace();
System.out.println("\nkeyboard input error");
return;
}
// シリアルポートを開き、通信速度等を設定する
try {
comID = CommPortIdentifier.getPortIdentifier(commDeviceName);
commPort = (SerialPort) comID.open("dummy_app_name", 2000);
commPort.setSerialPortParams(commSpeed, SerialPort.DATABITS_8,
SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
commPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
} catch (Exception e) {
e.printStackTrace();
System.out.print("\ncomm port open error\n");
if (commPort != null)
commPort.close();
return;
}
// シリアルポートからの受信を1行毎(Readline関数)を用いる場合
Receive_Readline();
// シリアルポートからの受信を1文字毎(Read関数)を用いる場合
// Receive_Read();
}
/**
* シリアルポートからの受信を1行毎(Readline関数)に画面表示し、 端末キーボードからの入力をシリアルポート側に送信する。
*/
private static void Receive_Readline() {
BufferedReader in;
OutputStream outStream;
Boolean flagDispDisable = false;
try {
// シリアルポート受信側ストリームを開く
in = new BufferedReader(new InputStreamReader(
commPort.getInputStream()));
// シリアルポート送信側ストリームを開く
outStream = commPort.getOutputStream();
// シリアルポート受信、端末キーボード入力の無限ループによる処理
String inputLine;
while (true) {
// シリアルポートから1行(末尾改行)テキストを読み込み画面表示
if ((in.ready()) && (inputLine = in.readLine()) != null) {
if (!flagDispDisable)
System.out.println(inputLine);
}
// 端末のキーボード入力を待ち、シリアルポート側へ送信する
if (br.ready()) {
String tmpStr = br.readLine();
// このプログラムを終了する
if (tmpStr.equalsIgnoreCase("quit")
|| tmpStr.equalsIgnoreCase("exit")
|| tmpStr.equalsIgnoreCase("q"))
break;
else if (tmpStr.length() < 1) {
// シリアルポートで受信したデータを表示するかどうかのトグル
flagDispDisable = !flagDispDisable;
if (flagDispDisable)
System.out
.println("(disp off) command -> quit, spdNNNN");
} else if (tmpStr.equalsIgnoreCase("spd4800")) {
// シリアルポートへの送信(通信速度設定)
outStream.write("spd4800\r".getBytes());
System.out.println("Send command \"speed 4800 bps\"");
} else if (tmpStr.equalsIgnoreCase("spd9600")) {
outStream.write("spd9600\r".getBytes());
System.out.println("Send command \"speed 9600 bps\"");
} else if (tmpStr.equalsIgnoreCase("spd19200")) {
outStream.write("spd19200\r".getBytes());
System.out.println("Send command \"speed 19200 bps\"");
} else if (tmpStr.equalsIgnoreCase("stop")) {
// シリアルポートへの送信(一時停止コマンド)
outStream.write("stop\r".getBytes());
System.out.println("Send command \"stop\"");
} else
System.out.println("command error");
}
}
System.out.print("exit read loop\n");
// シリアルポートの受信側ストリームを閉じる
in.close();
System.out.print("commPort BufferedReader is closed\n");
// シリアルポートの送信側ストリームを閉じる
outStream.close();
System.out.print("commPort OutputStream is closed\n");
} catch (IOException e) {
System.out.print("read error\n");
e.printStackTrace();
} finally {
try {
// シリアルポートを閉じる
commPort.close();
System.out.print("commPort is closed\n");
// キーボード入力を閉じる
br.close();
System.out.print("Keyboard input stream is closed\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* シリアルポートからの受信を1文字毎(Read関数)に画面表示し、 端末キーボードからの入力をシリアルポート側に送信する。
*/
private static void Receive_Read() {
BufferedReader in;
OutputStream outStream;
Boolean flagDispDisable = false;
try {
// シリアルポート受信側ストリームを開く
in = new BufferedReader(new InputStreamReader(
commPort.getInputStream()));
// シリアルポート送信側ストリームを開く
outStream = commPort.getOutputStream();
// シリアルポート受信、端末キーボード入力の無限ループによる処理
String inputLine = "";
int inputChar;
while (true) {
// シリアルポートから1行(末尾改行)テキストを読み込み画面表示
if ((in.ready()) && (inputChar = in.read()) != -1) {
// 受信すべき文字の範囲はASCII文字のみ
if (0x20 <= inputChar && inputChar <= 0x7e)
inputLine += (char) inputChar;
// 改行文字が来たら、また1行が256文字を超えれば画面表示
else if (inputChar == 0x0d || inputLine.length() >= 256) {
if (!flagDispDisable)
System.out.println(inputLine);
inputLine = "";
}
}
// 端末のキーボード入力を待ち、シリアルポート側へ送信する
if (br.ready()) {
String tmpStr = br.readLine();
// このプログラムを終了する
if (tmpStr.equalsIgnoreCase("quit")
|| tmpStr.equalsIgnoreCase("exit")
|| tmpStr.equalsIgnoreCase("q"))
break;
else if (tmpStr.length() < 1) {
// シリアルポートで受信したデータを表示するかどうかのトグル
flagDispDisable = !flagDispDisable;
if (flagDispDisable)
System.out
.println("(disp off) command -> quit, spdNNNN");
} else if (tmpStr.equalsIgnoreCase("spd4800")) {
// シリアルポートへの送信(通信速度設定)
outStream.write("spd4800\r".getBytes());
System.out.println("Send command \"speed 4800 bps\"");
} else if (tmpStr.equalsIgnoreCase("spd9600")) {
outStream.write("spd9600\r".getBytes());
System.out.println("Send command \"speed 9600 bps\"");
} else if (tmpStr.equalsIgnoreCase("spd19200")) {
outStream.write("spd19200\r".getBytes());
System.out.println("Send command \"speed 19200 bps\"");
} else if (tmpStr.equalsIgnoreCase("stop")) {
// シリアルポートへの送信(一時停止コマンド)
outStream.write("stop\r".getBytes());
System.out.println("Send command \"stop\"");
} else
System.out.println("command error");
}
}
System.out.print("exit read loop\n");
// シリアルポートの受信側ストリームを閉じる
in.close();
System.out.print("commPort BufferedReader is closed\n");
// シリアルポートの送信側ストリームを閉じる
outStream.close();
System.out.print("commPort OutputStream is closed\n");
} catch (IOException e) {
System.out.print("read error\n");
e.printStackTrace();
} finally {
try {
// シリアルポートを閉じる
commPort.close();
System.out.print("commPort is closed\n");
// キーボード入力を閉じる
br.close();
System.out.print("Keyboard input stream is closed\n");
} catch (IOException e) {
e.printStackTrace();
}
}
}
}

