2009-06-01 15:14:05 +00:00
/* -*- 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 ;
2014-02-20 14:40:00 +01:00
import static processing.app.I18n._ ;
2009-06-13 20:26:21 +00:00
2013-10-04 11:30:45 +02:00
import java.io.IOException ;
import java.util.Arrays ;
import java.util.List ;
2013-02-27 18:54:10 +01:00
2014-02-20 14:40:00 +01:00
import jssc.SerialPort ;
import jssc.SerialPortEvent ;
import jssc.SerialPortEventListener ;
import jssc.SerialPortException ;
import processing.app.debug.MessageConsumer ;
2009-06-01 15:14:05 +00:00
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 ;
2013-02-27 18:54:10 +01:00
byte buffer [ ] = new byte [ 32768 ] ;
int bufferIndex ;
int bufferLast ;
2013-10-04 11:30:45 +02:00
2009-06-13 20:26:21 +00:00
MessageConsumer consumer ;
2009-06-01 15:14:05 +00:00
public Serial ( boolean monitor ) throws SerialException {
2014-08-22 12:47:43 +02:00
this ( PreferencesData . get ( " serial.port " ) ,
PreferencesData . getInteger ( " serial.debug_rate " ) ,
PreferencesData . get ( " serial.parity " ) . charAt ( 0 ) ,
PreferencesData . getInteger ( " serial.databits " ) ,
new Float ( PreferencesData . get ( " serial.stopbits " ) ) . floatValue ( ) ) ;
2009-06-01 15:14:05 +00:00
this . monitor = monitor ;
}
2013-10-04 11:30:45 +02:00
2009-06-01 15:14:05 +00:00
public Serial ( ) throws SerialException {
2014-08-22 12:47:43 +02:00
this ( PreferencesData . get ( " serial.port " ) ,
PreferencesData . getInteger ( " serial.debug_rate " ) ,
PreferencesData . get ( " serial.parity " ) . charAt ( 0 ) ,
PreferencesData . getInteger ( " serial.databits " ) ,
new Float ( PreferencesData . get ( " serial.stopbits " ) ) . floatValue ( ) ) ;
2009-06-01 15:14:05 +00:00
}
public Serial ( int irate ) throws SerialException {
2014-08-22 12:47:43 +02:00
this ( PreferencesData . get ( " serial.port " ) , irate ,
PreferencesData . get ( " serial.parity " ) . charAt ( 0 ) ,
PreferencesData . getInteger ( " serial.databits " ) ,
new Float ( PreferencesData . get ( " serial.stopbits " ) ) . floatValue ( ) ) ;
2009-06-01 15:14:05 +00:00
}
public Serial ( String iname , int irate ) throws SerialException {
2014-08-22 12:47:43 +02:00
this ( iname , irate , PreferencesData . get ( " serial.parity " ) . charAt ( 0 ) ,
PreferencesData . getInteger ( " serial.databits " ) ,
new Float ( PreferencesData . get ( " serial.stopbits " ) ) . floatValue ( ) ) ;
2009-06-01 15:14:05 +00:00
}
public Serial ( String iname ) throws SerialException {
2014-08-22 12:47:43 +02:00
this ( iname , PreferencesData . getInteger ( " serial.debug_rate " ) ,
PreferencesData . get ( " serial.parity " ) . charAt ( 0 ) ,
PreferencesData . getInteger ( " serial.databits " ) ,
new Float ( PreferencesData . get ( " serial.stopbits " ) ) . floatValue ( ) ) ;
2009-06-01 15:14:05 +00:00
}
2012-02-13 00:37:21 -05:00
public static boolean touchPort ( String iname , int irate ) throws SerialException {
2013-10-04 11:30:45 +02:00
SerialPort serialPort = new SerialPort ( iname ) ;
2012-02-13 00:37:21 -05:00
try {
2013-10-04 11:30:45 +02:00
serialPort . openPort ( ) ;
serialPort . setParams ( irate , 8 , SerialPort . STOPBITS_1 , SerialPort . PARITY_NONE ) ;
serialPort . closePort ( ) ;
return true ;
} catch ( SerialPortException e ) {
throw new SerialException ( I18n . format ( _ ( " Error touching serial port ''{0}''. " ) , iname ) , e ) ;
} finally {
if ( serialPort . isOpened ( ) ) {
try {
serialPort . closePort ( ) ;
} catch ( SerialPortException e ) {
// noop
2013-02-27 18:54:10 +01:00
}
}
2012-02-13 00:37:21 -05:00
}
}
2013-10-04 11:30:45 +02:00
public Serial ( String iname , int irate , char iparity , int idatabits , float istopbits ) throws SerialException {
2009-06-01 15:14:05 +00:00
//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 {
2013-10-04 11:30:45 +02:00
port = new SerialPort ( iname ) ;
port . openPort ( ) ;
port . setParams ( rate , databits , stopbits , parity , true , true ) ;
port . addEventListener ( this ) ;
2013-02-27 18:54:10 +01:00
} catch ( Exception e ) {
2013-10-04 11:30:45 +02:00
throw new SerialException ( I18n . format ( _ ( " Error opening serial port ''{0}''. " ) , iname ) , e ) ;
2009-06-01 15:14:05 +00:00
}
2013-10-04 11:30:45 +02:00
2009-06-01 15:14:05 +00:00
if ( port = = null ) {
2013-10-04 11:30:45 +02:00
throw new SerialNotFoundException ( I18n . format ( _ ( " Serial port ''{0}'' not found. Did you select the right one from the Tools > Serial Port menu? " ) , iname ) ) ;
2009-06-01 15:14:05 +00:00
}
}
public void setup ( ) {
//parent.registerCall(this, DISPOSE);
}
2013-05-29 16:14:17 +02:00
public void dispose ( ) throws IOException {
2013-10-04 11:30:45 +02:00
if ( port ! = null ) {
try {
if ( port . isOpened ( ) ) {
port . closePort ( ) ; // close the port
}
} catch ( SerialPortException e ) {
throw new IOException ( e ) ;
} finally {
port = null ;
}
}
2009-06-01 15:14:05 +00:00
}
2013-10-04 11:30:45 +02:00
2009-06-13 20:26:21 +00:00
public void addListener ( MessageConsumer consumer ) {
this . consumer = consumer ;
}
2009-06-01 15:14:05 +00:00
2013-10-04 11:30:45 +02:00
public synchronized void serialEvent ( SerialPortEvent serialEvent ) {
if ( serialEvent . isRXCHAR ( ) ) {
2013-02-27 18:54:10 +01:00
try {
2014-02-21 11:14:30 +01:00
byte [ ] buf = port . readBytes ( serialEvent . getEventValue ( ) ) ;
2013-10-04 11:30:45 +02:00
if ( buf . length > 0 ) {
if ( bufferLast = = buffer . length ) {
byte temp [ ] = new byte [ bufferLast < < 1 ] ;
System . arraycopy ( buffer , 0 , temp , 0 , bufferLast ) ;
buffer = temp ;
}
if ( monitor ) {
System . out . print ( new String ( buf ) ) ;
}
if ( this . consumer ! = null ) {
this . consumer . message ( new String ( buf ) ) ;
2009-06-01 15:14:05 +00:00
}
}
2013-10-04 11:30:45 +02:00
} catch ( SerialPortException e ) {
2013-02-27 18:54:10 +01:00
errorMessage ( " serialEvent " , e ) ;
}
}
}
/ * *
* Returns the number of bytes that have been read from serial
* and are waiting to be dealt with by the user .
* /
2013-10-04 11:30:45 +02:00
public synchronized int available ( ) {
2013-02-27 18:54:10 +01:00
return ( bufferLast - bufferIndex ) ;
}
/ * *
* Ignore all the bytes read so far and empty the buffer .
* /
2013-10-04 11:30:45 +02:00
public synchronized void clear ( ) {
2013-02-27 18:54:10 +01:00
bufferLast = 0 ;
bufferIndex = 0 ;
}
/ * *
2013-10-04 11:30:45 +02:00
* Returns a number between 0 and 255 for the next byte that ' s
* waiting in the buffer .
2013-02-27 18:54:10 +01:00
* Returns - 1 if there was no byte ( although the user should
* first check available ( ) to see if things are ready to avoid this )
* /
2013-10-04 11:30:45 +02:00
public synchronized int read ( ) {
2013-02-27 18:54:10 +01:00
if ( bufferIndex = = bufferLast ) return - 1 ;
2013-10-04 11:30:45 +02:00
int outgoing = buffer [ bufferIndex + + ] & 0xff ;
if ( bufferIndex = = bufferLast ) { // rewind
bufferIndex = 0 ;
bufferLast = 0 ;
2009-06-01 15:14:05 +00:00
}
2013-10-04 11:30:45 +02:00
return outgoing ;
2009-06-01 15:14:05 +00:00
}
2013-02-27 18:54:10 +01:00
/ * *
* Returns the next byte in the buffer as a char .
* Returns - 1 , or 0xffff , if nothing is there .
* /
2013-10-04 11:30:45 +02:00
public synchronized char readChar ( ) {
if ( bufferIndex = = bufferLast ) return ( char ) ( - 1 ) ;
2013-02-27 18:54:10 +01:00
return ( char ) read ( ) ;
}
/ * *
* Return a byte array of anything that ' s in the serial buffer .
* Not particularly memory / speed efficient , because it creates
2013-10-04 11:30:45 +02:00
* a byte array on each read , but it ' s easier to use than
2013-02-27 18:54:10 +01:00
* readBytes ( byte b [ ] ) ( see below ) .
* /
2013-10-04 11:30:45 +02:00
public synchronized byte [ ] readBytes ( ) {
2013-02-27 18:54:10 +01:00
if ( bufferIndex = = bufferLast ) return null ;
2013-10-04 11:30:45 +02:00
int length = bufferLast - bufferIndex ;
byte outgoing [ ] = new byte [ length ] ;
System . arraycopy ( buffer , bufferIndex , outgoing , 0 , length ) ;
2013-02-27 18:54:10 +01:00
2013-10-04 11:30:45 +02:00
bufferIndex = 0 ; // rewind
bufferLast = 0 ;
return outgoing ;
2013-02-27 18:54:10 +01:00
}
/ * *
2013-10-04 11:30:45 +02:00
* 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 .
* < p / >
2013-02-27 18:54:10 +01:00
* 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 .
* /
2013-10-04 11:30:45 +02:00
public synchronized int readBytes ( byte outgoing [ ] ) {
2013-02-27 18:54:10 +01:00
if ( bufferIndex = = bufferLast ) return 0 ;
2013-10-04 11:30:45 +02:00
int length = bufferLast - bufferIndex ;
if ( length > outgoing . length ) length = outgoing . length ;
System . arraycopy ( buffer , bufferIndex , outgoing , 0 , length ) ;
2013-02-27 18:54:10 +01:00
2013-10-04 11:30:45 +02:00
bufferIndex + = length ;
if ( bufferIndex = = bufferLast ) {
bufferIndex = 0 ; // rewind
bufferLast = 0 ;
}
return length ;
2013-02-27 18:54:10 +01:00
}
/ * *
* Reads from the serial port into a buffer of bytes up to and
2013-10-04 11:30:45 +02:00
* including a particular character . If the character isn ' t in
2013-02-27 18:54:10 +01:00
* the serial buffer , then ' null ' is returned .
* /
2013-10-04 11:30:45 +02:00
public synchronized byte [ ] readBytesUntil ( int interesting ) {
2013-02-27 18:54:10 +01:00
if ( bufferIndex = = bufferLast ) return null ;
2013-10-04 11:30:45 +02:00
byte what = ( byte ) interesting ;
int found = - 1 ;
for ( int k = bufferIndex ; k < bufferLast ; k + + ) {
if ( buffer [ k ] = = what ) {
found = k ;
break ;
2013-02-27 18:54:10 +01:00
}
2013-10-04 11:30:45 +02:00
}
if ( found = = - 1 ) return null ;
2013-02-27 18:54:10 +01:00
2013-10-04 11:30:45 +02:00
int length = found - bufferIndex + 1 ;
byte outgoing [ ] = new byte [ length ] ;
System . arraycopy ( buffer , bufferIndex , outgoing , 0 , length ) ;
2013-02-27 18:54:10 +01:00
2013-10-04 11:30:45 +02:00
bufferIndex = 0 ; // rewind
bufferLast = 0 ;
return outgoing ;
2013-02-27 18:54:10 +01:00
}
/ * *
2013-10-04 11:30:45 +02:00
* Reads from the serial port into a buffer of bytes until a
2013-02-27 18:54:10 +01:00
* particular character . If the character isn ' t in the serial
* buffer , then ' null ' is returned .
2013-10-04 11:30:45 +02:00
* < p / >
* If outgoing [ ] is not big enough , then - 1 is returned ,
* and an error message is printed on the console .
2013-02-27 18:54:10 +01:00
* If nothing is in the buffer , zero is returned .
* If ' interesting ' byte is not in the buffer , then 0 is returned .
* /
2013-10-04 11:30:45 +02:00
public synchronized int readBytesUntil ( int interesting , byte outgoing [ ] ) {
2013-02-27 18:54:10 +01:00
if ( bufferIndex = = bufferLast ) return 0 ;
2013-10-04 11:30:45 +02:00
byte what = ( byte ) interesting ;
2013-02-27 18:54:10 +01:00
2013-10-04 11:30:45 +02:00
int found = - 1 ;
for ( int k = bufferIndex ; k < bufferLast ; k + + ) {
if ( buffer [ k ] = = what ) {
found = k ;
break ;
2013-02-27 18:54:10 +01:00
}
}
2013-10-04 11:30:45 +02:00
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 ;
2013-02-27 18:54:10 +01:00
}
/ * *
* Return whatever has been read from the serial port so far
2013-10-04 11:30:45 +02:00
* as a String . It assumes that the incoming characters are ASCII .
* < p / >
2013-02-27 18:54:10 +01:00
* 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 .
* /
2013-10-04 11:30:45 +02:00
public synchronized String readString ( ) {
2013-02-27 18:54:10 +01:00
if ( bufferIndex = = bufferLast ) return null ;
return new String ( readBytes ( ) ) ;
}
/ * *
2013-10-04 11:30:45 +02:00
* Combination of readBytesUntil and readString . See caveats in
2013-02-27 18:54:10 +01:00
* each function . Returns null if it still hasn ' t found what
* you ' re looking for .
2013-10-04 11:30:45 +02:00
* < p / >
2013-02-27 18:54:10 +01:00
* 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 .
* /
2013-10-04 11:30:45 +02:00
public synchronized String readStringUntil ( int interesting ) {
2013-02-27 18:54:10 +01:00
byte b [ ] = readBytesUntil ( interesting ) ;
if ( b = = null ) return null ;
return new String ( b ) ;
}
2013-02-27 17:54:40 +01:00
2009-06-01 15:14:05 +00:00
/ * *
* This will handle both ints , bytes and chars transparently .
* /
2013-02-27 18:54:10 +01:00
public void write ( int what ) { // will also cover char
2009-06-01 15:14:05 +00:00
try {
2013-10-04 11:30:45 +02:00
port . writeInt ( what & 0xff ) ;
} catch ( SerialPortException e ) {
2009-06-01 15:14:05 +00:00
errorMessage ( " write " , e ) ;
}
}
public void write ( byte bytes [ ] ) {
try {
2013-10-04 11:30:45 +02:00
port . writeBytes ( bytes ) ;
} catch ( SerialPortException e ) {
errorMessage ( " write " , e ) ;
2009-06-01 15:14:05 +00:00
}
}
/ * *
* Write a String to the output . Note that this doesn ' t account
2013-10-04 11:30:45 +02:00
* for Unicode ( two bytes per char ) , nor will it send UTF8
* characters . . It assumes that you mean to send a byte buffer
2009-06-01 15:14:05 +00:00
* ( 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 )
2013-10-04 11:30:45 +02:00
* < p / >
2009-06-01 15:14:05 +00:00
* 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 ( ) ) ;
}
public void setDTR ( boolean state ) {
2013-10-04 11:30:45 +02:00
try {
port . setDTR ( state ) ;
} catch ( SerialPortException e ) {
errorMessage ( " setDTR " , e ) ;
}
2009-06-01 15:14:05 +00:00
}
2010-08-10 01:32:28 +00:00
public void setRTS ( boolean state ) {
2013-10-04 11:30:45 +02:00
try {
port . setRTS ( state ) ;
} catch ( SerialPortException e ) {
errorMessage ( " setRTS " , e ) ;
}
2010-08-10 01:32:28 +00:00
}
2012-02-24 17:30:29 +01:00
static public List < String > list ( ) {
2013-10-04 11:30:45 +02:00
return Arrays . asList ( SerialPortList . getPortNames ( ) ) ;
2009-06-01 15:14:05 +00:00
}
/ * *
* 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 ) {
2011-10-05 03:03:19 +09:00
System . err . println ( I18n . format ( _ ( " Error inside Serial.{0}() " ) , where ) ) ;
2009-06-01 15:14:05 +00:00
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 ;
}
* /