ちょっと忙しかったので、久しぶりの更新。
最新、計測器制御用にRS-232C通信を使ったプログラムを書く機会があり、かなり久しぶり(10年振りくらい?)にJava Communications APIを使いました。
備忘録としてメモを残しておきます。
- Java Communications API3.0から、Windows用のバイナリが配布されなくなったようです。このため、互換ライブラリのRXTXライブラリを使用しました。
- とりあえず、以下のSerialPortCommクラスとSerialPortParameterクラスを書いて、通信を処理しました。
■SerialPortComm.java
import gnu.io.CommPortIdentifier; import gnu.io.CommPortOwnershipListener; import gnu.io.NoSuchPortException; import gnu.io.PortInUseException; import gnu.io.SerialPort; import gnu.io.SerialPortEvent; import gnu.io.SerialPortEventListener; import gnu.io.UnsupportedCommOperationException; import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.TooManyListenersException; import javax.swing.JOptionPane; public class SerialPortComm implements CommPortOwnershipListener{ private DataInputStream is; private DataOutputStream os; private PrintStream ps; private boolean owned=false; private SerialPortParameter parameter; private CommPortIdentifier port_id; private SerialPort port; private int TIMEOUT=10000; public SerialPortComm(SerialPortParameter parameter,PrintStream ps){ this.parameter=parameter; this.ps=ps; } public void open() throws IOException{ try { port_id=CommPortIdentifier.getPortIdentifier( parameter.getPortName()); } catch (NoSuchPortException e) { throw new IOException(e.getMessage()); } port_id.addPortOwnershipListener(this); try { String name="RS232C_"+Long.toString( System.currentTimeMillis()); port = (SerialPort)port_id.open(name, TIMEOUT); } catch (PortInUseException e) { throw new IOException(e.getMessage()); } try { port.setSerialPortParams( parameter.getBaudRate(), parameter.getDatabits(), parameter.getStopbits(), parameter.getParity()); } catch (UnsupportedCommOperationException e) { throw new IOException("Unsupported parameter"); } try { port.setFlowControlMode( parameter.getFlowControlIn() | parameter.getFlowControlOut()); } catch (UnsupportedCommOperationException e) { throw new IOException("Unsupported flow control"); } try { os=new DataOutputStream(port.getOutputStream()); is=new DataInputStream(port.getInputStream()); } catch (IOException e) { port.close(); throw new IOException("Error opening i/o streams"); } port.setRTS(parameter.isRTS()); port.setDTR(parameter.isDTR()); port.notifyOnDataAvailable(true); port.notifyOnBreakInterrupt(true); try { port.enableReceiveTimeout(TIMEOUT); } catch (UnsupportedCommOperationException e) { throw new IOException("Unsupported parameter"); } try{ port.addEventListener(new SerialReader()); }catch(TooManyListenersException e){ throw new IOException(e.getMessage()); } } public void close(){ try{ is.close(); os.close(); port.close(); ps.println("An close succeeded."); port_id.removePortOwnershipListener(this); }catch(IOException e){ e.printStackTrace(); } } public void ownershipChange(int arg0) { switch(arg0){ case CommPortOwnershipListener.PORT_OWNED: ps.println("An open succeeded."); owned=true; break; case CommPortOwnershipListener.PORT_UNOWNED: owned=false; break; case CommPortOwnershipListener.PORT_OWNERSHIP_REQUESTED: if(owned){ if(JOptionPane.showConfirmDialog(null, "I've been asked to give up the port, shold I?", "Port Conflict("+port.getName()+")", JOptionPane.OK_CANCEL_OPTION)==0){ close(); } }else{ ps.println("Somebody else has the port."); } } } public byte[] getDataBlock(String mes){ byte[] ret=new byte[36]; for(int i=0;i<ret.length;i++)ret[i]=0x1A; ret[0]=0x02; ret[1]=0x01; ret[2]=~0x01; byte[] m=mes.getBytes(); int ck=0; for(int i=0;i<m.length;i++){ ret[i+3]=m[i]; } for(int i=0;i<32;i++){ ck +=ret[i+3]; } ret[35]=(byte)(ck & 0x0000ff); return ret; } public synchronized void send(String mes){ try{ byte[] b=getDataBlock(mes); os.write(b,0,b.length); ps.println("#User> "+mes); }catch(IOException e){ e.printStackTrace(); } } public void sendNAK(){ try{ os.write(0x15); ps.println("#User> NAK"); }catch(IOException e){} } public void sendACK(){ try{ os.write(0x06); ps.println("#User> ACK"); }catch(IOException e){} } public void sendEOT(){ try{ os.write(0x04); ps.println("#User> EOT"); }catch(IOException e){} } public void sendCAN(){ try{ os.write(0x18); ps.println("#User> CAN"); }catch(IOException e){} } private class SerialReader implements SerialPortEventListener{ @Override public void serialEvent(SerialPortEvent arg0) { byte[] buffer = new byte[256]; if (arg0.getEventType() == SerialPortEvent.DATA_AVAILABLE) { try{ is.read(buffer); for(Reciever r : list)r.reciever(buffer,r); System.out.println( "#DEV > "+Integer.toHexString(buffer[0])); }catch(Exception e){e.printStackTrace();} } } } }
■SerialPortParameter.java
import gnu.io.SerialPort; public class SerialPortParameter { private String portName; private int baudRate; private int flowControlIn; private int flowControlOut; private int databits; private int stopbits; private int parity; private boolean isRTS=true; private boolean isDTR=true; private char[] delimiter; private static char[] CR="\r".toCharArray(); private static char[] LF="\n".toCharArray(); private static char[] CRLF="\r\n".toCharArray(); public static String DELIMITER_CR="CR"; public static String DELIMITER_LF="LF"; public static String DELIMITER_CRLF="CRLF"; public SerialPortParameter(){ portName="COM1"; baudRate=9600; flowControlIn=SerialPort.FLOWCONTROL_NONE; flowControlOut=SerialPort.FLOWCONTROL_NONE; databits=SerialPort.DATABITS_5; stopbits=SerialPort.STOPBITS_1; parity=SerialPort.PARITY_NONE; delimiter=CRLF; } public int getBaudRate() { return baudRate; } public void setBaudRate(int baudRate) { this.baudRate = baudRate; } public int getDatabits() { return databits; } public void setDatabits(int databits) { this.databits = databits; } public int getFlowControlIn() { return flowControlIn; } public void setFlowControlIn(int flowControlIn) { this.flowControlIn = flowControlIn; } public int getFlowControlOut() { return flowControlOut; } public void setFlowControlOut(int flowControlOut) { this.flowControlOut = flowControlOut; } public int getParity() { return parity; } public void setParity(int parity) { this.parity = parity; } public String getPortName() { return portName; } public void setPortName(String portName) { this.portName = portName; } public int getStopbits() { return stopbits; } public void setStopbits(int stopbits) { this.stopbits = stopbits; } public String getDelimiterType() { if(delimiter==CR){ return DELIMITER_CR; }else if(delimiter==LF){ return DELIMITER_LF; }else{ return DELIMITER_CRLF; } } public void setDelimiterType(String str) { if(str.equals("CR")){ delimiter=CR; }else{ delimiter=CRLF; } } public char[] getDelimiter() { return delimiter; } public boolean isRTS() { return isRTS; } public void setRTS(boolean isRTS) { this.isRTS = isRTS; } public boolean isDTR() { return isDTR; } public void setDTR(boolean isDTR) { this.isDTR = isDTR; } }