Skip to content

Event Based Reading Usage Example

Will Hedgecock edited this page Jan 5, 2022 · 22 revisions

If you would like to use the jSerialComm library in a completely asynchronous fashion, you can enable event-based callbacks via the addDataListener() method. This method takes your own custom callback object as a parameter which must implement the SerialPortDataListener interface. In any of the event-driven callback modes, you can register your own custom callback to be triggered upon certain serial I/O events. It is important to note that all timeout settings are disregarded when the serial port is operating in an event-driven callback mode listening for the LISTENING_EVENT_DATA_RECEIVED event type, and you should never try to mix both event-driven and synchronous port communications at the same time.

The primary events you can listen for are:

Secondary events you can listen for, but which are not recommended for practical use due to their support being extremely limited across the various operating systems and device drivers, are:

Note that these secondary event types are for notification purposes only and carry no additional payload or information.

Data Available for Reading Example

In this case, your callback will be triggered whenever there is any data available to be read over the serial port. Once your callback is triggered, you can optionally call bytesAvailable() to determine how much data is available to read, and you must actually read the data using any of the read() or readBytes() methods.

The following example shows one way to use this event trigger:

SerialPort comPort = SerialPort.getCommPorts()[0];
comPort.openPort();
comPort.addDataListener(new SerialPortDataListener() {
   @Override
   public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_AVAILABLE; }
   @Override
   public void serialEvent(SerialPortEvent event)
   {
      if (event.getEventType() != SerialPort.LISTENING_EVENT_DATA_AVAILABLE)
         return;
      byte[] newData = new byte[comPort.bytesAvailable()];
      int numRead = comPort.readBytes(newData, newData.length);
      System.out.println("Read " + numRead + " bytes.");
   }
});

Data Writing Successful Example

In this case, your callback will be triggered whenever all data you have written using any of the write() or writeBytes() methods has actually been transmitted.

Note that this mode of operation is only functional on Windows operating systems due to limitations in Linux's handling of serial writes.

The following example shows one way to use this event trigger:

SerialPort comPort = SerialPort.getCommPorts()[0];
comPort.openPort();
comPort.addDataListener(new SerialPortDataListener() {
   @Override
   public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_WRITTEN; }
   @Override
   public void serialEvent(SerialPortEvent event)
   {
      if (event.getEventType() == SerialPort.LISTENING_EVENT_DATA_WRITTEN)
         System.out.println("All bytes were successfully transmitted!");
   }
});

Data Bytes Received Example

In this case, your callback will be triggered whenever some amount of data has actually been read from the serial port. This raw data will be returned to you within your own callback, so there is no further need to read directly from the serial port.

If your data listener is listening for both the LISTENING_EVENT_DATA_RECEIVED and the LISTENING_EVENT_DATA_AVAILABLE event types, the LISTENING_EVENT_DATA_RECEIVED trigger will take precedence, and the serialEvent(SerialPortEvent event) callback will never get called with an event.getEventType() value of LISTENING_EVENT_DATA_AVAILABLE.

The following example shows one way to use this event trigger:

SerialPort comPort = SerialPort.getCommPorts()[0];
comPort.openPort();
comPort.addDataListener(new SerialPortDataListener() {
   @Override
   public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }
   @Override
   public void serialEvent(SerialPortEvent event)
   {
      byte[] newData = event.getReceivedData();
      System.out.println("Received data of size: " + newData.length);
      for (int i = 0; i < newData.length; ++i)
         System.out.print((char)newData[i]);
      System.out.println("\n");
   }
});

Fixed-Length Data Packet Received

In this case, your callback will be triggered whenever a set fixed amount of data has been read from the serial port. This raw data will be returned to you within your own callback, so there is no further need to read directly from the serial port.

Note that in this case, you must implement the SerialPortPacketListener which is itself a sub-class of the SerialPortDataListener.

The following example shows one way to use this event trigger. Notice that in this example, we actually define a qualified listener class instead of passing in an anonymous one as in the previous examples. Either method is fine, and both are shown simply for illustrative purposes:

private final class PacketListener implements SerialPortPacketListener
{
   @Override
   public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }

   @Override
   public int getPacketSize() { return 100; }

   @Override
   public void serialEvent(SerialPortEvent event)
   {
      byte[] newData = event.getReceivedData();
      System.out.println("Received data of size: " + newData.length);
      for (int i = 0; i < newData.length; ++i)
         System.out.print((char)newData[i]);
      System.out.println("\n");
   }
}

static public void main(String[] args)
{
   SerialPort comPort = SerialPort.getCommPorts()[0];
   comPort.openPort();
   PacketListener listener = new PacketListener();
   comPort.addDataListener(listener);
   try { Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); }
   comPort.removeDataListener();
   comPort.closePort();
}

Byte- or Multibyte-Delimited Message Received

In this case, your callback will be triggered whenever a message has been received based on a custom delimiter that you specify. This delimiter can contain one or more consecutive bytes and can indicate either the beginning or the end of a data packet. The raw data will be returned to you within your own callback, so there is no further need to read directly from the serial port.

Note that in this case, you must implement the SerialPortMessageListener which is itself a sub-class of the SerialPortDataListener.

The following example shows one way to use this event trigger. Notice that in this example, we actually define a qualified listener class instead of passing in an anonymous one as in the previous examples. Either method is fine, and both are shown simply for illustrative purposes:

private final class MessageListener implements SerialPortMessageListener
{
   @Override
   public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }

   @Override
   public byte[] getMessageDelimiter() { return new byte[] { (byte)0x0B, (byte)0x65 }; }

   @Override
   public boolean delimiterIndicatesEndOfMessage() { return true; }

   @Override
   public void serialEvent(SerialPortEvent event)
   {
      byte[] delimitedMessage = event.getReceivedData();
      System.out.println("Received the following delimited message: " + delimitedMessage);
   }
}

static public void main(String[] args)
{
   SerialPort comPort = SerialPort.getCommPorts()[0];
   comPort.openPort();
   MessageListener listener = new MessageListener();
   comPort.addDataListener(listener);
   try { Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); }
   comPort.removeDataListener();
   comPort.closePort();
}