diff --git a/IDE/processing/app/Base.java b/IDE/processing/app/Base.java index e00b33d..cdb5b9f 100644 --- a/IDE/processing/app/Base.java +++ b/IDE/processing/app/Base.java @@ -27,6 +27,7 @@ import java.io.*; import java.text.SimpleDateFormat; import java.util.*; +import java.net.*; import javax.swing.*; @@ -42,8 +43,8 @@ * files and images, etc) that comes from that. */ public class Base { - public static final int REVISION = 100; - static String VERSION_NAME = "0100"; + public static final int REVISION = 101; + static String VERSION_NAME = "0101"; /** Set true if this a proper release rather than a numbered revision. */ static public boolean RELEASE = false; /** True if heavy debugging error/log messages are enabled */ @@ -2259,8 +2260,62 @@ static public int showYesNoQuestion(Frame editor, String title, } } + static public String urlDecode(String str) { + try { + return URLDecoder.decode(str, "UTF-8"); + } catch (UnsupportedEncodingException e) { // safe per the JDK source + return null; + } + } + /** + * Adjacent the executable on Windows and Linux, + * or inside Contents/Resources/Java on Mac OS X. + */ + static protected File wiringRoot; + + static public File getContentFile(String name) { + if (wiringRoot == null) { + // Get the path to the .jar file that contains Base.class + String path = Base.class.getProtectionDomain().getCodeSource().getLocation().getPath(); + // Path may have URL encoding, so remove it + String decodedPath = urlDecode(path); + + if (decodedPath.contains("/app/bin")) { + if (Base.isMacOS()) { + wiringRoot = + new File(path, "../../build/macosx/work/Processing.app/Contents/Java"); + } else if (Base.isWindows()) { + wiringRoot = new File(path, "../../build/windows/work"); + } else if (Base.isLinux()) { + wiringRoot = new File(path, "../../build/linux/work"); + } + } else { + // The .jar file will be in the lib folder + File jarFolder = new File(decodedPath).getParentFile(); + if (jarFolder.getName().equals("lib")) { + // The main Processing installation directory. + // This works for Windows, Linux, and Apple's Java 6 on OS X. + wiringRoot = jarFolder.getParentFile(); + } else if (Base.isMacOS()) { + // This works for Java 7 on OS X. The 'lib' folder is not part of the + // classpath on OS X, and adding it creates more problems than it's + // worth. + wiringRoot = jarFolder; + + } + if (wiringRoot == null || !wiringRoot.exists()) { + // Try working directory instead (user.dir, different from user.home) + System.err.println("Could not find lib folder via " + + jarFolder.getAbsolutePath() + + ", switching to user.dir"); + wiringRoot = new File(System.getProperty("user.dir")); + } + } + } + + /* String path = System.getProperty("user.dir"); // Get a path to somewhere inside the .app folder @@ -2271,7 +2326,8 @@ static public File getContentFile(String name) { } } File working = new File(path); - return new File(working, name); + */ + return new File(wiringRoot, name); } @@ -2305,6 +2361,17 @@ static public Image getLibImage(String name, Component who) { * Return an InputStream for a file inside the Processing lib folder. */ static public InputStream getLibStream(String filename) throws IOException { + /* + Properties p = System.getProperties(); + Enumeration keys = p.keys(); + String res = new String(); + while (keys.hasMoreElements()) { + String key = (String)keys.nextElement(); + String value = (String)p.get(key); + res += key + ": " + value+ "\n"; + } + showMessage("HERE ", getContentFile("lib").getAbsolutePath() +"XXX"+ System.getProperty("os.name")+"XXX"+res); + */ return new FileInputStream(new File(getContentFile("lib"), filename)); } diff --git a/IDE/processing/app/Editor.java b/IDE/processing/app/Editor.java index b4b3651..5f2b1df 100644 --- a/IDE/processing/app/Editor.java +++ b/IDE/processing/app/Editor.java @@ -43,7 +43,7 @@ import javax.swing.undo.*; import java.util.regex.*; -import gnu.io.*; +import jssc.*; /** * Main editor panel for the Processing Development Environment. @@ -868,7 +868,20 @@ protected void populateSerialMenu() { try { - for (Enumeration enumeration = CommPortIdentifier.getPortIdentifiers(); enumeration.hasMoreElements();) + Vector ports = new Vector(Arrays.asList(SerialPortList.getPortNames())); + Enumeration portList = ports.elements(); + + while (portList.hasMoreElements()) { + String portId = + (String) portList.nextElement(); + rbMenuItem = new JCheckBoxMenuItem(portId, portId.equals(Preferences.get("serial.port"))); + rbMenuItem.addActionListener(serialMenuListener); + //serialGroup.add(rbMenuItem); + serialMenu.add(rbMenuItem); + empty = false; + } + + /*for (Enumeration enumeration = CommPortIdentifier.getPortIdentifiers(); enumeration.hasMoreElements();) { CommPortIdentifier commportidentifier = (CommPortIdentifier)enumeration.nextElement(); //System.out.println("Found communication port: " + commportidentifier); @@ -882,7 +895,7 @@ protected void populateSerialMenu() { serialMenu.add(rbMenuItem); empty = false; } - } + }*/ if (!empty) { //System.out.println("enabling the serialMenu"); serialMenu.setEnabled(true); @@ -924,21 +937,21 @@ protected JMenu buildSerialMenu() { // environment variable will hose things. try { //System.out.println("building port list"); - for( Enumeration portList = CommPortIdentifier.getPortIdentifiers(); portList.hasMoreElements();) + Vector ports = new Vector(Arrays.asList(SerialPortList.getPortNames())); + Enumeration portList = ports.elements(); + + while( portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); + String portId = (String) portList.nextElement(); //System.out.println(portId); - if (portId.getPortType() == CommPortIdentifier.PORT_SERIAL) { //if (portId.getName().equals(port)) { - String name = portId.getName(); + String name = portId; JCheckBoxMenuItem mi = new JCheckBoxMenuItem(name, name.equals(defaultName)); mi.addActionListener(listener); //mi.addItemListener(listener); serialMenu.add(mi); - } } } catch (UnsatisfiedLinkError e) { e.printStackTrace(); diff --git a/IDE/processing/app/Serial.java b/IDE/processing/app/Serial.java index 850e70b..841681f 100644 --- a/IDE/processing/app/Serial.java +++ b/IDE/processing/app/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 @@ -23,682 +24,487 @@ */ package processing.app; -//import processing.core.*; -import processing.app.debug.MessageConsumer; - -import gnu.io.*; - -import java.io.*; -import java.util.*; import java.lang.reflect.*; +import java.util.Map; +import processing.app.debug.MessageConsumer; -public class Serial implements SerialPortEventListener { - - //PApplet parent; - Method serialEventMethod; - - // properties can be passed in for default values - // otherwise defaults to 9600 N81 +import jssc.*; - // 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 +public class Serial implements SerialPortEventListener { public SerialPort port; + Method serialAvailableMethod; + Method serialEventMethod; - public int rate; - public int parity; - public int databits; - public int stopbits; - public boolean monitor = false; - - // read buffer and streams - - public InputStream input; - public OutputStream output; - - byte buffer[] = new byte[32768]; - int bufferIndex; - int bufferLast; + byte[] buffer = new byte[32768]; + int inBuffer = 0; + int readOffset = 0; - //boolean bufferUntil = false; - int bufferSize = 1; // how big before reset or event firing - boolean bufferUntil; - int bufferUntilByte; + int bufferUntilSize = 1; + byte bufferUntilByte = 0; + volatile boolean invokeSerialAvailable = false; + MessageConsumer consumer; + public boolean monitor = false; - // defaults - - static String dname = Preferences.get("serial.port"); //"COM1"; - static int drate = 115200; - static char dparity = 'N'; - static int ddatabits = 8; - static float dstopbits = 1; - + // Things we are currently not exposing: + // * hardware flow control + // * state of the RING, RLSD line + // * sending breaks - public Serial(boolean monitor) throws SerialException { + + public Serial() throws SerialException { this(Preferences.get("serial.port"), Preferences.getInteger("serial.rate"), Preferences.get("serial.parity").charAt(0), Preferences.getInteger("serial.databits"), new Float(Preferences.get("serial.stopbits")).floatValue()); - this.monitor = monitor; } - - public Serial() throws SerialException { + + public Serial(boolean monitor) throws SerialException { this(Preferences.get("serial.port"), Preferences.getInteger("serial.rate"), Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), + Preferences.getInteger("serial.databits"), new Float(Preferences.get("serial.stopbits")).floatValue()); + this.monitor = monitor; } + - public Serial(int irate) throws SerialException { - this(Preferences.get("serial.port"), irate, + public Serial(int baudRate) throws SerialException { + this(Preferences.get("serial.port"), baudRate, Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), + Preferences.getInteger("serial.databits"), new Float(Preferences.get("serial.stopbits")).floatValue()); } + - public Serial(String iname, int irate) throws SerialException { - this(iname, irate, Preferences.get("serial.parity").charAt(0), - Preferences.getInteger("serial.databits"), + public Serial(String portName) throws SerialException { + this(portName, Preferences.getInteger("serial.rate"), + Preferences.get("serial.parity").charAt(0), + Preferences.getInteger("serial.databits"), new Float(Preferences.get("serial.stopbits")).floatValue()); } + - public Serial(String iname) throws SerialException { - this(iname, Preferences.getInteger("serial.rate"), + public Serial(String portName, int baudRate) throws SerialException { + this(portName, baudRate, Preferences.get("serial.parity").charAt(0), Preferences.getInteger("serial.databits"), new Float(Preferences.get("serial.stopbits")).floatValue()); } - - public Serial(String iname, int irate, - char iparity, int idatabits, float istopbits) throws SerialException { - //if (port != null) port.close(); - //this.parent = parent; - //parent.attach(this); - - this.rate = irate; - - 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; - try { - Enumeration portList = CommPortIdentifier.getPortIdentifiers(); - while (portList.hasMoreElements()) { - CommPortIdentifier portId = - (CommPortIdentifier) portList.nextElement(); - - 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"); - } - } - } - - } catch (PortInUseException e) { - throw new SerialException("Serial port " + iname + " already in use. Check no other program is using it.", e); - } catch (Exception e) { - port = null; - input = null; - output = null; - throw new SerialException("Error opening serial port "+ iname + ".", e); + + public Serial(String portName, int baudRate, char parity, int dataBits, float stopBits) throws SerialException { +// parent.registerMethod("dispose", this); +// parent.registerMethod("pre", this); + + // 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; } - if (port == null) { - //System.err.println("Serial port '" + iname + "' not found. Did you select the right one from the Tools > Serial Port menu?"); - throw new SerialException("Serial port '" + iname + "' not found. Did you select the right one from the Tools > Serial Port menu?"); + // 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; } - } - - - /*public void setMonitor(boolean monitor) - { - this.monitor = monitor; - }*/ - - /** - * Stop talking to serial and shut things down. - *

- * Basically just a user-accessible version of dispose(). - * For now, it just calls dispose(), but dispose shouldn't - * be called from applets, because in some libraries, - * dispose() blows shit up if it's called by a user who - * doesn't know what they're doing. - */ - public void stop() { - dispose(); - } - - /** - * Used by PApplet to shut things down. - */ - public void dispose() { + port = new SerialPort(portName); try { - // do io streams need to be closed first? - if (input != null) input.close(); - if (output != null) output.close(); - - } catch (Exception e) { - e.printStackTrace(); + // 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()); } - input = null; - output = null; - try { - if (port != null) port.close(); // close the port +// serialEventMethod = findCallback("serialEvent"); +// serialAvailableMethod = findCallback("serialAvailable"); + } + /*private Method findCallback(final String name) { + try { + return parent.getClass().getMethod(name, this.getClass()); } catch (Exception e) { - e.printStackTrace(); } - port = null; - } - - public void reset() { + // Permit callback(Object) as alternative to callback(Serial). try { - if (port != null) port.setDTR(true); // close the port + return parent.getClass().getMethod(name, Object.class); } catch (Exception e) { - e.printStackTrace(); } - - } - - /** - * Set the DTR line. Addition from Tom Hulbert. - */ - public void setDTR(boolean state) { - port.setDTR(state); - } - - public void setRTS(boolean state) { - port.setRTS(state); - } + return null; + }*/ - public void addListener(MessageConsumer consumer) { - this.consumer = consumer; + public void dispose() { + stop(); } + - - synchronized public void serialEvent(SerialPortEvent serialEvent) { - if (serialEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE) { + /*public void pre() { + if (serialAvailableMethod != null && invokeSerialAvailable) { + invokeSerialAvailable = false; try { - while ((input != null)&&(input.available() > 0)) { - 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()); - -// if (serialEventMethod != null) { -// if ((bufferUntil && -// (buffer[bufferLast-1] == bufferUntilByte)) || -// (!bufferUntil && -// ((bufferLast - bufferIndex) >= bufferSize))) { -// try { -// serialEventMethod.invoke(parent, new Object[] { this }); -// } catch (Exception e) { -// String msg = "error, disabling serialEvent() for " + port; -// System.err.println(msg); -// e.printStackTrace(); -// serialEventMethod = null; -// } -// } -// } - } - } - - } catch (IOException e) { - errorMessage("serialEvent", e); - } - catch (Exception e) { + serialAvailableMethod.invoke(parent, this); + } catch (Exception e) { + System.err.println("Error, disabling serialAvailable() for "+port.getPortName()); + System.err.println(e.getLocalizedMessage()); + serialAvailableMethod = null; } } - } + }*/ - /** - * Set number of bytes to buffer before calling serialEvent() - * in the host applet. - */ - public void buffer(int count) { - bufferUntil = false; - bufferSize = count; + public int available() { + return (inBuffer-readOffset); } - - /** - * Set a specific byte to buffer until before calling - * serialEvent() in the host applet. - */ - public void bufferUntil(int what) { - bufferUntil = true; - bufferUntilByte = what; + + public void buffer(int size) { + bufferUntilSize = size; } - - /** - * 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); + + public void bufferUntil(int inByte) { + bufferUntilSize = 0; + bufferUntilByte = (byte)inByte; } - - /** - * Ignore all the bytes read so far and empty the buffer. - */ + public void clear() { - bufferLast = 0; - bufferIndex = 0; + synchronized (buffer) { + inBuffer = 0; + readOffset = 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; + public boolean getCTS() { + try { + return port.isCTS(); + } catch (SerialPortException e) { + throw new RuntimeException("Error reading the CTS line: " + e.getExceptionType()); + } + } - synchronized (buffer) { - int outgoing = buffer[bufferIndex++] & 0xff; - if (bufferIndex == bufferLast) { // rewind - bufferIndex = 0; - bufferLast = 0; - } - return outgoing; + + 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) { + return SerialPortList.getPortProperties(portName); + } + - /** - * 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. - */ public int last() { - if (bufferIndex == bufferLast) return -1; + if (inBuffer == readOffset) { + return -1; + } + synchronized (buffer) { - int outgoing = buffer[bufferLast-1]; - bufferIndex = 0; - bufferLast = 0; - return outgoing; + int ret = buffer[inBuffer-1] & 0xFF; + inBuffer = 0; + readOffset = 0; + return ret; } } + + public char lastChar() { + return (char)last(); + } - /** - * 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(); + + public static String[] list() { + // returns list sorted alphabetically, thus cu.* comes before tty.* + // this was different with RXTX + return SerialPortList.getPortNames(); } + + public int read() { + if (inBuffer == readOffset) { + return -1; + } - /** - * Just like last() and readChar(). - */ - public char lastChar() { - if (bufferIndex == bufferLast) return (char)(-1); - return (char) last(); + synchronized (buffer) { + int ret = buffer[readOffset++] & 0xFF; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; + } + return ret; + } } - - /** - * 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; + if (inBuffer == readOffset) { + 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; + byte[] ret = new byte[inBuffer-readOffset]; + System.arraycopy(buffer, readOffset, ret, 0, ret.length); + inBuffer = 0; + readOffset = 0; + return ret; } } + - - /** - * 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; + public int readBytes(byte[] dest) { + if (inBuffer == readOffset) { + 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; + 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 length; + return toCopy; } } + - - /** - * 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; + public byte[] readBytesUntil(int inByte) { + if (inBuffer == readOffset) { + return null; + } synchronized (buffer) { + // look for needle in buffer int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; + for (int i=readOffset; i < inBuffer; i++) { + if (buffer[i] == (byte)inByte) { + found = i; break; } } - if (found == -1) return null; - - int length = found - bufferIndex + 1; - byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); + if (found == -1) { + return null; + } - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; + 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; } - return outgoing; + return dest; } } - - /** - * 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; + + public int readBytesUntil(int inByte, byte[] dest) { + if (inBuffer == readOffset) { + return 0; + } synchronized (buffer) { + // look for needle in buffer int found = -1; - for (int k = bufferIndex; k < bufferLast; k++) { - if (buffer[k] == what) { - found = k; + for (int i=readOffset; i < inBuffer; i++) { + if (buffer[i] == (byte)inByte) { + found = i; break; } } - if (found == -1) return 0; + 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); + // 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; } - //byte outgoing[] = new byte[length]; - System.arraycopy(buffer, bufferIndex, outgoing, 0, length); - - bufferIndex += length; - if (bufferIndex == bufferLast) { - bufferIndex = 0; // rewind - bufferLast = 0; + System.arraycopy(buffer, readOffset, dest, 0, toCopy); + readOffset += toCopy; + if (inBuffer == readOffset) { + inBuffer = 0; + readOffset = 0; } - return length; + return toCopy; } } + + public char readChar() { + return (char) read(); + } - /** - * 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; + if (inBuffer == readOffset) { + 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); + + public String readStringUntil(int inByte) { + byte temp[] = readBytesUntil(inByte); + if (temp == null) { + return null; + } else { + return new String(temp); + } } - /** - * This will handle both ints, bytes and chars transparently. - */ - public void write(int what) { // will also cover char - try { - output.write(what & 0xff); // for good measure do the & - output.flush(); // hmm, not sure if a good idea + public void addListener(MessageConsumer consumer) { + this.consumer = consumer; + } - } catch (Exception e) { // null pointer or serial port dead - errorMessage("write", e); + + public void serialEvent(SerialPortEvent event) { + if (event.getEventType() == SerialPortEvent.RXCHAR) { + int toRead; + try { + while (0 < (toRead = port.getInputBufferBytesCount())) { + // this method can be called from the context of another thread + synchronized (buffer) { + // read one byte at a time if the sketch is using serialEvent + if (serialEventMethod != null) { + toRead = 1; + } + // 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; + } + // 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(monitor == true) + System.out.print((char) read()); + if (this.consumer != null) + this.consumer.message("" + (char) read()); + } + /*if (serialEventMethod != null) { + 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, this); + } catch (Exception e) { + System.err.println("Error, disabling serialEvent() for "+port.getPortName()); + System.err.println(e.getLocalizedMessage()); + serialEventMethod = null; + } + } + } + invokeSerialAvailable = true; + */ + } + } catch (SerialPortException e) { + throw new RuntimeException("Error reading from serial port " + e.getPortName() + ": " + e.getExceptionType()); + } } } - - public void write(byte bytes[]) { + + 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(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.setDTR(state); + } catch (SerialPortException e) { + throw new RuntimeException("Error setting the DTR line: " + e.getExceptionType()); } } - - /** - * 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. - */ - public void write(String what) { - write(what.getBytes()); - } - - - /** - * 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. - */ - static public String[] list() { - Vector list = new Vector(); + + public void setRTS(boolean state) { 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.setRTS(state); + } catch (SerialPortException e) { + throw new RuntimeException("Error setting the RTS line: " + e.getExceptionType()); } - //System.err.println("move out"); - String outgoing[] = new String[list.size()]; - list.copyInto(outgoing); - return outgoing; } - - /** - * 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 + "()"); + + public void stop() { + try { + port.closePort(); + } catch (SerialPortException e) { + // ignored + } + inBuffer = 0; + readOffset = 0; } -} - - /* - 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")); + + public void write(byte[] src) { + try { + // 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()); } } - */ - - /* - 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(int 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(); + port.writeInt(src); + } 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); + + public void write(String src) { + try { + port.writeString(src); + } catch (SerialPortException e) { + throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType()); } - return list; } - */ - - +} diff --git a/IDE/processing/app/SerialException.java b/IDE/processing/app/SerialException.java index 525c240..d8fdcf4 100644 --- a/IDE/processing/app/SerialException.java +++ b/IDE/processing/app/SerialException.java @@ -20,6 +20,7 @@ package processing.app; + public class SerialException extends Exception { public SerialException() { super(); diff --git a/IDE/processing/app/debug/AvrdudeUploader.java b/IDE/processing/app/debug/AvrdudeUploader.java index ff0644d..2c97188 100644 --- a/IDE/processing/app/debug/AvrdudeUploader.java +++ b/IDE/processing/app/debug/AvrdudeUploader.java @@ -34,7 +34,7 @@ import java.util.*; import java.util.zip.*; import javax.swing.*; -import gnu.io.*; +import jssc.*; public class AvrdudeUploader extends Uploader { diff --git a/IDE/processing/app/debug/Uploader.java b/IDE/processing/app/debug/Uploader.java index e7dad8d..741c005 100644 --- a/IDE/processing/app/debug/Uploader.java +++ b/IDE/processing/app/debug/Uploader.java @@ -28,7 +28,7 @@ import java.util.*; import java.util.zip.*; import javax.swing.*; -import gnu.io.*; +import jssc.*; public abstract class Uploader implements MessageConsumer{ diff --git a/build.xml b/build.xml index c968cdc..4f27673 100644 --- a/build.xml +++ b/build.xml @@ -64,7 +64,7 @@ - + @@ -210,9 +210,9 @@ - - + diff --git a/build/macosx/plat-build.xml b/build/macosx/plat-build.xml index 0755337..bf274b4 100644 --- a/build/macosx/plat-build.xml +++ b/build/macosx/plat-build.xml @@ -5,20 +5,36 @@ Configuration ============= --> + + + + + + + + + + + + + + + location="${dist.app}/Contents/Java"/> + @@ -39,19 +55,109 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + @@ -73,12 +179,38 @@ files). Rather than mess with java.library.path elsewhere, we'll just hack it like this for now. --> - + + + Code signing will only work if you have a $99/yr Apple developer ID. + + With a proper ID, if code signing fails, you may need to use: + export CODESIGN_ALLOCATE="/Applications/Xcode.app/Contents/Developer/usr/bin/codesign_allocate" + + + + + + + + + + + + + + + + + + + + @@ -87,6 +219,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ======================================================= + Wiring for Mac OS X was built. Grab it from + + out/dist/wiring-${version}-macosx.zip + ======================================================= + + + diff --git a/build/shared/lib/serial/RXTXcomm.jar b/build/shared/lib/serial/RXTXcomm.jar deleted file mode 100755 index afb4b16..0000000 Binary files a/build/shared/lib/serial/RXTXcomm.jar and /dev/null differ diff --git a/build/shared/lib/serial/export.txt b/build/shared/lib/serial/export.txt old mode 100644 new mode 100755 index ceaaca1..1d262aa --- a/build/shared/lib/serial/export.txt +++ b/build/shared/lib/serial/export.txt @@ -1,4 +1 @@ name = Serial I/O -application.macosx = serial.jar, RXTXcomm.jar, librxtxSerial.jnilib -application.windows = serial.jar, RXTXcomm.jar, rxtxSerial.dll -application.linux = serial.jar, RXTXcomm.jar, librxtxSerial.so diff --git a/build/shared/lib/serial/jssc.jar b/build/shared/lib/serial/jssc.jar new file mode 100644 index 0000000..93269cf Binary files /dev/null and b/build/shared/lib/serial/jssc.jar differ diff --git a/build/shared/lib/serial/jssc.txt b/build/shared/lib/serial/jssc.txt new file mode 100644 index 0000000..7174ece --- /dev/null +++ b/build/shared/lib/serial/jssc.txt @@ -0,0 +1,4 @@ +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. + +To compile the C++ portion of the library on OS X: +g++ -shared [or: -dynamiclib?] -arch i386 -arch x86_64 -I/System/Library/Frameworks/IOKit.framework/Versions/A/Headers -I$JAVA_HOME/include -I$JAVA_HOME/include/darwin -framework IOKit -framework CoreFoundation -o libjSSC-2.6.jnilib jssc.cpp diff --git a/build/shared/lib/serial/librxtxSerial.jnilib b/build/shared/lib/serial/librxtxSerial.jnilib deleted file mode 100755 index 6dfbdd6..0000000 Binary files a/build/shared/lib/serial/librxtxSerial.jnilib and /dev/null differ diff --git a/build/shared/lib/serial/linux-i686/librxtxSerial.so b/build/shared/lib/serial/linux-i686/librxtxSerial.so deleted file mode 100644 index 1ce4ebe..0000000 Binary files a/build/shared/lib/serial/linux-i686/librxtxSerial.so and /dev/null differ diff --git a/build/shared/lib/serial/linux-x86_64/librxtxSerial.so b/build/shared/lib/serial/linux-x86_64/librxtxSerial.so deleted file mode 100755 index 470dbfa..0000000 Binary files a/build/shared/lib/serial/linux-x86_64/librxtxSerial.so and /dev/null differ diff --git a/build/shared/lib/serial/linux32/libjSSC-2.8.so b/build/shared/lib/serial/linux32/libjSSC-2.8.so new file mode 100644 index 0000000..8ea5d6e Binary files /dev/null and b/build/shared/lib/serial/linux32/libjSSC-2.8.so differ diff --git a/build/shared/lib/serial/linux64/libjSSC-2.8.so b/build/shared/lib/serial/linux64/libjSSC-2.8.so new file mode 100644 index 0000000..1108cb5 Binary files /dev/null and b/build/shared/lib/serial/linux64/libjSSC-2.8.so differ diff --git a/build/shared/lib/serial/macosx/libjSSC-2.8.jnilib b/build/shared/lib/serial/macosx/libjSSC-2.8.jnilib new file mode 100755 index 0000000..012a168 Binary files /dev/null and b/build/shared/lib/serial/macosx/libjSSC-2.8.jnilib differ diff --git a/build/shared/lib/serial/rxtxSerial.dll b/build/shared/lib/serial/rxtxSerial.dll deleted file mode 100755 index c5ae7a7..0000000 Binary files a/build/shared/lib/serial/rxtxSerial.dll and /dev/null differ diff --git a/build/shared/lib/serial/serial.jar b/build/shared/lib/serial/serial.jar old mode 100755 new mode 100644 index 48864fa..d579d59 Binary files a/build/shared/lib/serial/serial.jar and b/build/shared/lib/serial/serial.jar differ diff --git a/build/shared/lib/serial/windows32/jSSC-2.8.dll b/build/shared/lib/serial/windows32/jSSC-2.8.dll new file mode 100644 index 0000000..8ff7541 Binary files /dev/null and b/build/shared/lib/serial/windows32/jSSC-2.8.dll differ diff --git a/build/shared/lib/serial/windows64/jSSC-2.8.dll b/build/shared/lib/serial/windows64/jSSC-2.8.dll new file mode 100644 index 0000000..d4e19e0 Binary files /dev/null and b/build/shared/lib/serial/windows64/jSSC-2.8.dll differ diff --git a/todo.txt b/todo.txt index aa467f3..9622f44 100644 --- a/todo.txt +++ b/todo.txt @@ -1,4 +1,8 @@ -0100 +0101 +x Add support for osx 10.9 +x Replace rxtx library +x Add support for Windows 8.1 +x Fix random and map issue with longs 0027 x Add New hardware Serial and FIFO libraries thanks to Brett Hagman