From 0837e89f1509ef7fa6f93b9a25d0df967b4ae6ed Mon Sep 17 00:00:00 2001 From: "David A. Mellis" Date: Mon, 28 Nov 2005 14:04:07 +0000 Subject: [PATCH] Serial flushing now works (added Processing's Serial library as found in the Wiring repository). --- app/Serial.java | 627 ++++++++++++++++++++++++++++++++++++++++++++++ app/Uploader.java | 3 +- 2 files changed, 629 insertions(+), 1 deletion(-) create mode 100755 app/Serial.java diff --git a/app/Serial.java b/app/Serial.java new file mode 100755 index 000000000..5a73f41d6 --- /dev/null +++ b/app/Serial.java @@ -0,0 +1,627 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + PSerial - class for serial port goodness + Part of the Processing project - http://processing.org + + Copyright (c) 2004 Ben Fry & Casey Reas + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA +*/ + +package processing.app; +//import processing.core.*; + +import gnu.io.*; + +import java.io.*; +import java.util.*; + + +public class Serial implements SerialPortEventListener { + + //PApplet parent; + + // properties can be passed in for default values + // otherwise defaults to 9600 N81 + + // 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 + + SerialPort port; + + int rate; + int parity; + int databits; + int stopbits; + boolean monitor = false; + + // read buffer and streams + + InputStream input; + OutputStream output; + + byte buffer[] = new byte[32768]; + int bufferIndex; + int bufferLast; + + + // defaults + + static String dname = Preferences.get("serial.port"); //"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(); + } +*/ + + public void setProperties() { + //System.out.println("setting serial properties"); + dname = Preferences.get("serial.port"); + drate = Preferences.getInteger("serial.debug_rate"); + dparity = Preferences.get("serial.parity").charAt(0); + ddatabits = Preferences.getInteger("serial.databits"); + dstopbits = new Float(Preferences.get("serial.stopbits")).floatValue(); + } + + public Serial(boolean monitor) { + this(dname, drate, dparity, ddatabits, dstopbits); + this.monitor = monitor; + } + + public Serial() { + //setProperties(); + this(dname, drate, dparity, ddatabits, dstopbits); + } + + public Serial(int irate) { + this(dname, irate, dparity, ddatabits, dstopbits); + } + + public Serial(String iname, int irate) { + this(iname, irate, dparity, ddatabits, dstopbits); + } + + public Serial(String iname) { + this(iname, drate, dparity, ddatabits, dstopbits); + } + + public Serial(String iname, int irate, + char iparity, int idatabits, float istopbits) { + //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)) { + //System.out.println("looking for "+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 (Exception e) { + errorMessage("", e); + //exception = e; + //e.printStackTrace(); + port = null; + input = null; + output = null; + } + } + + + public void setup() { + //parent.registerCall(this, DISPOSE); + } + + + //public void size(int w, int h) { } + + //public void pre() { } + + //public void draw() { } + + //public void post() { } + + //public void mouse(java.awt.event.MouseEvent event) { } + + //public void key(java.awt.event.KeyEvent e) { } + + + public void dispose() { + try { + // 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(); + } + port = null; + } + + + 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()); + + /* + System.err.println(input.available() + " " + + ((char) buffer[bufferLast-1])); + */ //} + } + } + //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("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; + } + } + + + /** + * 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) { // will also cover char + 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); + } + } + + + public void write(byte bytes[]) { + 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(); + } + } + + + /** + * 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(); + 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); + } + //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) { + System.err.println("Error inside Serial." + where + "()"); + e.printStackTrace(); + } +} + + + /* + 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. + 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(); + } + + //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; + } + */ + + + diff --git a/app/Uploader.java b/app/Uploader.java index 9a991df49..64344cf09 100755 --- a/app/Uploader.java +++ b/app/Uploader.java @@ -105,6 +105,7 @@ public class Uploader implements MessageConsumer { commandDownloader.add((!Base.isMacOS() ? "" : userdir) + "tools/avr/bin/uisp"); commandDownloader.add("-dprog=" + Preferences.get("upload.programmer")); commandDownloader.add("-dpart=" + Preferences.get("build.mcu")); + //commandDownloader.add("-v=4"); // extra verbosity for help debugging. if (Preferences.get("upload.programmer").equals("dapa")) commandDownloader.add("-dlpt=" + Preferences.get("parallel.port")); else { @@ -126,7 +127,7 @@ public class Uploader implements MessageConsumer { }*/ // Cleanup the serial buffer - serialPort = new Serial(); + Serial serialPort = new Serial(); byte[] readBuffer; while(serialPort.available() > 0) { readBuffer = serialPort.readBytes();