1
votes

I have a problem with writing function of jSSC. My Arduino Uno board seems not getting data from my Java program.

I have a stepper motor controlled by Arduino Uno board. I made a simple program that has 2 buttons. One is for CW rotation and the other is CCW rotation. CW button sends 'H' char and CCW button sends 'L' char. Now I have:

  1. I checked from Arduino IDE serial console my Arduino program works correct. When I send 'H' the motor turns CW and with 'L' the motor turns CCW.
  2. I made a program in Processing with two buttons sending 'H' and 'L'. It worked.
  3. I made a Java program with JSSC with two buttons sending 'H' and 'L'. IT FAILED. When I push one of the buttons in my program I see "L" light on the board blinks 3-4 times but nothing happens.
  4. I tried getting data from my board with JSSC and it worked. It seems the problem is in writing function.
  5. I checked with another Arduino Uno board but the result is the same.

My Java program uses serialPort.writeByte((byte)'H'); and serialPort.writeByte((byte)'L');

Any ideas?

3
Do you mind running your test with Processing ? It uses JSSC behind the scenes for it's Serial class. If you look into 8Examples > libraries > Serial* you should find samples there and the docs [here](processing.org/reference/libraries/serial). If this works, it might be something with your java implementaton, in which case, either extend Processing's PApplet and use it's Serial class in your java project or look at Processing's Serial class (the source code is included)George Profenza
I used jSSC-2.6.0 in this program but when I use jSSC-0.7.1 I'm able to send data now. 0.7.1 is the one that is explained in the library's web site.Huseyin Ulku
If you use 2.6.0 in your project, does that solve the issue ?George Profenza
In 0.7.1 there is a dll file coming in "bin" directory. But there isn't any bin folder and dll file in 2.6.0 even though it's written "bin+src+javadoc" in download page. I think without using a dll, the library doesn't work (at least for Windows).Huseyin Ulku
how about C:\Program Files\processing-2.1.2\modes\java\libraries\serial\library\windows32 or C:\Program Files\processing-2.1.2\modes\java\libraries\serial\library\windows64 ?George Profenza

3 Answers

1
votes

Did you try setting the parameters for flow control. Since while writing to the interface, it requires a permission.

serialPort.setParams(SerialPort.BAUDRATE_9600,
                                 SerialPort.DATABITS_8,
                                 SerialPort.STOPBITS_1,
                                 SerialPort.PARITY_NONE,false,true);//Set params. Also you can set params by this string: serialPort.setParams(9600, 8, 1, 0,RTSEnable,DTSEnable);
serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
0
votes

Can it be a reset-related problem? Maybe your java function uses the DTR pin, which is connected to the RESET pin; so when you try to send data instead you are just resetting the board.

If you want to test you can make another led blink at startup or send something through the serial interface at setup. If you get that feedback try looking at the way to disable DTR ;)

0
votes

You can refactor Processing's Serial class (which works pretty well) to avoid PApplet if you don't plan to use it in your java project:

/*
  PSerial - class for serial port goodness
  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
  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
*/
import java.lang.reflect.Method;
import java.util.Map;

import jssc.SerialPort;
import jssc.SerialPortEvent;
import jssc.SerialPortEventListener;
import jssc.SerialPortException;
import jssc.SerialPortList;

public class Serial implements SerialPortEventListener {
          Object parent;
          public SerialPort port;
          Method serialAvailableMethod;
          Method serialEventMethod;

          byte[] buffer = new byte[32768];
          int inBuffer = 0;
          int readOffset = 0;

          int bufferUntilSize = 1;
          byte bufferUntilByte = 0;

          volatile boolean invokeSerialAvailable = false;

          // Things we are currently not exposing:
          // * hardware flow control
          // * state of the RING, RLSD line
          // * sending breaks


          public Serial(Object parent) {
            this(parent, "COM1", 9600, 'N', 8, 1);
          }


