diff --git a/java/libraries/serial/.classpath b/java/libraries/serial/.classpath index fb88820a0..d8894f2e3 100644 --- a/java/libraries/serial/.classpath +++ b/java/libraries/serial/.classpath @@ -2,7 +2,7 @@ - + diff --git a/java/libraries/serial/build.xml b/java/libraries/serial/build.xml index d04e8a66a..d6b18410e 100755 --- a/java/libraries/serial/build.xml +++ b/java/libraries/serial/build.xml @@ -3,7 +3,7 @@ - + @@ -18,7 +18,7 @@ srcdir="src" destdir="bin" encoding="UTF-8" includeAntRuntime="false" - classpath="../../../core/library/core.jar; library/RXTXcomm.jar" + classpath="../../../core/library/core.jar; library/jssc.jar" nowarn="true" compiler="org.eclipse.jdt.core.JDTCompilerAdapter"> diff --git a/java/libraries/serial/library/jssc.txt b/java/libraries/serial/library/jssc.txt new file mode 100644 index 000000000..cf2f974ac --- /dev/null +++ b/java/libraries/serial/library/jssc.txt @@ -0,0 +1 @@ +This is using a modified version of Java Simple Serial Connector by Alexey Sokolov. See https://github.com/gohai/java-simple-serial-connector for details on the modifications. diff --git a/java/libraries/serial/src/processing/serial/Serial.java b/java/libraries/serial/src/processing/serial/Serial.java index fd3595fc1..8e82e2184 100644 --- a/java/libraries/serial/src/processing/serial/Serial.java +++ b/java/libraries/serial/src/processing/serial/Serial.java @@ -5,6 +5,7 @@ Part of the Processing project - http://processing.org Copyright (c) 2004-05 Ben Fry & Casey Reas + Reworked by Gottfried Haider as part of GSOC 2013 This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -24,728 +25,401 @@ package processing.serial; import processing.core.*; - -import gnu.io.*; - -import java.io.*; -import java.util.*; import java.lang.reflect.*; +import java.util.Map; +import jssc.*; -/** - * @generate Serial.xml - * @webref net - * @usage application - */ public class Serial implements SerialPortEventListener { PApplet parent; + public SerialPort port; + Method serialAvailableMethod; Method serialEventMethod; - // properties can be passed in for default values - // otherwise defaults to 9600 N81 + byte[] buffer = new byte[32768]; + int inBuffer = 0; + int readOffset = 0; - // these could be made static, which might be a solution - // for the classloading problem.. because if code ran again, - // the static class would have an object that could be closed + int bufferUntilSize = 1; + byte bufferUntilByte = 0; - public SerialPort port; + volatile boolean invokeSerialAvailable = false; - public int rate; - public int parity; - public int databits; - public int stopbits; + // Things we are currently not exposing: + // * hardware flow control + // * state of the RING, RLSD line + // * sending breaks - - // read buffer and streams - - public InputStream input; - public OutputStream output; - - byte buffer[] = new byte[32768]; - int bufferIndex; - int bufferLast; - - //boolean bufferUntil = false; - int bufferSize = 1; // how big before reset or event firing - boolean bufferUntil; - byte bufferUntilByte; - - - // defaults - - static String dname = "COM1"; - static int drate = 9600; - static char dparity = 'N'; - static int ddatabits = 8; - static float dstopbits = 1; - - - public void setProperties(Properties props) { - dname = - props.getProperty("serial.port", dname); - drate = - Integer.parseInt(props.getProperty("serial.rate", "9600")); - dparity = - props.getProperty("serial.parity", "N").charAt(0); - ddatabits = - Integer.parseInt(props.getProperty("serial.databits", "8")); - dstopbits = - new Float(props.getProperty("serial.stopbits", "1")).floatValue(); - } - -/** - * @param parent typically use "this" - */ public Serial(PApplet parent) { - this(parent, dname, drate, dparity, ddatabits, dstopbits); + this(parent, "COM1", 9600, 'N', 8, 1); } - -/** - * @param irate 9600 is the default - */ - public Serial(PApplet parent, int irate) { - this(parent, dname, irate, dparity, ddatabits, dstopbits); + public Serial(PApplet parent, int baudRate) { + this(parent, "COM1", baudRate, 'N', 8, 1); } - -/** - * @param iname name of the port (COM1 is the default) - */ - public Serial(PApplet parent, String iname, int irate) { - this(parent, iname, irate, dparity, ddatabits, dstopbits); + public Serial(PApplet parent, String portName) { + this(parent, portName, 9600, 'N', 8, 1); } - public Serial(PApplet parent, String iname) { - this(parent, iname, drate, dparity, ddatabits, dstopbits); + public Serial(PApplet parent, String portName, int baudRate) { + this(parent, portName, baudRate, 'N', 8, 1); } - -/** - * @param iparity 'N' for none, 'E' for even, 'O' for odd ('N' is the default) - * @param idatabits 8 is the default - * @param istopbits 1.0, 1.5, or 2.0 (1.0 is the default) - */ - public Serial(PApplet parent, String iname, int irate, - char iparity, int idatabits, float istopbits) { - //if (port != null) port.close(); + public Serial(PApplet parent, String portName, int baudRate, char parity, int dataBits, float stopBits) { this.parent = parent; - //parent.attach(this); + parent.registerMethod("dispose", this); + parent.registerMethod("pre", this); - // On OS X, make sure the lock folder needed by RXTX is present - if (PApplet.platform == PConstants.MACOSX) { - File lockFolder = new File("/var/lock"); - if (!lockFolder.exists() || - !lockFolder.canRead() || - !lockFolder.canWrite() || - !lockFolder.canExecute()) { - final String MESSAGE = - "To use the serial library, first open\n" + - "Applications -> Utilities -> Terminal.app\n" + - "and enter the following:\n" + - "sudo mkdir -p /var/lock\n" + - "sudo chmod 777 /var/lock"; - System.err.println(MESSAGE); - //throw new RuntimeException("Additional installation required to " + - // "use serial, read the console below."); - final String msg = - "Please use Tools \u2192 Fix the Serial Library."; - throw new RuntimeException(msg); - } + // setup parity + if (parity == 'O') { + parity = SerialPort.PARITY_ODD; + } else if (parity == 'E') { + parity = SerialPort.PARITY_EVEN; + } else if (parity == 'M') { + parity = SerialPort.PARITY_MARK; + } else if (parity == 'S') { + parity = SerialPort.PARITY_SPACE; + } else { + parity = SerialPort.PARITY_NONE; } - this.rate = irate; + // setup stop bits + int stopBitsIdx = SerialPort.STOPBITS_1; + if (stopBits == 1.5f) { + stopBitsIdx = SerialPort.STOPBITS_1_5; + } else if (stopBits == 2) { + stopBitsIdx = SerialPort.STOPBITS_2; + } - parity = SerialPort.PARITY_NONE; - if (iparity == 'E') parity = SerialPort.PARITY_EVEN; - if (iparity == 'O') parity = SerialPort.PARITY_ODD; - - this.databits = idatabits; - - stopbits = SerialPort.STOPBITS_1; - if (istopbits == 1.5f) stopbits = SerialPort.STOPBITS_1_5; - if (istopbits == 2) stopbits = SerialPort.STOPBITS_2; + port = new SerialPort(portName); + try { + // the native open() call is not using O_NONBLOCK, so this might block for certain operations (see write()) + port.openPort(); + port.setParams(baudRate, dataBits, stopBitsIdx, parity); + // we could register more events here + port.addEventListener(this, SerialPort.MASK_RXCHAR); + } catch (SerialPortException e) { + // this used to be a RuntimeException before, so stick with it + throw new RuntimeException("Error opening serial port "+e.getPortName()+": "+e.getExceptionType()); + } try { - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); + serialEventMethod = parent.getClass().getMethod("serialEvent", new Class[] { this.getClass() }); + } catch (Exception e) { + } - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { - //System.out.println("found " + portId.getName()); - if (portId.getName().equals(iname)) { - port = (SerialPort)portId.open("serial madness", 2000); - input = port.getInputStream(); - output = port.getOutputStream(); - port.setSerialPortParams(rate, databits, stopbits, parity); - port.addEventListener(this); - port.notifyOnDataAvailable(true); - //System.out.println("opening, ready to roll"); - } + try { + serialAvailableMethod = parent.getClass().getMethod("serialAvailable", new Class[] { this.getClass() }); + } catch (Exception e) { + } + } + + public void dispose() { + stop(); + } + + public void pre() { + if (serialAvailableMethod != null && invokeSerialAvailable) { + invokeSerialAvailable = false; + try { + serialAvailableMethod.invoke(parent, new Object[] { this }); + } catch (Exception e) { + System.err.println("Error, disabling serialAvailable() for "+port.getPortName()); + System.err.println(e.getLocalizedMessage()); + serialAvailableMethod = null; + } + } + } + + + public int available() { + return (inBuffer-readOffset); + } + + public void buffer(int size) { + bufferUntilSize = size; + } + + public void bufferUntil(int inByte) { + bufferUntilSize = 0; + bufferUntilByte = (byte)inByte; + } + + public void clear() { + synchronized (buffer) { + inBuffer = 0; + readOffset = 0; + } + } + + public boolean getCTS() { + try { + return port.isCTS(); + } catch (SerialPortException e) { + throw new RuntimeException("Error reading the CTS line: "+e.getExceptionType()); + } + } + + public boolean getDSR() { + try { + return port.isDSR(); + } catch (SerialPortException e) { + throw new RuntimeException("Error reading the DSR line: "+e.getExceptionType()); + } + } + + public static Map getProperties(String portName) { + SerialPortList list = new SerialPortList(); + return list.getPortProperties(portName); + } + + public int last() { + if (inBuffer == readOffset) { + return -1; + } + + synchronized (buffer) { + int ret = buffer[inBuffer-1] & 0xFF; + inBuffer = 0; + readOffset = 0; + return ret; + } + } + + public char lastChar() { + return (char)last(); + } + + public static String[] list() { + SerialPortList list = new SerialPortList(); + // returns list sorted alphabetically, thus cu.* comes before tty.* + // this was different with RXTX + return list.getPortNames(); + } + + public int read() { + if (inBuffer == readOffset) { + return -1; + } + + synchronized (buffer) { + int ret = buffer[readOffset++] & 0xFF; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; + } + return ret; + } + } + + public byte[] readBytes() { + if (inBuffer == readOffset) { + return null; + } + + synchronized (buffer) { + byte[] ret = new byte[inBuffer-readOffset]; + System.arraycopy(buffer, readOffset, ret, 0, ret.length); + inBuffer = 0; + readOffset = 0; + return ret; + } + } + + public int readBytes(byte[] dest) { + if (inBuffer == readOffset) { + return 0; + } + + synchronized (buffer) { + int toCopy = inBuffer-readOffset; + if (dest.length < toCopy) { + toCopy = dest.length; + } + System.arraycopy(buffer, readOffset, dest, 0, toCopy); + readOffset += toCopy; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; + } + return toCopy; + } + } + + public byte[] readBytesUntil(int inByte) { + if (inBuffer == readOffset) { + return null; + } + + synchronized (buffer) { + // look for needle in buffer + int found = -1; + for (int i=readOffset; i < inBuffer; i++) { + if (buffer[i] == (byte)inByte) { + found = i; + break; } } - - } catch (Exception e) { - errorMessage("", e); - //exception = e; - //e.printStackTrace(); - port = null; - input = null; - output = null; - } - - parent.registerMethod("dispose", this); - - // reflection to check whether host applet has a call for - // public void serialEvent(processing.serial.Serial) - // which would be called each time an event comes in - try { - serialEventMethod = - parent.getClass().getMethod("serialEvent", - new Class[] { Serial.class }); - } catch (Exception e) { - // no such method, or an error.. which is fine, just ignore - } - } - - - /** - * @generate Serial_stop.xml - * @webref serial:serial - * @usage web_application - */ - public void stop() { - dispose(); - } - - - /** - * Used by PApplet to shut things down. - */ - public void dispose() { - try { - if (input != null) { - input.close(); - input = null; + if (found == -1) { + return null; } - } catch (Exception e) { - e.printStackTrace(); - } - try { - if (output != null) { - output.close(); - output = null; + int toCopy = found-readOffset+1; + byte[] dest = new byte[toCopy]; + System.arraycopy(buffer, readOffset, dest, 0, toCopy); + readOffset += toCopy; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; } - } catch (Exception e) { - e.printStackTrace(); - } - - try { - if (port != null) { - port.close(); - port = null; - } - } catch (Exception e) { - e.printStackTrace(); + return dest; } } + public int readBytesUntil(int inByte, byte[] dest) { + if (inBuffer == readOffset) { + return 0; + } - /** - * Set the DTR line. Addition from Tom Hulbert. - */ - public void setDTR(boolean state) { - port.setDTR(state); + synchronized (buffer) { + // look for needle in buffer + int found = -1; + for (int i=readOffset; i < inBuffer; i++) { + if (buffer[i] == (byte)inByte) { + found = i; + break; + } + } + if (found == -1) { + return 0; + } + + // check if bytes to copy fit in dest + int toCopy = found-readOffset+1; + if (dest.length < toCopy) { + System.err.println( "The buffer passed to readBytesUntil() is to small " + + "to contain " + toCopy + " bytes up to and including " + + "char " + (byte)inByte); + return -1; + } + System.arraycopy(buffer, readOffset, dest, 0, toCopy); + readOffset += toCopy; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; + } + return toCopy; + } } + public char readChar() { + return (char)read(); + } - /** - * @generate serialEvent.xml - * @webref serial:events - * @usage web_application - * @param serialEvent the port where new data is available - */ - synchronized public void serialEvent(SerialPortEvent serialEvent) { - if (serialEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { + public String readString() { + if (inBuffer == readOffset) { + return null; + } + + return new String(readBytes()); + } + + public void serialEvent(SerialPortEvent event) { + if (event.getEventType() == SerialPortEvent.RXCHAR) { + int toRead; try { - while (input.available() > 0) { + while (0 < (toRead = port.getInputBufferBytesCount())) { + // this method can be called from the context of another thread synchronized (buffer) { - if (bufferLast == buffer.length) { - byte temp[] = new byte[bufferLast << 1]; - System.arraycopy(buffer, 0, temp, 0, bufferLast); + // enlarge buffer if necessary + if (buffer.length < inBuffer+toRead) { + byte temp[] = new byte[buffer.length<<1]; + System.arraycopy(buffer, 0, temp, 0, inBuffer); buffer = temp; } - buffer[bufferLast++] = (byte) input.read(); + // read an array of bytes and copy it into our buffer + byte[] read = port.readBytes(toRead); + System.arraycopy(read, 0, buffer, inBuffer, read.length); + inBuffer += read.length; if (serialEventMethod != null) { - if ((bufferUntil && - (buffer[bufferLast-1] == bufferUntilByte)) || - (!bufferUntil && - ((bufferLast - bufferIndex) >= bufferSize))) { + if ((0 < bufferUntilSize && bufferUntilSize <= inBuffer-readOffset) || + (0 == bufferUntilSize && bufferUntilByte == buffer[inBuffer-1])) { try { + // serialEvent() is invoked in the context of the current (serial) thread + // which means that serialization and atomic variables need to be used to + // guarantee reliable operation (and better not draw() etc..) + // serialAvailable() does not provide any real benefits over using + // available() and read() inside draw - but this function has no + // thread-safety issues since it's being invoked during pre in the context + // of the Processing applet serialEventMethod.invoke(parent, new Object[] { this }); } catch (Exception e) { - String msg = "error, disabling serialEvent() for " + port; - System.err.println(msg); - e.printStackTrace(); + System.err.println("Error, disabling serialEvent() for "+port.getPortName()); + System.err.println(e.getLocalizedMessage()); serialEventMethod = null; } } } + invokeSerialAvailable = true; } } - - } catch (IOException e) { - errorMessage("serialEvent", e); + } catch (SerialPortException e) { + throw new RuntimeException("Error reading from serial port "+e.getPortName()+": "+e.getExceptionType()); } } } - - /** - * @generate Serial_buffer.xml - * @webref serial:serial - * @usage web_application - * @param count number of bytes to buffer - */ - public void buffer(int count) { - bufferUntil = false; - bufferSize = count; - } - - - /** - * @generate Serial_bufferUntil.xml - * @webref serial:serial - * @usage web_application - * @param what the value to buffer until - */ - public void bufferUntil(int what) { - bufferUntil = true; - bufferUntilByte = (byte) what; - } - - - /** - * @generate Serial_available.xml - * @webref serial:serial - * @usage web_application - */ - public int available() { - return (bufferLast - bufferIndex); - } - - - /** - * @generate Serial_clear.xml - * @webref serial:serial - * @usage web_application - */ - public void clear() { - bufferLast = 0; - bufferIndex = 0; - } - - - /** - * @generate Serial_read.xml - * @webref serial:serial - * @usage web_application - */ - public int read() { - if (bufferIndex == bufferLast) return -1; - - synchronized (buffer) { - int outgoing = buffer[bufferIndex++] & 0xff; - if (bufferIndex == bufferLast) { // rewind - bufferIndex = 0; - bufferLast = 0; - } - return outgoing; - } - } - - - /** - * @generate Serial_last.xml - *

