title: Java Serial Port, handle serialEvent effectively
body: <p>Using the RXTX library I've encountered that on a serialEvent (when data arrives) I don't know how to reference the already running main application. </p>
  
  <p>The way of making it work that I've found is to close the serial port when the endOfMessageFlag arrives (so I don't get the "lock file already exists error" when I try to send more data afterwards) and make a new instance of the class that handles the message.</p>
  
  <p>I don't like this "solution" as I'm afraid is not very efficient and if many messages arrive together I would probably even get a stackoverflow exception.</p>
  
  <p>I'm using rxtx-2.2-pre2 on raspbian.</p>
  
  <p>I have three classes, one with the main, one with protocol and one that handles the serial port (initialize, send, (receive)serialEvent ).</p>
  
  <p>Main class snipet:</p>
  
  <pre><code>package app;
  public class MainClass {
  
      private MyProtocol myProt = new MyProtocol();
      public boolean newCDevices = false;
      public int newDevices = 0;
  
      public static void main(String[] args) throws Exception {
          System.setProperty("gnu.io.rxtx.SerialPorts", "/dev/ttyAMA0"); 
          MainClass myMain = new MainClass();
          monitorS.findDevices();
      }
  
      public void messageReceived(byte[] message){
          myProt.processMessage(message);
          myProt.sendAcknowledge();
      }
  
      private void findDevices(){
          myProt.findNewDevices();
      }
  }
  </code></pre>
  
  <p>Protocol class snipet:</p>
  
  <pre><code>package serialcomms;
  public class MyProtocol {
  
      private static SerialComms messageSender = new SerialComms();
  
      // sends acknowledge onReceive.
      public void sendAcknowledge(){        
          byte[] messageBytes = composeMessage(acknowledge);
          if(messageSender.initialize()){
              messageSender.sendData(messageBytes);
              try { Thread.sleep(2000); } catch (InterruptedException ie) {}
              messageSender.close();
          }
      }
  
      //sends broadcast message asking all unidentified devices to make contact.
      public void findNewDevices(){
          byte[] messageBytes = composeMessage(findDevicesMessage);
          if(messageSender.initialize()){
              messageSender.sendData(messageBytes);
              try { Thread.sleep(2000); } catch (InterruptedException ie) {}
              messageSender.close();
          }
      }
  }
  </code></pre>
  
  <p>And the class that handles the serial port:
  (based on this example btw: <a href="http://www.drdobbs.com/jvm/control-an-arduino-from-java/240163864" rel="nofollow">http://www.drdobbs.com/jvm/control-an-arduino-from-java/240163864</a> )</p>
  
  <pre><code>    package serialcomms;
  
      import gnu.io.CommPortIdentifier;
      import gnu.io.SerialPort;
      import gnu.io.SerialPortEvent;
      import gnu.io.SerialPortEventListener;
      import java.io.BufferedReader;
      import java.io.InputStreamReader;
      import java.io.OutputStream;
      import java.time.Clock;
      import java.util.Enumeration;
  
      public class SerialComms implements SerialPortEventListener {
  
          SerialPort serialPort = null;
  
          private static final String PORT_NAMES[] = { 
    //      "/dev/tty.usbmodem", // Mac OS X
  //        "/dev/usbdev", // Linux
          "/dev/ttyAMA0", // Raspberry
  //        "/dev/tty", // Linux
  //       "/dev/serial", // Linux
  //        "COM3", // Windows
      };
  
      private String appName;
      private BufferedReader input;
      private OutputStream output;  
      private int tail = 0;
  
      int lengthArray = 50;
      public byte[] buffer = new byte[lengthArray];
  
      private static final int TIME_OUT = 1000; // Port open timeout
      private static final int DATA_RATE = 9600; // Arduino serial port
  
      private static final int BYTE_START = 100;
      private static final int BYTE_END = 120;
      private final byte startOfMessage = (byte)BYTE_START;
      private final byte endOfMessage = (byte)BYTE_END;
  
      public SerialComms(){
          appName = getClass().getName();
      }
  
      public boolean initialize() {
          try {
              CommPortIdentifier portId = null;
              Enumeration portEnum = CommPortIdentifier.getPortIdentifiers();
  
              // Enumerate system ports and try connecting to Arduino over each
              //
              System.out.println( "Trying:");
              while (portId == null &amp;&amp; portEnum.hasMoreElements()) {
                  // Iterate through your host computer's serial port IDs
                  //
                  CommPortIdentifier currPortId = (CommPortIdentifier) portEnum.nextElement();
                  System.out.println( "   port" + currPortId.getName() );
                  for (String portName : PORT_NAMES) {
                      if ( currPortId.getName().equals(portName) 
                        || currPortId.getName().startsWith(portName)) {
  
                          // Try to connect to the Arduino on this port
                          //
                          // Open serial port
                          serialPort = (SerialPort)currPortId.open(appName, TIME_OUT);
                          portId = currPortId;
                          System.out.println( "Connected on port" + currPortId.getName() );
                          break;
                      }
                  }
              }
  
              if (portId == null || serialPort == null) {
                  System.out.println("Oops... Could not connect to Arduino");
                  return false;
              }
  
              // set port parameters
              serialPort.setSerialPortParams(DATA_RATE,
                              SerialPort.DATABITS_8,
                              SerialPort.STOPBITS_1,
                              SerialPort.PARITY_NONE);
  
              // add event listeners
              serialPort.addEventListener(this);
              serialPort.notifyOnDataAvailable(true);
  
              // Give the Arduino some time
              try { Thread.sleep(2000); } catch (InterruptedException ie) {}
  
              return true;
          }
          catch ( Exception e ) { 
              e.printStackTrace();
          }
          return false;
      }
  
      public void sendData(byte[] data) {
          try {
              System.out.println("Sending data: '" + data +"'");
              // open the streams and send 
              output = serialPort.getOutputStream();
              output.write( data );
          } 
          catch (Exception e) {
              System.err.println(e.toString());
              System.exit(0);
          }
      }
  
      //
      // This should be called when you stop using the port
      //
      public synchronized void close() {
          if ( serialPort != null ) {
              serialPort.removeEventListener();
              serialPort.close();
          }
      }
  
  
      //
      // Handle serial port event
      //
      public synchronized void serialEvent(SerialPortEvent oEvent) {
          try {
              while (oEvent.getEventType() == SerialPortEvent.DATA_AVAILABLE){
  
                      byte singleData = (byte)serialPort.getInputStream().read();
                      if (singleData == startOfMessage){
                          for(int i = 0; i &lt; tail ; i++){
                              buffer[i] = 0x00;
                          }
                          tail = 0;
                          buffer[tail] = singleData;
                          tail++;
  
                      } else if(singleData == endOfMessage &amp;&amp; tail &lt;= buffer.length){ 
                          buffer[tail] = singleData;  
                          tail++;
                          for(int i = 0; i&lt; tail ; i++){
                              System.out.println(buffer[i]);
                          }
                          close();                                //This are the lines that got it to
                          MainClass newMain = new MainClass();    //work. However I think there must
                          newMain.messageReceived(buffer);        //be a better solution.
                      } else if(tail &lt; buffer.length){  
                          buffer[tail] = singleData;  
                          tail++;  
                      }
  
                      break;           
                 default:
                      break;
  
      }
          } 
          catch (Exception e) {
              System.err.println(e.toString());
          }
      }
  }
  </code></pre>
  
  <p>Edited serialEvent method on SerialComms so it would receive all available data instead of having to be interrupted for each byte received.</p>