          public Serial(Object parent, int baudRate) {
            this(parent, "COM1", baudRate, 'N', 8, 1);
          }


          public Serial(Object parent, String portName) {
            this(parent, portName, 9600, 'N', 8, 1);
          }


          public Serial(Object parent, String portName, int baudRate) {
            this(parent, portName, baudRate, 'N', 8, 1);
          }


          public Serial(Object parent, String portName, int baudRate, char parity, int dataBits, float stopBits) {
            this.parent = parent;

            //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;
            }

            // 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;
            }

            port = new SerialPort(portName);
            try {
              // the native open() call is not using O_NONBLOCK, so this might block for certain operations (see write())
              port.openPort();
              port.setParams(baudRate, dataBits, stopBitsIdx, parity);
              // we could register more events here
              port.addEventListener(this, SerialPort.MASK_RXCHAR);
            } catch (SerialPortException e) {
              // this used to be a RuntimeException before, so stick with it
              throw new RuntimeException("Error opening serial port " + e.getPortName() + ": " + e.getExceptionType());
            }

            serialEventMethod = findCallback("serialEvent");
            serialAvailableMethod = findCallback("serialAvailable");
          }

          private Method findCallback(final String name) {
            try {
              return parent.getClass().getMethod(name, this.getClass());
            } catch (Exception e) {
            }
            // Permit callback(Object) as alternative to callback(Serial).
            try {
              return parent.getClass().getMethod(name, Object.class);
            } catch (Exception e) {
            }
            return null;
          }


          public void dispose() {
            stop();
          }


          public void pre() {
            if (serialAvailableMethod != null && invokeSerialAvailable) {
              invokeSerialAvailable = false;
              try {
                serialAvailableMethod.invoke(parent, this);
              } catch (Exception e) {
                System.err.println("Error, disabling serialAvailable() for "+port.getPortName());
                System.err.println(e.getLocalizedMessage());
                serialAvailableMethod = null;
              }
            }
          }


          public int available() {
            return (inBuffer-readOffset);
          }


          public void buffer(int size) {
            bufferUntilSize = size;
          }


          public void bufferUntil(int inByte) {
            bufferUntilSize = 0;
            bufferUntilByte = (byte)inByte;
          }


          public void clear() {
            synchronized (buffer) {
              inBuffer = 0;
              readOffset = 0;
            }
          }


          public boolean getCTS() {
            try {
              return port.isCTS();
            } catch (SerialPortException e) {
              throw new RuntimeException("Error reading the CTS line: " + e.getExceptionType());
            }
          }


          public boolean getDSR() {
            try {
              return port.isDSR();
            } catch (SerialPortException e) {
              throw new RuntimeException("Error reading the DSR line: " + e.getExceptionType());
            }
          }


          public static Map<String, String> getProperties(String portName) {
            return SerialPortList.getPortProperties(portName);
          }


          public int last() {
            if (inBuffer == readOffset) {
              return -1;
            }

            synchronized (buffer) {
              int ret = buffer[inBuffer-1] & 0xFF;
              inBuffer = 0;
              readOffset = 0;
              return ret;
            }
          }


          public char lastChar() {
            return (char)last();
          }


          public static String[] list() {
            // 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;
            }

            synchronized (buffer) {
              int ret = buffer[readOffset++] & 0xFF;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return ret;
            }
          }


          public byte[] readBytes() {
            if (inBuffer == readOffset) {
              return null;
            }

            synchronized (buffer) {
              byte[] ret = new byte[inBuffer-readOffset];
              System.arraycopy(buffer, readOffset, ret, 0, ret.length);
              inBuffer = 0;
              readOffset = 0;
              return ret;
            }
          }


          public int readBytes(byte[] dest) {
            if (inBuffer == readOffset) {
              return 0;
            }

            synchronized (buffer) {
              int toCopy = inBuffer-readOffset;
              if (dest.length < toCopy) {
                toCopy = dest.length;
              }
              System.arraycopy(buffer, readOffset, dest, 0, toCopy);
              readOffset += toCopy;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return toCopy;
            }
          }


          public byte[] readBytesUntil(int inByte) {
            if (inBuffer == readOffset) {
              return null;
            }

            synchronized (buffer) {
              // look for needle in buffer
              int found = -1;
              for (int i=readOffset; i < inBuffer; i++) {
                if (buffer[i] == (byte)inByte) {
                  found = i;
                  break;
                }
              }
              if (found == -1) {
                return null;
              }

              int toCopy = found-readOffset+1;
              byte[] dest = new byte[toCopy];
              System.arraycopy(buffer, readOffset, dest, 0, toCopy);
              readOffset += toCopy;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return dest;
            }
          }


          public int readBytesUntil(int inByte, byte[] dest) {
            if (inBuffer == readOffset) {
              return 0;
            }

            synchronized (buffer) {
              // look for needle in buffer
              int found = -1;
              for (int i=readOffset; i < inBuffer; i++) {
                if (buffer[i] == (byte)inByte) {
                  found = i;
                  break;
                }
              }
              if (found == -1) {
                return 0;
              }

              // check if bytes to copy fit in dest
              int toCopy = found-readOffset+1;
              if (dest.length < toCopy) {
                System.err.println( "The buffer passed to readBytesUntil() is to small " +
                          "to contain " + toCopy + " bytes up to and including " +
                          "char " + (byte)inByte);
                return -1;
              }
              System.arraycopy(buffer, readOffset, dest, 0, toCopy);
              readOffset += toCopy;
              if (inBuffer == readOffset) {
                inBuffer = 0;
                readOffset = 0;
              }
              return toCopy;
            }
          }


          public char readChar() {
            return (char) read();
          }


          public String readString() {
            if (inBuffer == readOffset) {
              return null;
            }
            return new String(readBytes());
          }


          public String readStringUntil(int inByte) {
            byte temp[] = readBytesUntil(inByte);
            if (temp == null) {
              return null;
            } else {
              return new String(temp);
            }
          }


          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 (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 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 {
              port.setDTR(state);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error setting the DTR line: " + e.getExceptionType());
            }
          }


          public void setRTS(boolean state) {
            try {
              port.setRTS(state);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error setting the RTS line: " + e.getExceptionType());
            }
          }


          public void stop() {
            try {
              port.closePort();
            } catch (SerialPortException e) {
              // ignored
            }
            inBuffer = 0;
            readOffset = 0;
          }


          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());
            }
          }


          public void write(int src) {
            try {
              port.writeInt(src);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
            }
          }


          public void write(String src) {
            try {
              port.writeString(src);
            } catch (SerialPortException e) {
              throw new RuntimeException("Error writing to serial port " + e.getPortName() + ": " + e.getExceptionType());
            }
          }
        }

Here's an example class using the above:

public class SerialTest {

        public static void main(String[] args) {
                try{
                        Serial serial = new Serial(new SerialTest(),"/dev/tty.usbmodemfd121",115200);
                        serial.write("H");
                        serial.write("L");//can also try serial.write((int)'L');
                }catch(Exception e){
                        System.err.println("serial not connected!");
                }
        }
        public void serialAvailable(Serial s){
                System.out.println(s.toString());
        }

        public void serialEvent(Serial s){
                System.out.print("from serial:");
                System.out.println(s.read());
        }

}

Be sure to change the port and baud rate to what your Arduino Uno is using.

In Processing's serial library folder you'll also find the JNI native libraries. For example on Windows:

C:\Program Files\processing-2.1.2\modes\java\libraries\serial\library

Where the dll would reside in the windows32 and windows64 folders, depending on what you plan to use. The Serial class above is pretty much the same as C:\Program Files\processing-2.1.2\modes\java\libraries\serial\src\processing\serial/Serial.java replacing PApplet with Object.

Also, here is the Processing Serial library reference