Advanced

- * Same as read() but returns the very last value received - * and clears the buffer. Useful when you just want the most - * recent value sent over the port. - * @webref serial:serial - * @usage web_application - */ - public int last() { - if (bufferIndex == bufferLast) return -1; - synchronized (buffer) { - int outgoing = buffer[bufferLast-1]; - bufferIndex = 0; - bufferLast = 0; - return outgoing; - } - } - - - /** - * @generate Serial_readChar.xml - * @webref serial:serial - * @usage web_application - */ - public char readChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) read(); - } - - - /** - * @generate Serial_lastChar.xml - * @webref serial:serial - * @usage web_application - */ - public char lastChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) last(); - } - - - /** - * @generate Serial_readBytes.xml - * @webref serial:serial - * @usage web_application - */ - public byte[] readBytes() { - if (bufferIndex == bufferLast) return null; - - synchronized (buffer) { - int length = bufferLast - bufferIndex; - byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex = 0; // rewind - bufferLast = 0; - return outgoing; - } - } - - - /** - *

Advanced

- * Grab whatever is in the serial buffer, and stuff it into a - * byte buffer passed in by the user. This is more memory/time - * efficient than readBytes() returning a byte[] array. - * - * Returns an int for how many bytes were read. If more bytes - * are available than can fit into the byte array, only those - * that will fit are read. - */ - public int readBytes(byte outgoing[]) { - if (bufferIndex == bufferLast) return 0; - - synchronized (buffer) { - int length = bufferLast - bufferIndex; - if (length > outgoing.length) length = outgoing.length; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return length; - } - } - - - /** - * @generate Serial_readBytesUntil.xml - * @webref serial:serial - * @usage web_application - * @param interesting character designated to mark the end of the data - */ - public byte[] readBytesUntil(int interesting) { - if (bufferIndex == bufferLast) return null; - byte what = (byte)interesting; - - synchronized (buffer) { - int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; - break; - } - } - if (found == -1) return null; - - int length = found - bufferIndex + 1; - byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return outgoing; - } - } - - - /** - *

Advanced

- * If outgoing[] is not big enough, then -1 is returned, - * and an error message is printed on the console. - * If nothing is in the buffer, zero is returned. - * If 'interesting' byte is not in the buffer, then 0 is returned. - * @param outgoing passed in byte array to be altered - */ - public int readBytesUntil(int interesting, byte outgoing[]) { - if (bufferIndex == bufferLast) return 0; - byte what = (byte)interesting; - - synchronized (buffer) { - int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; - break; - } - } - if (found == -1) return 0; - - int length = found - bufferIndex + 1; - if (length > outgoing.length) { - System.err.println("readBytesUntil() byte buffer is" + - " too small for the " + length + - " bytes up to and including char " + interesting); - return -1; - } - //byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; - } - return length; - } - } - - - /** - * @generate Serial_readString.xml - * @webref serial:serial - * @usage web_application - */ - public String readString() { - if (bufferIndex == bufferLast) return null; - return new String(readBytes()); - } - - - /** - * @generate Serial_readStringUntil.xml - *

