Initial implementation of SerialPortMessageListener
This commit is contained in:
parent
051ba9f8fb
commit
6ec19f472f
|
@ -2,7 +2,7 @@
|
||||||
* SerialPort.java
|
* SerialPort.java
|
||||||
*
|
*
|
||||||
* Created on: Feb 25, 2012
|
* Created on: Feb 25, 2012
|
||||||
* Last Updated on: Mar 07, 2019
|
* Last Updated on: Mar 15, 2019
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2019 Fazecast, Inc.
|
* Copyright (C) 2012-2019 Fazecast, Inc.
|
||||||
|
@ -26,6 +26,7 @@
|
||||||
package com.fazecast.jSerialComm;
|
package com.fazecast.jSerialComm;
|
||||||
|
|
||||||
import java.lang.ProcessBuilder;
|
import java.lang.ProcessBuilder;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
import java.io.DataOutputStream;
|
import java.io.DataOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -37,12 +38,13 @@ import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides native access to serial ports and devices without requiring external libraries or tools.
|
* This class provides native access to serial ports and devices without requiring external libraries or tools.
|
||||||
*
|
*
|
||||||
* @author Will Hedgecock <will.hedgecock@fazecast.com>
|
* @author Will Hedgecock <will.hedgecock@fazecast.com>
|
||||||
* @version 2.4.2
|
* @version 2.5.0
|
||||||
* @see java.io.InputStream
|
* @see java.io.InputStream
|
||||||
* @see java.io.OutputStream
|
* @see java.io.OutputStream
|
||||||
*/
|
*/
|
||||||
|
@ -679,25 +681,29 @@ public final class SerialPort
|
||||||
* <p>
|
* <p>
|
||||||
* Calling this function enables event-based serial port callbacks to be used instead of, or in addition to, direct serial port read/write calls or the {@link java.io.InputStream}/{@link java.io.OutputStream} interface.
|
* Calling this function enables event-based serial port callbacks to be used instead of, or in addition to, direct serial port read/write calls or the {@link java.io.InputStream}/{@link java.io.OutputStream} interface.
|
||||||
* <p>
|
* <p>
|
||||||
* The parameter passed into this method must be an implementation of either the {@link SerialPortDataListener} or the {@link SerialPortPacketListener}.
|
* The parameter passed into this method must be an implementation of either {@link SerialPortDataListener}, {@link SerialPortPacketListener}, or {@link SerialPortMessageListener}.
|
||||||
* The {@link SerialPortPacketListener} interface <b>must</b> be used if you plan to use event-based reading of <i>full</i> data packets over the serial port.
|
* The {@link SerialPortMessageListener} interface <b>should</b> be used if you plan to use event-based reading of <i>delimited</i> data messages over the serial port.
|
||||||
|
* The {@link SerialPortPacketListener} interface <b>should</b> be used if you plan to use event-based reading of <i>full</i> data packets over the serial port.
|
||||||
* Otherwise, the simpler {@link SerialPortDataListener} may be used.
|
* Otherwise, the simpler {@link SerialPortDataListener} may be used.
|
||||||
* <p>
|
* <p>
|
||||||
* Only one listener can be registered at a time; however, that listener can be used to detect multiple types of serial port events.
|
* Only one listener can be registered at a time; however, that listener can be used to detect multiple types of serial port events.
|
||||||
* Refer to {@link SerialPortDataListener} and {@link SerialPortPacketListener} for more information.
|
* Refer to {@link SerialPortDataListener}, {@link SerialPortPacketListener}, and {@link SerialPortMessageListener} for more information.
|
||||||
*
|
*
|
||||||
* @param listener A {@link SerialPortDataListener} or {@link SerialPortPacketListener}implementation to be used for event-based serial port communications.
|
* @param listener A {@link SerialPortDataListener}, {@link SerialPortPacketListener}, or {@link SerialPortMessageListener} implementation to be used for event-based serial port communications.
|
||||||
* @return Whether the listener was successfully registered with the serial port.
|
* @return Whether the listener was successfully registered with the serial port.
|
||||||
* @see SerialPortDataListener
|
* @see SerialPortDataListener
|
||||||
* @see SerialPortPacketListener
|
* @see SerialPortPacketListener
|
||||||
|
* @see SerialPortMessageListener
|
||||||
*/
|
*/
|
||||||
public final boolean addDataListener(SerialPortDataListener listener)
|
public final boolean addDataListener(SerialPortDataListener listener)
|
||||||
{
|
{
|
||||||
if (userDataListener != null)
|
if (userDataListener != null)
|
||||||
return false;
|
return false;
|
||||||
userDataListener = listener;
|
userDataListener = listener;
|
||||||
serialEventListener = new SerialPortEventListener((userDataListener instanceof SerialPortPacketListener) ?
|
serialEventListener = ((userDataListener instanceof SerialPortPacketListener) ? new SerialPortEventListener(((SerialPortPacketListener)userDataListener).getPacketSize()) :
|
||||||
((SerialPortPacketListener)userDataListener).getPacketSize() : 0);
|
((userDataListener instanceof SerialPortMessageListener) ?
|
||||||
|
new SerialPortEventListener(((SerialPortMessageListener)userDataListener).getMessageDelimiter(), ((SerialPortMessageListener)userDataListener).getCharacterEncoding()) :
|
||||||
|
new SerialPortEventListener()));
|
||||||
|
|
||||||
eventFlags = 0;
|
eventFlags = 0;
|
||||||
if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_AVAILABLE) > 0)
|
if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_AVAILABLE) > 0)
|
||||||
|
@ -1139,10 +1145,15 @@ public final class SerialPort
|
||||||
{
|
{
|
||||||
private volatile boolean isListening = false;
|
private volatile boolean isListening = false;
|
||||||
private final byte[] dataPacket;
|
private final byte[] dataPacket;
|
||||||
|
private final String delimiter, delimiterRegex;
|
||||||
|
private final Charset messageCharset;
|
||||||
private volatile int dataPacketIndex = 0;
|
private volatile int dataPacketIndex = 0;
|
||||||
|
private String messages = "";
|
||||||
private Thread serialEventThread = null;
|
private Thread serialEventThread = null;
|
||||||
|
|
||||||
public SerialPortEventListener(int packetSizeToReceive) { dataPacket = new byte[packetSizeToReceive]; }
|
public SerialPortEventListener() { dataPacket = new byte[0]; delimiter = delimiterRegex = ""; messageCharset = Charset.forName("UTF-8"); }
|
||||||
|
public SerialPortEventListener(int packetSizeToReceive) { dataPacket = new byte[packetSizeToReceive]; delimiter = delimiterRegex = ""; messageCharset = Charset.forName("UTF-8"); }
|
||||||
|
public SerialPortEventListener(String messageDelimiter, Charset charset) { dataPacket = new byte[0]; delimiter = messageDelimiter; delimiterRegex = Pattern.quote(messageDelimiter); messageCharset = charset; }
|
||||||
|
|
||||||
public final void startListening()
|
public final void startListening()
|
||||||
{
|
{
|
||||||
|
@ -1192,7 +1203,17 @@ public final class SerialPort
|
||||||
byte[] newBytes = new byte[numBytesAvailable];
|
byte[] newBytes = new byte[numBytesAvailable];
|
||||||
newBytesIndex = 0;
|
newBytesIndex = 0;
|
||||||
bytesRemaining = readBytes(portHandle, newBytes, newBytes.length, 0);
|
bytesRemaining = readBytes(portHandle, newBytes, newBytes.length, 0);
|
||||||
if(dataPacket.length == 0)
|
if (!delimiter.isEmpty())
|
||||||
|
{
|
||||||
|
messages += new String(newBytes, messageCharset);
|
||||||
|
while (messages.contains(delimiter))
|
||||||
|
{
|
||||||
|
String[] message = messages.split(delimiterRegex, 2);
|
||||||
|
messages = (message.length > 1) ? message[1] : "";
|
||||||
|
userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, message[0].getBytes(messageCharset)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dataPacket.length == 0)
|
||||||
userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, newBytes.clone()));
|
userDataListener.serialEvent(new SerialPortEvent(SerialPort.this, LISTENING_EVENT_DATA_RECEIVED, newBytes.clone()));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,55 @@
|
||||||
|
/*
|
||||||
|
* SerialPortMessageListener.java
|
||||||
|
*
|
||||||
|
* Created on: Mar 14, 2019
|
||||||
|
* Last Updated on: Mar 15, 2019
|
||||||
|
* Author: Will Hedgecock
|
||||||
|
*
|
||||||
|
* Copyright (C) 2012-2019 Fazecast, Inc.
|
||||||
|
*
|
||||||
|
* This file is part of jSerialComm.
|
||||||
|
*
|
||||||
|
* jSerialComm is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of either the Apache Software License, version 2, or
|
||||||
|
* the GNU Lesser General Public License as published by the Free Software
|
||||||
|
* Foundation, version 3 or above.
|
||||||
|
*
|
||||||
|
* jSerialComm 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.
|
||||||
|
*
|
||||||
|
* You should have received a copy of both the GNU Lesser General Public
|
||||||
|
* License and the Apache Software License along with jSerialComm. If not,
|
||||||
|
* see <http://www.gnu.org/licenses/> and <http://www.apache.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.fazecast.jSerialComm;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This interface must be implemented to enable delimited string-based message reads using event-based serial port I/O.
|
||||||
|
* <p>
|
||||||
|
* <i>Note</i>: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context.
|
||||||
|
*
|
||||||
|
* @author Will Hedgecock <will.hedgecock@fazecast.com>
|
||||||
|
* @version 2.5.0
|
||||||
|
* @see com.fazecast.jSerialComm.SerialPortDataListener
|
||||||
|
* @see java.util.EventListener
|
||||||
|
*/
|
||||||
|
public interface SerialPortMessageListener extends SerialPortDataListener
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Must be overridden to return the expected message delimiter that <b>must</b> be encountered before the {@link #serialEvent(SerialPortEvent)} callback is triggered.
|
||||||
|
*
|
||||||
|
* @return A string indicating the expected message delimiter that must be encountered before the {@link #serialEvent(SerialPortEvent)} callback is triggered.
|
||||||
|
*/
|
||||||
|
public abstract String getMessageDelimiter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Must be overridden to return the expected character encoding used by your message transfer protocol.
|
||||||
|
*
|
||||||
|
* @return A {@link java.nio.charset.Charset} indicating the expected character encoding used by your serial messages.
|
||||||
|
*/
|
||||||
|
public abstract Charset getCharacterEncoding();
|
||||||
|
}
|
|
@ -2,10 +2,10 @@
|
||||||
* SerialPortTest.java
|
* SerialPortTest.java
|
||||||
*
|
*
|
||||||
* Created on: Feb 27, 2015
|
* Created on: Feb 27, 2015
|
||||||
* Last Updated on: Jan 10, 2018
|
* Last Updated on: Mar 14, 2019
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2018 Fazecast, Inc.
|
* Copyright (C) 2012-2019 Fazecast, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of jSerialComm.
|
* This file is part of jSerialComm.
|
||||||
*
|
*
|
||||||
|
@ -26,13 +26,14 @@
|
||||||
package com.fazecast.jSerialComm;
|
package com.fazecast.jSerialComm;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.Scanner;
|
import java.util.Scanner;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class provides a test case for the jSerialComm library.
|
* This class provides a test case for the jSerialComm library.
|
||||||
*
|
*
|
||||||
* @author Will Hedgecock <will.hedgecock@gmail.com>
|
* @author Will Hedgecock <will.hedgecock@gmail.com>
|
||||||
* @version 2.4.1
|
* @version 2.5.0
|
||||||
* @see java.io.InputStream
|
* @see java.io.InputStream
|
||||||
* @see java.io.OutputStream
|
* @see java.io.OutputStream
|
||||||
*/
|
*/
|
||||||
|
@ -55,6 +56,22 @@ public class SerialPortTest
|
||||||
public int getPacketSize() { return 100; }
|
public int getPacketSize() { return 100; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final class MessageListener implements SerialPortMessageListener
|
||||||
|
{
|
||||||
|
@Override
|
||||||
|
public int getListeningEvents() { return SerialPort.LISTENING_EVENT_DATA_RECEIVED; }
|
||||||
|
@Override
|
||||||
|
public void serialEvent(SerialPortEvent event)
|
||||||
|
{
|
||||||
|
String newMessage = new String(event.getReceivedData());
|
||||||
|
System.out.println("Received the following message: " + newMessage);
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public String getMessageDelimiter() { return "\n"; }
|
||||||
|
@Override
|
||||||
|
public Charset getCharacterEncoding() { return Charset.forName("UTF-8"); }
|
||||||
|
}
|
||||||
|
|
||||||
static public void main(String[] args)
|
static public void main(String[] args)
|
||||||
{
|
{
|
||||||
SerialPort[] ports = SerialPort.getCommPorts();
|
SerialPort[] ports = SerialPort.getCommPorts();
|
||||||
|
@ -169,8 +186,13 @@ public class SerialPortTest
|
||||||
PacketListener listener = new PacketListener();
|
PacketListener listener = new PacketListener();
|
||||||
ubxPort.addDataListener(listener);
|
ubxPort.addDataListener(listener);
|
||||||
try { Thread.sleep(5000); } catch (Exception e) {}
|
try { Thread.sleep(5000); } catch (Exception e) {}
|
||||||
System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
|
|
||||||
ubxPort.removeDataListener();
|
ubxPort.removeDataListener();
|
||||||
|
System.out.println("\nNow listening for newline-delimited string messages\n");
|
||||||
|
MessageListener messageListener = new MessageListener();
|
||||||
|
ubxPort.addDataListener(messageListener);
|
||||||
|
try { Thread.sleep(5000); } catch (Exception e) {}
|
||||||
|
ubxPort.removeDataListener();
|
||||||
|
System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
|
||||||
try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); }
|
try { Thread.sleep(1000); } catch (InterruptedException e1) { e1.printStackTrace(); }
|
||||||
System.out.println("Reopening " + ubxPort.getDescriptivePortName() + ": " + ubxPort.openPort() + "\n");
|
System.out.println("Reopening " + ubxPort.getDescriptivePortName() + ": " + ubxPort.openPort() + "\n");
|
||||||
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);
|
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);
|
||||||
|
|
Loading…
Reference in New Issue