2005年10月27日

シリアル通信 その2 By直井

以前紹介したシリアル通信のサンプルプログラムを作ってみました。

import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.TooManyListenersException;
import java.util.Vector;
import javax.comm.CommPortIdentifier;
import javax.comm.NoSuchPortException;
import javax.comm.PortInUseException;
import javax.comm.SerialPort;
import javax.comm.SerialPortEvent;
import javax.comm.SerialPortEventListener;
import javax.comm.UnsupportedCommOperationException;
import javax.print.attribute.standard.Chromaticity;
public class SerialTranslator implements SerialPortEventListener {
    // SerialPort
    private SerialPort   serialport = null;
    private InputStream  in         = null;
    private OutputStream out        = null;
    /**
     * 
     */
    public SerialTranslator() {
        super();
    }
    public static void main(String[] args) {
        SerialTranslator trans = new SerialTranslator();
        trans.send();
        trans.close();
    }
    /* 
     * ASCIIデータを受信して表示する
     * ETX(0x02)をデータ送信終了コードとする仕様
     */
    public void serialEvent(SerialPortEvent event) {
        try {
            if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
                StringBuffer inputBuffer = new StringBuffer();
                int newData = 0;
                System.out.println("Serial Receive START->");
                while (true) {
                    try {
                        newData = in.read();// 入力ストリームから読み込み
                        if (newData == -1 || newData == 0x02) {// EOF or ETX?
                            System.out.println(inputBuffer+"<-END");
                            break;
                        }
                        if ('\r' == (char)newData) {
                            inputBuffer.append('\n');
                            System.out.print(inputBuffer);
                        } else {
                            inputBuffer.append((char)newData);
                        }
                    } catch (IOException ex) {
                        System.err.println(ex);
                        return;
                    }
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    /* 
     * シリアルポートを初期化した後
     * Key入力されたASCIIコードを送信する
     */
    public void send() {
        try {
            // Open new Serial Port.
            openSerialPort();
            BufferedReader keyin = new BufferedReader(new InputStreamReader(System.in));
            String keyString;
            while (true) {
                try {
                    // Key入力待ち
                    keyString = keyin.readLine();
                    // EXITと入力された場合は終了
                    if(keyString.equals("EXIT")){
                        break;
                    }
                    byte[] bytes = keyString.getBytes();
                    out.write(bytes);    // 出力ストリームにバイト列を書き込む
                    out.flush();        // 出力ストリームをフラッシュ
                }
                catch (Exception e) {
                    e.printStackTrace();
                    continue;
                }
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    /*
     * ストリーム、シリアルポートのクローズ処理
     */
    public void close() {
        try {
            if(in != null){
                in.close();
            }
            if(out != null){
                out.close();
            }
            if (serialport != null) {
                serialport.close();
            }
        }
        catch (Exception e) {
            e.printStackTrace();
        }
    }
    /**
     * シリアルポートの初期化
     * ポート:COM1
     * ボーレート:9600
     * データビット:8
     * ストップビット:1
     * パリティ:なし
     * フロー制御:なし
     */
    private void openSerialPort() {
        try{
            CommPortIdentifier port = CommPortIdentifier.getPortIdentifier("COM1");
            // ユニークな名前でシリアルポートを開く
            SerialPort serialPort = (SerialPort) port.open("SerialTranslator", 30000);
            // シリアルポートのパラメータを設定
            serialPort.setSerialPortParams(    9600,        // Baudrate
                            SerialPort.DATABITS_8,        // Data Bits
                            SerialPort.STOPBITS_1,        // Stop Bits
                            SerialPort.PARITY_NONE);    // Parity Bit
            // Flow Control Mode
            serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
            // イベントリスナー登録
            serialPort.addEventListener(this);
            // シリアルポートがデータを受信した際に教えてねと設定
            serialPort.notifyOnDataAvailable(true);
            // 入力ストリームを取得
            in = serialPort.getInputStream();
            // 出力ストリームを取得
            out = serialPort.getOutputStream();
        }
        catch (Exception e) {
            e.printStackTrace();
        } 
    }
    private void dumpBytes(byte[] data){
        for(int i = 0; i < data.length; i++){
            System.out.print("[" + Integer.toHexString(data[i]) + "]");
        }
        System.out.println();
    }
}

投稿者 Tsuda : 15:30 | コメント (0) | トラックバック

2005年08月16日

JAVA 「文字区切り処理」

アプリケーションを作成していると設定データやCSV形式(カンマ、タブ区切り)のデータを読み込んで処理することが多々あります。
その際につきものなのが文字区切りの処理です。
今回は文字区切り処理についていくつかのサンプルを紹介します。

まず、処理する文字列をCSV形式のタブ区切りで表した場合を今回のサンプルとします。
サンプルデータ->String sampleMoji = "文字 hoge hoge? "

1.思いっきり解析
JavaのAPIがよくわかりませんという方は文字列内からカンマを見つけて文字を抜き出すというロジックを組むでしょう。
String sampleMoji = "文字	hoge		hoge?	";
Vector moji = new Vector();
StringBuffer buf = new StringBuffer();
for(int idx=0; idx < sampleMoji.length() ; idx++){
  if(sampleMoji.charAt(idx) == '\t'){// sampleMoji.toCharArray()[idx] == '\t'でもいいよね
    moji.addElement(buf.toString());
    buf.delete(0,buf.length());
  }
  else{
    buf.append(sampleMoji.charAt(idx));
  }
}
System.out.println(moji.toString());

実行結果:[文字, hoge, , hoge?]
文字、hoge、なし、hoge?となる

2.インデックス処理
StringクラスのindexOf()とsubstring()を利用してもできます。
indexOf(探したい文字,開始位置) -> 見つかった文字の位置
substring(開始位置,終了位置) -> 指定した開始から終了までの文字
String sampleMoji = "文字	hoge		hoge?	";
Vector moji = new Vector();
for(int idx=0, idx2=0; idx < sampleMoji.length(); idx++){
  if((idx=sampleMoji.indexOf("\t",idx))<0){
    moji.addElement(sampleMoji.substring(idx2));
    break;
  }
  moji.addElement(sampleMoji.substring(idx2,idx));
  idx2 = idx+1;
}
System.out.println(moji.toString());

実行結果:[文字, hoge, , hoge?]
文字、hoge、なし、hoge?となる

3.トークン処理
StringTokenizerというクラスを利用したらなんかシンプルになったけど実行結果が少し違う。
String sampleMoji = "文字	hoge		hoge?	";
Vector moji = new Vector();
StringTokenizer tok = new StringTokenizer(sampleMoji,"\t");
while( tok.hasMoreTokens() ) {
  moji.addElement(tok.nextToken());
}
System.out.println(moji.toString());

実行結果:[文字, hoge, hoge?]
文字、hoge、hoge?となる

4.スプリット処理
ver1.4からStringクラスにsplit()っていうのがあるみたいなので利用した。いきなり区切り処理が終わって配列が返ってきます。
String sampleMoji = "文字	hoge		hoge?	";
Vector moji = new Vector();
String[] mojimoji = sampleMoji.split("\t");
for(int i=0; i < mojimoji.length; i++){
  moji.addElement(mojimoji[i]);
}
System.out.println(moji.toString());

実行結果:[文字, hoge, , hoge?]
文字、hoge、なし、hoge?となる

とまあこんな感じです。
文字の区切り処理といってもやり方がいろいろあるので試してみてください。

投稿者 Tsuda : 13:16 | コメント (0) | トラックバック

2005年06月02日

「シリアル通信」

私は現在は主にJavaを利用した比較的大規模なシステム構築に携わっています。
でもこのシステムは世で頻繁に使用されているWebシステムではありません。
さらにこのシステムはJavaでRS232C通信、Socket通信等を使用しています。
なぜなら対象が人間ではなくて装置であることが多いためにこのような構成を必要としているからです。

今回は私が経験した中で世間ではあまり使われていないであろうJavaによるRS232C通信について必要なライブラリー、サンプルを紹介します。

以下の話はJavaで開発できる環境が整っている前提で進めます。

実行するためには「Java Communication API」が必要です。
こちらからダウンロードして下さい
ダウンロードしたら配置手順に従って拡張ライブラリーを配置してください。

1.シリアルポートのオープン
 Java Communication APIにはシリアルポートを制御するクラスが用意されています。
 シリアルポートを利用するにはまずどのポートを利用するかを宣言してCommPortIdentifierオブジェクトを取得します。
 次に取得したCommPortIdentifierをOpenしてSerialPortクラスにキャストします。
 このままでも利用できますが各パラメータの設定方法も合わせて載せておきます。

CommPortIdentifier port = CommPortIdentifier.getPortIdentifier("COM1");
// ユニークな名前でシリアルポートを開く
SerialPort serialPort = (SerialPort) port.open("SerialPort", 30000);
// シリアルポートのパラメータを設定
serialPort.setSerialPortParams( 9600,                    // Baudrate
                                SerialPort.DATABITS_8,   // Data Bits
                                SerialPort.STOPBITS_1,   // Stop Bits
                                SerialPort.PARITY_NONE); // Parity Bit
                               // Flow Control Mode
                                serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);

2.入力/出力ストリーム
 ポートを開いただけではデータの送信/受信ができませんよね。
 データ送受信はストリームを介して行います。ファイルの読み書きのように扱えます。

// 入力ストリームを取得
in = serialPort.getInputStream();
// 出力ストリームを取得
out = serialPort.getOutputStream();

3.リスナー登録
 シリアルポートからのデータはリスナー登録することでイベントが飛んできます。
 インプリメントするリスナークラスはSerialPortEventListener。

// イベントリスナー登録
serialPort.addEventListener(this);
// シリアルポートがデータを受信した際に教えてねと設定
serialPort.notifyOnDataAvailable(true);

4.データ送信
 送信は先ほど取得した出力ストリームを使用して送信できます。

byte[] bytes = "送信テスト".getBytes();
out.write(bytes);	// 出力ストリームにバイト列を書き込む
out.flush();		// 出力ストリームをフラッシュ

5.データ受信
 受信はSerialPortEventListenerのserialEvent(SerialPortEvent)メソッドを実装。

public void serialEvent(SerialPortEvent arg0) {
    if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
        StringBuffer inputBuffer = new StringBuffer();
        int newData = 0;
        while (true) {
            try {
                newData = is.read();// 入力ストリームから読み込み
                if (newData == -1 || newData == 0x02) {// EOF or ETX?
                    break;
                }
                if ('\r' == (char)newData) {
                    inputBuffer.append('\n');
                } else {
                    inputBuffer.append((char)newData);
                }
            } catch (IOException ex) {
                System.err.println(ex);
                return;
            }
        }
    }
}

6.クローズ
 オープンしていたシリアルポート、ストリームはちゃんと閉じましょう。

in.close();
out.close();
serialPort.close();


まあこんな感じでシリアル通信のテストが出来るはずです。
他のPCと接続してテストする際はシリアルケーブルのクロスを使用しないとできませんよ!!

どうです?動きました?

投稿者 Tsuda : 13:44 | コメント (2) | トラックバック