Advanced

- * If you want to move Unicode data, you can first convert the - * String to a byte stream in the representation of your choice - * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. - * - * @webref serial:serial - * @usage web_application - * @param interesting character designated to mark the end of the data - */ - public String readStringUntil(int interesting) { - byte b[] = readBytesUntil(interesting); - if (b == null) return null; - return new String(b); - } - - - /** - *

Advanced

- * This will handle both ints, bytes and chars transparently. - * @param what data to write - */ - public void write(int what) { // will also cover char + public void setDTR(boolean state) { + // there is no way to influence the behavior of the DTR line when opening the serial port + // this means that at least on Linux and OS X, Arduino devices are always reset try { - output.write(what & 0xff); // for good measure do the & - output.flush(); // hmm, not sure if a good idea - - } catch (Exception e) { // null pointer or serial port dead - errorMessage("write", e); + port.setDTR(state); + } catch (SerialPortException e) { + throw new RuntimeException("Error setting the DTR line: "+e.getExceptionType()); } } - /** - * @param bytes[] data to write - */ - public void write(byte bytes[]) { + public void setRTS(boolean state) { try { - output.write(bytes); - output.flush(); // hmm, not sure if a good idea - - } catch (Exception e) { // null pointer or serial port dead - //errorMessage("write", e); - e.printStackTrace(); + port.setRTS(state); + } catch (SerialPortException e) { + throw new RuntimeException("Error setting the RTS line: "+e.getExceptionType()); } } - - /** - * @generate Serial_write.xml - *

Advanced

- * Write a String to the output. Note that this doesn't account - * for Unicode (two bytes per char), nor will it send UTF8 - * characters.. It assumes that you mean to send a byte buffer - * (most often the case for networking and serial i/o) and - * will only use the bottom 8 bits of each char in the string. - * (Meaning that internally it uses String.getBytes) - * - * If you want to move Unicode data, you can first convert the - * String to a byte stream in the representation of your choice - * (i.e. UTF8 or two-byte Unicode data), and send it as a byte array. - * - * @webref serial:serial - * @usage web_application - * @param what data to write - */ - public void write(String what) { - write(what.getBytes()); - } - - - /** - * @generate Serial_list.xml - *

Advanced

- * If this just hangs and never completes on Windows, - * it may be because the DLL doesn't have its exec bit set. - * Why the hell that'd be the case, who knows. - * - * @webref serial - * @usage web_application - */ - static public String[] list() { - Vector list = new Vector(); + public void stop() { try { - //System.err.println("trying"); - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - //System.err.println("got port list"); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); - //System.out.println(portId); - - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { - String name = portId.getName(); - list.addElement(name); - } - } - - } catch (UnsatisfiedLinkError e) { - //System.err.println("1"); - errorMessage("ports", e); - - } catch (Exception e) { - //System.err.println("2"); - errorMessage("ports", e); + port.closePort(); + } catch (SerialPortException e) { } - //System.err.println("move out"); - String outgoing[] = new String[list.size()]; - list.copyInto(outgoing); - return outgoing; + inBuffer = 0; + readOffset = 0; } - - /** - * General error reporting, all corraled here just in case - * I think of something slightly more intelligent to do. - */ - static public void errorMessage(String where, Throwable e) { - e.printStackTrace(); - throw new RuntimeException("Error inside Serial." + where + "()"); - } -} - - - /* - class SerialMenuListener implements ItemListener { - //public SerialMenuListener() { } - - public void itemStateChanged(ItemEvent e) { - int count = serialMenu.getItemCount(); - for (int i = 0; i < count; i++) { - ((CheckboxMenuItem)serialMenu.getItem(i)).setState(false); - } - CheckboxMenuItem item = (CheckboxMenuItem)e.getSource(); - item.setState(true); - String name = item.getLabel(); - //System.out.println(item.getLabel()); - PdeBase.properties.put("serial.port", name); - //System.out.println("set to " + get("serial.port")); - } - } - */ - - - /* - protected Vector buildPortList() { - // get list of names for serial ports - // have the default port checked (if present) - Vector list = new Vector(); - - //SerialMenuListener listener = new SerialMenuListener(); - boolean problem = false; - - // if this is failing, it may be because - // lib/javax.comm.properties is missing. - // java is weird about how it searches for java.comm.properties - // so it tends to be very fragile. i.e. quotes in the CLASSPATH - // environment variable will hose things. + public void write(byte[] src) { try { - //System.out.println("building port list"); - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); - //System.out.println(portId); - - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { - //if (portId.getName().equals(port)) { - String name = portId.getName(); - //CheckboxMenuItem mi = - //new CheckboxMenuItem(name, name.equals(defaultName)); - - //mi.addItemListener(listener); - //serialMenu.add(mi); - list.addElement(name); - } - } - } catch (UnsatisfiedLinkError e) { - e.printStackTrace(); - problem = true; - - } catch (Exception e) { - System.out.println("exception building serial menu"); - e.printStackTrace(); + // this might block if the serial device is not yet ready (esp. tty devices under OS X) + port.writeBytes(src); + // we used to call flush() here + } catch (SerialPortException e) { + throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); } - - //if (serialMenu.getItemCount() == 0) { - //System.out.println("dimming serial menu"); - //serialMenu.setEnabled(false); - //} - - // only warn them if this is the first time - if (problem && PdeBase.firstTime) { - JOptionPane.showMessageDialog(this, //frame, - "Serial port support not installed.\n" + - "Check the readme for instructions\n" + - "if you need to use the serial port. ", - "Serial Port Warning", - JOptionPane.WARNING_MESSAGE); - } - return list; } - */ + public void write(int src) { + try { + port.writeInt(src); + } catch (SerialPortException e) { + throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); + } + } + public void write(String src) { + try { + port.writeString(src); + } catch (SerialPortException e) { + throw new RuntimeException("Error writing to serial port "+e.getPortName()+": "+e.getExceptionType()); + } + } +} \ No newline at end of file