-
Notifications
You must be signed in to change notification settings - Fork 286
Event Based Reading Usage Example
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:
- Data Available for Reading (LISTENING_EVENT_DATA_AVAILABLE)
- Data Writing Successful (LISTENING_EVENT_DATA_WRITTEN)
- Data Bytes Received (LISTENING_EVENT_DATA_RECEIVED)
- Port Disconnected (LISTENING_EVENT_PORT_DISCONNECTED)
- Fixed-Length Data Packet Received
- Byte- or Multibyte-Delimited Message Received
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:
- Break Interrupt Notification (LISTENING_EVENT_BREAK_INTERRUPT)
- Carrier Detect Notification (LISTENING_EVENT_CARRIER_DETECT)
- CTS Line Status Change (LISTENING_EVENT_CTS)
- DSR Line Status Change (LISTENING_EVENT_DSR)
- Ring Indicator Line Status Change (LISTENING_EVENT_RING_INDICATOR)
- Framing Error Detected (LISTENING_EVENT_FRAMING_ERROR)
- Device Driver Buffer Overrun Detected (LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR)
- Application Buffer Overrun Detected (LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR)
- Parity Error Detected (LISTENING_EVENT_PARITY_ERROR)
Note that these secondary event types are for notification purposes only and carry no additional payload or information.
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.");
}
});
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!");
}
});
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");
}
});
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();
}
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();
}
Copyright © 2012-2024 Fazecast, Inc. All rights reserved.