目次
前
次
テストアプリケーション
複数のボードを作成したので、各ボードをテストする
環境が必要になりました。
C#で、お手軽に作ろうとしましたが、大阪に持参する
ノートPCのHD容量が小さいので、スクリプトを記述し
インタプリタで動作させられる、Javaを使うことに。
Javaでコードを作成するのは、10年以上振りだったため
1日でできる予定が、2日かかってしまいました。
Javaは、クラスを定義し、それらを組み合わせることで
動作させるので、ハードウエアと同じように箱を作成し
動作を考えます。
TeraTermをイメージし、操作を考えるためにGUIを
スケッチして決めました。
シリアルポートの番号は、利用コンピュータで変わる
ので、COM1〜COM8から選択できるようにします。
データ転送速度は、38400bpsで固定ですが、こちらも
4800、9600、19200、38400、57600から選べるように
定義しました。
操作画面が決まったので、最初のクラスを定義します。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import gnu.io.*;
import java.io.*;
public class McrTst
{
private final static int my_frm_width = 500 ;
private final static int my_frm_height = 500 ;
public static void main(String args[])
{
MFrame frame = new MFrame();
//
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set dimension
frame.setSize(my_frm_width,my_frm_height);
// show
frame.setVisible(true);
}
}
Cと同じように、mainとなる関数を定義し、他のクラスの
メソッドを利用して、おしまいです。
ウィンドウを用意し、右上にあるXをクリックすると
終了する仕様を採用しました。
シリアル通信に関連するクラスを、自作するのは大変
なので、RXTXクラスをダウンロードして利用します。
RXTXクラスのメソッドを利用して、最もマイコンに近い
部分を抽象化しました。
クラスを定義するので、実現したい機能を考えます。
- シリアルポートのオープン
- シリアルポートのクローズ
- 文字列送信
- データ受信
データ受信は、割込み(Javaだとlistenerですが)を利用
しなければならないので、別クラスで実現します。
機能を絞って、DTBクラスを定義しました。
class DtbC
{
SerialPort port;
CommPortIdentifier comID;
String comName;
int baudRate;
InputStream in;
OutputStream out;
// open method
boolean rs_open(String Com_Name,int Baud_Rate)
{
comName = Com_Name;
baudRate = Baud_Rate;
// get port ID
try {
comID = CommPortIdentifier.getPortIdentifier(comName);
} catch(Exception e) {
JOptionPane.showMessageDialog(null,"Do not nortify !","DtbC.open()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
// already opened
if ( comID.isCurrentlyOwned() == false ) {
try {
// generate instance
port = (SerialPort)comID.open("DTB",2000);
// baud rate , data length , stop bit , parity
port.setSerialPortParams(baudRate,SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE );
// no flow control
port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
// input and output stream
in = port.getInputStream();
out = port.getOutputStream();
} catch(Exception e) {
JOptionPane.showMessageDialog(null,"Do not open !","DtbC.rs_open()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
} else {
JOptionPane.showMessageDialog(null,"Already opened !","DtbC.rs_open()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
return true;
}
// close method
boolean rs_close()
{
if ( comID.isCurrentlyOwned() ) {
try {
port.close();
in.close();
out.close();
} catch(IOException e) {
JOptionPane.showMessageDialog(null,"Do not close !","DtbC.rs_close()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
} else {
JOptionPane.showMessageDialog(null,"Already closed !","DtbC.rs_close()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
return true;
}
// send string
void Serial_puts(String str)
{
byte[] data = str.getBytes();
try {
out.write(data);
out.flush();
} catch(Exception e) {
}
}
}
ポートオープンとクローズは、既に開いている、閉じて
いる場合を考え、try..catchで定義しました。
文字列送信は、OutputStreamを用意して、その中にある
文字列を、RXTXのwriteメソッドで出力します。
データ送受信が楽になるように、InputStream、OutputStreamで
エンドポイントを用意します。
シリアルの通信に関連するクラスを定義したので
シリアル処理を単純にすると同時に、上位クラス
の負担軽減用ミドルウエアを考えます。
class Serial_Class extends DtbC
{
JComboBox cbxCom;
JComboBox cbxBaud;
JTextArea edtText;
JScrollPane scrPane;
// constructor
Serial_Class()
{
// generate text area
edtText = new JTextArea();
// generate scroll pane
scrPane = new JScrollPane(edtText);
scrPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// COM port ComboBox
cbxCom = new JComboBox();
cbxCom.addItem("COM1"); cbxCom.addItem("COM2");
cbxCom.addItem("COM3"); cbxCom.addItem("COM4");
cbxCom.addItem("COM5"); cbxCom.addItem("COM6");
cbxCom.addItem("COM7"); cbxCom.addItem("COM8");
// default port
cbxCom.setSelectedItem("COM6");
// Buad rate ComboBox
cbxBaud = new JComboBox();
cbxBaud.addItem("4800") ; cbxBaud.addItem("9600");
cbxBaud.addItem("19200"); cbxBaud.addItem("38400");
cbxBaud.addItem("57600");
// default baud rate
cbxBaud.setSelectedItem("38400");
}
// open method
void open()
{
boolean flag;
// convert COM name to string
String COM_Name = (cbxCom.getSelectedItem()).toString();
// get baud rate from ComboBox
int Baud_Rate = Integer.parseInt((cbxBaud.getSelectedItem()).toString());
// open
flag = rs_open(COM_Name,Baud_Rate);
// success
if ( flag ) {
try {
// register receive event handler
port.addEventListener(new SerialPortListener());
// add event monitor
port.notifyOnDataAvailable(true);
} catch(Exception e) {
}
edtText.append("Connected\n");
}
}
// close method
void close()
{
boolean flag;
// close
flag = rs_close();
// success
if ( flag ) { edtText.append("Disconnected\n"); }
}
// event listener
class SerialPortListener implements SerialPortEventListener
{
// event handler
public void serialEvent(SerialPortEvent Serial_event)
{
StringBuffer buffer = new StringBuffer();
int received_data = 0 ;
// receive completed
if ( Serial_event.getEventType() == SerialPortEvent.DATA_AVAILABLE ) {
// loop until get 'break'
while (true) {
try {
// get data from input stream
received_data = in.read();
// no charactor
if ( received_data == -1 ) break;
// store
if ( (char)received_data != '\r' ) {
buffer.append((char)received_data);
} else {
// get delimiter
// convert
edtText.append(buffer.toString());
// clear buffer
buffer.delete(0,buffer.length()-1);
// post handling
edtText.setCaretPosition(edtText.getText().length());
//break;
}
} catch(IOException ex){
}
}
}
}
}
}
コンストラクタで、コンボボックスを生成し
COMポート番号選択、ボーレート選択ができる
ようにします。
さらに、テキストエリアを用意して、送受信の
内容を表示できるようにします。
クラスメソッドを利用する側の負担が減るように
open、closeを用意します。
openメソッドでは、COMポート番号、ボーレートを
確定して、DTBクラスのメソッドにパラメータを
渡します。
受信データを、テキストエリアに表示するため
SerialPortEventListenerで、DTBクラスが入力した
データを、転送する仕掛けを入れました。
受信データは、'\r'で1区切りと判断しています。
Serialクラスを定義したので、GUIを担当するフレーム
クラスを定義します。
コンストラクタで、GUIに必要なComboBox、Label、Buttonを
パネルに貼付けていきます。また、パネルは、フレームの中
に入れるようにします。
ボタンは、COMポートのオープン、クローズに利用します。
ボタン操作に関係するイベント処理は、Actionを利用して
捉まえます。
マイコンボードに転送するデータを、キーボードから入力
できるようにします。このとき、'\r'をつけるため、仮想
キー入力をEnterにバインドします。
また、キー入力はKeyAdapterクラスのサブクラスになる
クラスを定義して対応します。
ここまで考えた仕様をまとめます。
class MFrame extends JFrame
{
Serial_Class serial;
// constructor
MFrame()
{
// call super class method
super("MCR machine test");
serial = new Serial_Class();
// generate pane
JPanel cp = new JPanel();
// set layout moe
cp.setLayout(null);
// add pane to frame
setContentPane(cp);
// generate scroll pane
JScrollPane sp = new JScrollPane(serial.edtText);
// enable vertical scroll bar
sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// set scroll pane dimension
sp.setBounds(50,50,400,300);
// add scroll pane
cp.add(sp);
// show COM port
JLabel com_label = new JLabel("COM port:");
cp.add(com_label);
com_label.setBounds(50,20,100,20);
cp.add(serial.cbxCom);
serial.cbxCom.setBounds(120,20,80,20);
// show selected baud rate
JLabel baud_label = new JLabel("Baud rate : ");
cp.add(baud_label);
baud_label.setBounds(250,20,100,20);
cp.add(serial.cbxBaud);
serial.cbxBaud.setBounds(350,20,80,20);
// generate Font
Font font = new Font("SansSerif",Font.PLAIN,16);
// add Font information to textarea。
serial.edtText.setFont(font);
serial.edtText.setLineWrap(true);
serial.edtText.addKeyListener(new KeyInput());
serial.scrPane.setBounds(50,50,400,300);
cp.add(serial.scrPane);
// define button
JButton btnConnect = new JButton(new open_action());
btnConnect.setBounds(50,400,150,40);
cp.add(btnConnect);
JButton btnDisconnect = new JButton(new close_action());
btnDisconnect.setBounds(300,400,150,40);
cp.add(btnDisconnect);
// register KeyInput class to KeyListener
serial.edtText.addKeyListener(new KeyInput());
}
// internal class (bntConnect)
class open_action extends AbstractAction
{
// constructor
open_action()
{
putValue(Action.NAME,"\nConnect");
}
// event method
public void actionPerformed(ActionEvent btnConnect_act)
{
serial.open();
}
}
// internal class (bntDisconnect)
class close_action extends AbstractAction
{
// constructor
close_action()
{
putValue(Action.NAME,"\nDisconnect");
}
// event method
public void actionPerformed(ActionEvent btnDisconnect_act)
{
serial.close();
}
}
// key event
class KeyInput extends KeyAdapter
{
String stmp;
String[] stmp_array;
int lineNum;
public void keyPressed(KeyEvent e)
{
// get key then echo to textArea
if ( e.getKeyCode() == KeyEvent.VK_ENTER ) {
//serial.edtText.append("\n");
stmp = serial.edtText.getText();
stmp_array = stmp.split("\n",0);
lineNum = stmp_array.length - 1;
// send serial port
serial.Serial_puts(stmp_array[lineNum]+"\r");
}
}
}
}
ソースコード
4つのクラスを、一つのファイルにまとめてみると
次のようになります。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import gnu.io.*;
import java.io.*;
// internal Device Test Box class
class DtbC
{
SerialPort port;
CommPortIdentifier comID;
String comName;
int baudRate;
InputStream in;
OutputStream out;
// open method
boolean rs_open(String Com_Name,int Baud_Rate)
{
comName = Com_Name;
baudRate = Baud_Rate;
// get port ID
try {
comID = CommPortIdentifier.getPortIdentifier(comName);
} catch(Exception e) {
JOptionPane.showMessageDialog(null,"Do not nortify !","DtbC.open()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
// already opened
if ( comID.isCurrentlyOwned() == false ) {
try {
// generate instance
port = (SerialPort)comID.open("DTB",2000);
// baud rate , data length , stop bit , parity
port.setSerialPortParams(baudRate,SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE );
// no flow control
port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
// input and output stream
in = port.getInputStream();
out = port.getOutputStream();
} catch(Exception e) {
JOptionPane.showMessageDialog(null,"Do not open !","DtbC.rs_open()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
} else {
JOptionPane.showMessageDialog(null,"Already opened !","DtbC.rs_open()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
return true;
}
// close method
boolean rs_close()
{
if ( comID.isCurrentlyOwned() ) {
try {
port.close();
in.close();
out.close();
} catch(IOException e) {
JOptionPane.showMessageDialog(null,"Do not close !","DtbC.rs_close()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
} else {
JOptionPane.showMessageDialog(null,"Already closed !","DtbC.rs_close()",JOptionPane.INFORMATION_MESSAGE);
return false;
}
return true;
}
// send string
void Serial_puts(String str)
{
byte[] data = str.getBytes();
try {
out.write(data);
out.flush();
} catch(Exception e) {
}
}
}
// internal Serial Class (super class => DtbC)
class Serial_Class extends DtbC
{
JComboBox cbxCom;
JComboBox cbxBaud;
JTextArea edtText;
JScrollPane scrPane;
// constructor
Serial_Class()
{
// generate text area
edtText = new JTextArea();
// generate scroll pane
scrPane = new JScrollPane(edtText);
scrPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// COM port ComboBox
cbxCom = new JComboBox();
cbxCom.addItem("COM1"); cbxCom.addItem("COM2");
cbxCom.addItem("COM3"); cbxCom.addItem("COM4");
cbxCom.addItem("COM5"); cbxCom.addItem("COM6");
cbxCom.addItem("COM7"); cbxCom.addItem("COM8");
// default port
cbxCom.setSelectedItem("COM6");
// Buad rate ComboBox
cbxBaud = new JComboBox();
cbxBaud.addItem("4800") ; cbxBaud.addItem("9600");
cbxBaud.addItem("19200"); cbxBaud.addItem("38400");
cbxBaud.addItem("57600");
// default baud rate
cbxBaud.setSelectedItem("38400");
}
// open method
void open()
{
boolean flag;
// convert COM name to string
String COM_Name = (cbxCom.getSelectedItem()).toString();
// get baud rate from ComboBox
int Baud_Rate = Integer.parseInt((cbxBaud.getSelectedItem()).toString());
// open
flag = rs_open(COM_Name,Baud_Rate);
// success
if ( flag ) {
try {
// register receive event handler
port.addEventListener(new SerialPortListener());
// add event monitor
port.notifyOnDataAvailable(true);
} catch(Exception e) {
}
edtText.append("Connected\n");
}
}
// close method
void close()
{
boolean flag;
// close
flag = rs_close();
// success
if ( flag ) { edtText.append("Disconnected\n"); }
}
// event listener
class SerialPortListener implements SerialPortEventListener
{
// event handler
public void serialEvent(SerialPortEvent Serial_event)
{
StringBuffer buffer = new StringBuffer();
int received_data = 0 ;
// receive completed
if ( Serial_event.getEventType() == SerialPortEvent.DATA_AVAILABLE ) {
// loop until get 'break'
while (true) {
try {
// get data from input stream
received_data = in.read();
// no charactor
if ( received_data == -1 ) break;
// store
if ( (char)received_data != '\r' ) {
buffer.append((char)received_data);
} else {
// get delimiter
// convert
edtText.append(buffer.toString());
// clear buffer
buffer.delete(0,buffer.length()-1);
// post handling
edtText.setCaretPosition(edtText.getText().length());
//break;
}
} catch(IOException ex){
}
}
}
}
}
}
// internal Frame (window) class
class MFrame extends JFrame
{
Serial_Class serial;
// constructor
MFrame()
{
// call super class method
super("MCR machine test");
serial = new Serial_Class();
// generate pane
JPanel cp = new JPanel();
// set layout moe
cp.setLayout(null);
// add pane to frame
setContentPane(cp);
// generate scroll pane
JScrollPane sp = new JScrollPane(serial.edtText);
// enable vertical scroll bar
sp.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
sp.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
// set scroll pane dimension
sp.setBounds(50,50,400,300);
// add scroll pane
cp.add(sp);
// show COM port
JLabel com_label = new JLabel("COM port:");
cp.add(com_label);
com_label.setBounds(50,20,100,20);
cp.add(serial.cbxCom);
serial.cbxCom.setBounds(120,20,80,20);
// show selected baud rate
JLabel baud_label = new JLabel("Baud rate : ");
cp.add(baud_label);
baud_label.setBounds(250,20,100,20);
cp.add(serial.cbxBaud);
serial.cbxBaud.setBounds(350,20,80,20);
// generate Font
Font font = new Font("SansSerif",Font.PLAIN,16);
// add Font information to textarea。
serial.edtText.setFont(font);
serial.edtText.setLineWrap(true);
serial.edtText.addKeyListener(new KeyInput());
serial.scrPane.setBounds(50,50,400,300);
cp.add(serial.scrPane);
// define button
JButton btnConnect = new JButton(new open_action());
btnConnect.setBounds(50,400,150,40);
cp.add(btnConnect);
JButton btnDisconnect = new JButton(new close_action());
btnDisconnect.setBounds(300,400,150,40);
cp.add(btnDisconnect);
// register KeyInput class to KeyListener
serial.edtText.addKeyListener(new KeyInput());
}
// internal class (bntConnect)
class open_action extends AbstractAction
{
// constructor
open_action()
{
putValue(Action.NAME,"\nConnect");
}
// event method
public void actionPerformed(ActionEvent btnConnect_act)
{
serial.open();
}
}
// internal class (bntDisconnect)
class close_action extends AbstractAction
{
// constructor
close_action()
{
putValue(Action.NAME,"\nDisconnect");
}
// event method
public void actionPerformed(ActionEvent btnDisconnect_act)
{
serial.close();
}
}
// key event
class KeyInput extends KeyAdapter
{
String stmp;
String[] stmp_array;
int lineNum;
public void keyPressed(KeyEvent e)
{
// get key then echo to textArea
if ( e.getKeyCode() == KeyEvent.VK_ENTER )
{
//serial.edtText.append("\n");
stmp = serial.edtText.getText();
stmp_array = stmp.split("\n",0);
lineNum = stmp_array.length - 1;
// send serial port
serial.Serial_puts(stmp_array[lineNum]+"\r");
}
}
}
}
public class McrTst
{
private final static int my_frm_width = 500 ;
private final static int my_frm_height = 500 ;
public static void main(String args[])
{
MFrame frame = new MFrame();
//
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// set dimension
frame.setSize(my_frm_width,my_frm_height);
// show
frame.setVisible(true);
}
}
コンパイル、リンク、実行
JavaSEのJDKをダウンロードし、インストールしておけば
コンパイル、リンクは単純です。
コンパイル、リンクは次のように入力します。
javac McrTst.java{enter}
実行は、以下です。
java McrTst{enter}
GUIの操作をしてみます。
ボタンクリックで、マイコンに接続します。
キーボードから'?'を入力し、マイコンからの返信を
表示します。
GameBoyCameraに撮影させて、画像データをシリアル
転送しているところです。
ボタンクリックで、マイコンを切断します。
簡単なテストアプリケーションですが
ハードウエアとファームウエアのバグ
を叩出すのに、充分役に立ちました。
目次
前
次