diff --git a/app/lib/RXTXcomm.jar b/app/lib/RXTXcomm.jar index d3d0aec9f..14de2259b 100644 Binary files a/app/lib/RXTXcomm.jar and b/app/lib/RXTXcomm.jar differ diff --git a/app/lib/jssc.jar b/app/lib/jssc.jar deleted file mode 100644 index 8545759c5..000000000 Binary files a/app/lib/jssc.jar and /dev/null differ diff --git a/app/src/processing/app/Editor.java b/app/src/processing/app/Editor.java index dd9d1ffe3..0175da235 100644 --- a/app/src/processing/app/Editor.java +++ b/app/src/processing/app/Editor.java @@ -22,7 +22,6 @@ package processing.app; -import jssc.SerialPortList; import processing.app.debug.*; import processing.app.syntax.*; import processing.app.tools.*; @@ -44,6 +43,8 @@ import javax.swing.event.*; import javax.swing.text.*; import javax.swing.undo.*; +import gnu.io.*; + /** * Main editor panel for the Processing Development Environment. */ @@ -978,19 +979,36 @@ public class Editor extends JFrame implements RunnerListener { serialMenu.removeAll(); boolean empty = true; - String[] portNames = SerialPortList.getPortNames(); - for (String curr_port : portNames) { - rbMenuItem = new JCheckBoxMenuItem(curr_port, curr_port.equals(Preferences.get("serial.port"))); - rbMenuItem.addActionListener(serialMenuListener); - //serialGroup.add(rbMenuItem); - serialMenu.add(rbMenuItem); - empty = false; - } - if (!empty) { - //System.out.println("enabling the serialMenu"); - serialMenu.setEnabled(true); + try + { + for (Enumeration enumeration = CommPortIdentifier.getPortIdentifiers(); enumeration.hasMoreElements();) + { + CommPortIdentifier commportidentifier = (CommPortIdentifier)enumeration.nextElement(); + //System.out.println("Found communication port: " + commportidentifier); + if (commportidentifier.getPortType() == CommPortIdentifier.PORT_SERIAL) + { + //System.out.println("Adding port to serial port menu: " + commportidentifier); + String curr_port = commportidentifier.getName(); + rbMenuItem = new JCheckBoxMenuItem(curr_port, curr_port.equals(Preferences.get("serial.port"))); + rbMenuItem.addActionListener(serialMenuListener); + //serialGroup.add(rbMenuItem); + serialMenu.add(rbMenuItem); + empty = false; + } + } + if (!empty) { + //System.out.println("enabling the serialMenu"); + serialMenu.setEnabled(true); + } + } + catch (Exception exception) + { + System.out.println(_("error retrieving port list")); + exception.printStackTrace(); + } + if (serialMenu.getItemCount() == 0) { serialMenu.setEnabled(false); } diff --git a/app/src/processing/app/Serial.java b/app/src/processing/app/Serial.java index c1caaec4a..5537f9275 100644 --- a/app/src/processing/app/Serial.java +++ b/app/src/processing/app/Serial.java @@ -25,10 +25,11 @@ package processing.app; //import processing.core.*; -import jssc.*; import processing.app.debug.MessageConsumer; import static processing.app.I18n._; +import gnu.io.*; + import java.io.*; import java.util.*; @@ -52,6 +53,15 @@ public class Serial implements SerialPortEventListener { int stopbits; boolean monitor = false; + // read buffer and streams + + InputStream input; + OutputStream output; + + byte buffer[] = new byte[32768]; + int bufferIndex; + int bufferLast; + MessageConsumer consumer; public Serial(boolean monitor) throws SerialException { @@ -92,15 +102,30 @@ public class Serial implements SerialPortEventListener { } public static boolean touchPort(String iname, int irate) throws SerialException { - SerialPort port = new SerialPort(iname); + SerialPort port; + boolean result = false; try { - port.openPort(); - port.setParams(irate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, false, true); - port.closePort(); - return true; - } catch (SerialPortException e) { - throw new SerialException(I18n.format(_("Error touching serial port ''{0}''."), iname), e); + @SuppressWarnings("unchecked") + Enumeration portList = CommPortIdentifier.getPortIdentifiers(); + while (portList.hasMoreElements()) { + CommPortIdentifier portId = portList.nextElement(); + if ((CommPortIdentifier.PORT_SERIAL == portId.getPortType()) && (portId.getName().equals(iname))) { + port = (SerialPort) portId.open("tap", 2000); + port.setSerialPortParams(irate, 8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE); + port.close(); + result = true; + } + } + } catch (PortInUseException e) { + throw new SerialException( + I18n.format(_("Serial port ''{0}'' already in use. Try quitting any programs that may be using it."), iname) + ); + } catch (Exception e) { + throw new SerialException( + I18n.format(_("Error touching serial port ''{0}''."), iname), e + ); } + return result; } public Serial(String iname, int irate, @@ -123,15 +148,46 @@ public class Serial implements SerialPortEventListener { if (istopbits == 2) stopbits = SerialPort.STOPBITS_2; try { - port = new SerialPort(iname); + port = null; + @SuppressWarnings("unchecked") + Enumeration portList = CommPortIdentifier.getPortIdentifiers(); + while (portList.hasMoreElements()) { + CommPortIdentifier portId = portList.nextElement(); - //System.out.println("looking for "+iname); - port.openPort(); - port.setParams(rate, databits, stopbits, parity, false, true); - port.addEventListener(this); - //System.out.println("opening, ready to roll"); - } catch (SerialPortException e) { - throw new SerialException(I18n.format(_("Error opening serial port ''{0}''."),iname),e); + if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { + //System.out.println("found " + portId.getName()); + if (portId.getName().equals(iname)) { + //System.out.println("looking for "+iname); + port = (SerialPort)portId.open("serial madness", 2000); + port.setDTR(true); + port.setRTS(true); + 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"); + } + } + } + } catch (PortInUseException e) { + throw new SerialException( + I18n.format( + _("Serial port ''{0}'' already in use. Try quiting any programs that may be using it."), + iname + ) + ); + } catch (Exception e) { + throw new SerialException( + I18n.format( + _("Error opening serial port ''{0}''."), + iname + ), + e + ); +// //errorMessage("", e); +// //exception = e; +// //e.printStackTrace(); } if (port == null) { @@ -165,7 +221,18 @@ public class Serial implements SerialPortEventListener { public void dispose() { try { - if (port != null) port.closePort(); // close the port + // do io streams need to be closed first? + if (input != null) input.close(); + if (output != null) output.close(); + + } catch (Exception e) { + e.printStackTrace(); + } + input = null; + output = null; + + try { + if (port != null) port.close(); // close the port } catch (Exception e) { e.printStackTrace(); @@ -179,34 +246,270 @@ public class Serial implements SerialPortEventListener { } - public synchronized void serialEvent(SerialPortEvent serialEvent) { - switch (serialEvent.getEventType()) { - case SerialPortEvent.RXCHAR: - case SerialPortEvent.RXFLAG: - try { - byte[] bytes = port.readBytes(); - String bytesAsString = new String(bytes); - if(monitor) { - System.out.print(bytesAsString); + synchronized public void serialEvent(SerialPortEvent serialEvent) { + //System.out.println("serial port event"); // " + serialEvent); + //System.out.flush(); + //System.out.println("into"); + //System.out.flush(); + //System.err.println("type " + serialEvent.getEventType()); + //System.err.println("ahoooyey"); + //System.err.println("ahoooyeysdfsdfsdf"); + if (serialEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { + //System.out.println("data available"); + //System.err.flush(); + try { + while (input.available() > 0) { + //if (input.available() > 0) { + //serial = input.read(); + //serialEvent(); + //buffer[bufferCount++] = (byte) serial; + synchronized (buffer) { + if (bufferLast == buffer.length) { + byte temp[] = new byte[bufferLast << 1]; + System.arraycopy(buffer, 0, temp, 0, bufferLast); + buffer = temp; + } + //buffer[bufferLast++] = (byte) input.read(); + if(monitor == true) + System.out.print((char) input.read()); + if (this.consumer != null) + this.consumer.message("" + (char) input.read()); + + /* + System.err.println(input.available() + " " + + ((char) buffer[bufferLast-1])); + */ //} } - if (this.consumer != null) { - this.consumer.message(bytesAsString); - } - } catch (SerialPortException e) { - errorMessage("serialEvent", e); } + //System.out.println("no more"); + + } catch (IOException e) { + errorMessage("serialEvent", e); + //e.printStackTrace(); + //System.out.println("angry"); + } + catch (Exception e) { + } + } + //System.out.println("out of"); + //System.err.println("out of event " + serialEvent.getEventType()); + } + + + /** + * Returns the number of bytes that have been read from serial + * and are waiting to be dealt with by the user. + */ + public int available() { + return (bufferLast - bufferIndex); + } + + + /** + * Ignore all the bytes read so far and empty the buffer. + */ + public void clear() { + bufferLast = 0; + bufferIndex = 0; + } + + + /** + * Returns a number between 0 and 255 for the next byte that's + * waiting in the buffer. + * Returns -1 if there was no byte (although the user should + * first check available() to see if things are ready to avoid this) + */ + 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; } } + /** + * Returns the next byte in the buffer as a char. + * Returns -1, or 0xffff, if nothing is there. + */ + public char readChar() { + if (bufferIndex == bufferLast) return (char)(-1); + return (char) read(); + } + + + /** + * Return a byte array of anything that's in the serial buffer. + * Not particularly memory/speed efficient, because it creates + * a byte array on each read, but it's easier to use than + * readBytes(byte b[]) (see below). + */ + 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; + } + } + + + /** + * 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; + } + } + + + /** + * Reads from the serial port into a buffer of bytes up to and + * including a particular character. If the character isn't in + * the serial buffer, then 'null' is returned. + */ + 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 = 0; // rewind + bufferLast = 0; + return outgoing; + } + } + + + /** + * Reads from the serial port into a buffer of bytes until a + * particular character. If the character isn't in the serial + * buffer, then 'null' is returned. + * + * 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. + */ + 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( + I18n.format( + _("readBytesUntil() byte buffer is too small for the {0}" + + " bytes up to and including char {1}"), + length, + 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; + } + } + + + /** + * Return whatever has been read from the serial port so far + * as a String. It assumes that the incoming characters are ASCII. + * + * 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. + */ + public String readString() { + if (bufferIndex == bufferLast) return null; + return new String(readBytes()); + } + + + /** + * Combination of readBytesUntil and readString. See caveats in + * each function. Returns null if it still hasn't found what + * you're looking for. + * + * 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. + */ + public String readStringUntil(int interesting) { + byte b[] = readBytesUntil(interesting); + if (b == null) return null; + return new String(b); + } + /** * This will handle both ints, bytes and chars transparently. */ - public void write(int what) { + public void write(int what) { // will also cover char try { - port.writeInt(what & 0xff); // for good measure do the & - } catch (SerialPortException e) { // null pointer or serial port dead + 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); } } @@ -214,9 +517,12 @@ public class Serial implements SerialPortEventListener { public void write(byte bytes[]) { try { - port.writeBytes(bytes); - } catch (SerialPortException e) { - errorMessage("write", e); + 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(); } } @@ -238,19 +544,11 @@ public class Serial implements SerialPortEventListener { } public void setDTR(boolean state) { - try { - port.setDTR(state); - } catch (SerialPortException e) { - errorMessage("write", e); - } + port.setDTR(state); } public void setRTS(boolean state) { - try { - port.setRTS(state); - } catch (SerialPortException e) { - errorMessage("write", e); - } + port.setRTS(state); } /** @@ -259,7 +557,33 @@ public class Serial implements SerialPortEventListener { * Why the hell that'd be the case, who knows. */ static public List list() { - return Arrays.asList(SerialPortList.getPortNames()); + List list = new ArrayList(); + try { + //System.err.println("trying"); + @SuppressWarnings("unchecked") + 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.add(name); + } + } + + } catch (UnsatisfiedLinkError e) { + //System.err.println("1"); + errorMessage("ports", e); + + } catch (Exception e) { + //System.err.println("2"); + errorMessage("ports", e); + } + //System.err.println("move out"); + return list; } diff --git a/app/src/processing/app/debug/Uploader.java b/app/src/processing/app/debug/Uploader.java index d7610ef2d..50d7a5e13 100644 --- a/app/src/processing/app/debug/Uploader.java +++ b/app/src/processing/app/debug/Uploader.java @@ -34,7 +34,9 @@ import java.util.Collection; import processing.app.I18n; import processing.app.Preferences; +import processing.app.Serial; import processing.app.SerialException; +import processing.app.SerialNotFoundException; public abstract class Uploader implements MessageConsumer { static final String BUGS_URL = @@ -53,8 +55,7 @@ public abstract class Uploader implements MessageConsumer { throws RunnerException, SerialException; public abstract boolean burnBootloader() throws RunnerException; - - /* + protected void flushSerialBuffer() throws RunnerException, SerialException { // Cleanup the serial buffer try { @@ -84,7 +85,6 @@ public abstract class Uploader implements MessageConsumer { throw new RunnerException(e.getMessage()); } } - */ protected boolean executeUploadCommand(Collection commandDownloader) throws RunnerException {