00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 package ikayaki.squid;
00024
00025 import ikayaki.Ikayaki;
00026
00027 import javax.comm.*;
00028 import javax.swing.*;
00029 import javax.swing.event.EventListenerList;
00030 import java.io.*;
00031 import java.text.DateFormat;
00032 import java.text.SimpleDateFormat;
00033 import java.util.Calendar;
00034 import java.util.Date;
00035 import java.util.TooManyListenersException;
00036 import java.util.Vector;
00037
00043 public class SerialIO implements SerialPortEventListener {
00044
00045
00046
00047
00048
00049 private static final boolean DEBUG = false;
00050 private static final DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss.SSS");
00051
00055 private static Vector<SerialIO> openPorts = new Vector<SerialIO>();
00056
00060 private EventListenerList listenerList = new EventListenerList();
00061
00065 private SerialPort sPort;
00066
00070 private OutputStream os;
00071
00075 private InputStream is;
00076
00080 private String portName;
00081
00085 private BufferedWriter logWriter;
00086
00090 private boolean logWriterTriedCreate = false;
00091
00095 private enum LogEvent {
00096 SESSION_START, SEND, REVEIVE
00097 };
00098
00105 private SerialIO(SerialParameters parameters) throws SerialIOException {
00106 CommPortIdentifier portId;
00107 SerialPort sPort;
00108
00109 try {
00110 portId = CommPortIdentifier.getPortIdentifier(parameters.getPortName());
00111 } catch (NoSuchPortException e) {
00112 throw new SerialIOException("No such port exists:" + parameters.getPortName());
00113 }
00114
00115
00116 try {
00117 sPort = (SerialPort) portId.open("SerialPort", 4000);
00118 } catch (PortInUseException e) {
00119 throw new SerialIOException("The port " + parameters.getPortName() + " is already in use");
00120 }
00121
00122
00123 debug(LogEvent.SESSION_START, sPort.getName());
00124
00125
00126 try {
00127 sPort.setSerialPortParams(parameters.getBaudRate(),
00128 parameters.getDatabits(),
00129 parameters.getStopbits(),
00130 parameters.getParity());
00131 } catch (UnsupportedCommOperationException e) {
00132 sPort.close();
00133 throw new SerialIOException("Unsupported parameter");
00134 }
00135
00136
00137 try {
00138 sPort.setFlowControlMode(parameters.getFlowControlIn()
00139 | parameters.getFlowControlOut());
00140 } catch (UnsupportedCommOperationException e) {
00141 sPort.close();
00142 throw new SerialIOException("Unsupported flow control");
00143 }
00144
00145
00146 try {
00147 this.os = sPort.getOutputStream();
00148 this.is = sPort.getInputStream();
00149 } catch (IOException e) {
00150 sPort.close();
00151 throw new SerialIOException("Error opening i/o streams");
00152 }
00153
00154
00155 try {
00156 sPort.addEventListener(this);
00157 } catch (TooManyListenersException ex) {
00158 throw new SerialIOException("Too many listeners");
00159 }
00160
00161
00162 sPort.notifyOnDataAvailable(true);
00163
00164
00165
00166 try {
00167 sPort.enableReceiveTimeout(30);
00168 } catch (UnsupportedCommOperationException e) {
00169 throw new SerialIOException("Unsupported operation");
00170 }
00171
00172 this.sPort = sPort;
00173 this.portName = sPort.getName();
00174
00175 return;
00176 }
00177
00178 public static SerialIO openPort(SerialParameters parameters) throws SerialIOException {
00179
00180
00181 SerialIO newPort = null;
00182
00183
00184
00185 for (int i = 0; i < openPorts.size(); i++) {
00186 if (parameters.getPortName().equals(openPorts.elementAt(i).portName)) {
00187 return openPorts.elementAt(i);
00188 }
00189 }
00190 newPort = new SerialIO(parameters);
00191 openPorts.add(newPort);
00192
00193 System.out.println("Port: " + parameters.getPortName() + " opened");
00194 return newPort;
00195 }
00196
00203 public void writeMessage(String message) throws SerialIOException {
00204
00205 byte[] asciiMsg;
00206
00207
00208 try {
00209 asciiMsg = message.getBytes("US-ASCII");
00210 } catch (UnsupportedEncodingException e) {
00211 throw new SerialIOException("ASCII charset not supported");
00212 }
00213
00214
00215 try {
00216 try {
00217 Thread.sleep(50);
00218
00219 } catch (InterruptedException ex) {
00220 }
00221 debug(LogEvent.SEND, message);
00222 os.write(asciiMsg);
00223 os.flush();
00224 } catch (IOException e) {
00225 throw new SerialIOException("Couldn't write to outputstream of" + this.portName);
00226 }
00227
00228 return;
00229 }
00230
00234 public void closePort() {
00235 if (sPort != null) {
00236 this.sPort.close();
00237 try {
00238 this.is.close();
00239 } catch (IOException ex) {
00240 System.err.println("Could not close inputstream for COM port");
00241 }
00242 try {
00243 this.os.close();
00244 } catch (IOException ex1) {
00245 System.err.println("Could not close outputstream for COM port");
00246 }
00247 }
00248 }
00249
00253 public static void closeAllPorts() {
00254 for (int i = 0; i < openPorts.size(); i++) {
00255 openPorts.elementAt(i).closePort();
00256 }
00257 }
00258
00262 public void serialEvent(SerialPortEvent event) {
00263
00264 switch (event.getEventType()) {
00265 case SerialPortEvent.BI:
00266 case SerialPortEvent.OE:
00267 case SerialPortEvent.FE:
00268 case SerialPortEvent.PE:
00269 case SerialPortEvent.CD:
00270 case SerialPortEvent.CTS:
00271 case SerialPortEvent.DSR:
00272 case SerialPortEvent.RI:
00273 case SerialPortEvent.OUTPUT_BUFFER_EMPTY:
00274 break;
00275 case SerialPortEvent.DATA_AVAILABLE:
00276 StringBuffer inputBuffer = new StringBuffer();
00277 int newData = 0;
00278 byte[] newByte = new byte[1];
00279
00280 while (newData != -1) {
00281 try {
00282 newData = is.read();
00283 if (newData == -1) {
00284 break;
00285 }
00286 newByte[0] = new Integer(newData).byteValue();
00287 inputBuffer.append(new String(newByte, "US-ASCII"));
00288
00289 } catch (IOException ex) {
00290 System.err.println(ex);
00291 return;
00292 }
00293 }
00294
00295 fireSerialIOEvent(new String(inputBuffer));
00296
00297
00298 debug(LogEvent.REVEIVE, inputBuffer.toString());
00299
00300 break;
00301 }
00302 return;
00303 }
00304
00310 public synchronized void addSerialIOListener(SerialIOListener l) {
00311 listenerList.add(SerialIOListener.class, l);
00312 }
00313
00319 public synchronized void removeSerialIOListener(SerialIOListener l) {
00320 listenerList.remove(SerialIOListener.class, l);
00321 }
00322
00328 private synchronized void fireSerialIOEvent(String message) {
00329 final SerialIOEvent event = new SerialIOEvent(this, message);
00330 final SerialIOListener[] listeners = listenerList.getListeners(SerialIOListener.class);
00331 SwingUtilities.invokeLater(new Runnable() {
00332 public void run() {
00333 for (SerialIOListener l : listeners) {
00334 try {
00335 l.serialIOEvent(event);
00336 } catch (Throwable t) {
00337 t.printStackTrace();
00338 }
00339 }
00340 }
00341 });
00342 }
00343
00350 private void debug(LogEvent e, String message) {
00351
00352 if (DEBUG == false) return;
00353
00354
00355 if (!logWriterTriedCreate) {
00356 logWriterTriedCreate = true;
00357
00358 Calendar now = Calendar.getInstance();
00359 int y = now.get(Calendar.YEAR), m = now.get(Calendar.MONTH) + 1, d = now.get(Calendar.DAY_OF_MONTH);
00360 String port = e == LogEvent.SESSION_START ? message : portName;
00361 File file = new File(Ikayaki.DEBUG_LOG_DIR, y + "-" + padn(m) + "-" + padn(d) + "-" + port + ".log");
00362
00363 boolean oldFile = file.exists();
00364 if (!Ikayaki.DEBUG_LOG_DIR.exists()) Ikayaki.DEBUG_LOG_DIR.mkdir();
00365
00366 try {
00367 logWriter = new BufferedWriter(new FileWriter(file, true));
00368
00369 if (oldFile) logWriter.newLine();
00370 } catch (IOException ex1) {
00371 System.err.println("Error creating log file: " + ex1);
00372 }
00373 }
00374
00375
00376 if (logWriter == null) return;
00377
00378
00379 String time = dateFormat.format(new Date());
00380 try {
00381 logWriter.write(time + " " + e + ": " + message);
00382 logWriter.newLine();
00383 logWriter.flush();
00384 } catch (IOException ex1) {
00385 System.err.println(ex1);
00386 }
00387 }
00388
00395 private String padn(int n) {
00396 return (n < 10 ? "0" : "") + n;
00397 }
00398
00399 public String getPortName() {
00400 return portName;
00401 }
00402 }