Initial implementation of SerialPortMessageListener
This commit is contained in:
parent
051ba9f8fb
commit
6ec19f472f
|
@ -2,7 +2,7 @@
|
|||
* SerialPort.java
|
||||
*
|
||||
* Created on: Feb 25, 2012
|
||||
* Last Updated on: Mar 07, 2019
|
||||
* Last Updated on: Mar 15, 2019
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2019 Fazecast, Inc.
|
||||
|
@ -26,6 +26,7 @@
|
|||
package com.fazecast.jSerialComm;
|
||||
|
||||
import java.lang.ProcessBuilder;
|
||||
import java.nio.charset.Charset;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.File;
|
||||
|
@ -37,12 +38,13 @@ import java.io.InputStream;
|
|||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
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.
|
||||
*
|
||||
* @author Will Hedgecock <will.hedgecock@fazecast.com>
|
||||
* @version 2.4.2
|
||||
* @version 2.5.0
|
||||
* @see java.io.InputStream
|
||||
* @see java.io.OutputStream
|
||||
*/
|
||||
|
@ -679,25 +681,29 @@ public final class SerialPort
|
|||
* <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.
|
||||
* <p>
|
||||
* The parameter passed into this method must be an implementation of either the {@link SerialPortDataListener} or the {@link SerialPortPacketListener}.
|
||||
* 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 parameter passed into this method must be an implementation of either {@link SerialPortDataListener}, {@link SerialPortPacketListener}, or {@link SerialPortMessageListener}.
|
||||
* 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.
|
||||
* <p>
|
||||
* 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.
|
||||
* @see SerialPortDataListener
|
||||
* @see SerialPortPacketListener
|
||||
* @see SerialPortMessageListener
|
||||
*/
|
||||
public final boolean addDataListener(SerialPortDataListener listener)
|
||||
{
|
||||
if (userDataListener != null)
|
||||
return false;
|
||||
userDataListener = listener;
|
||||
serialEventListener = new SerialPortEventListener((userDataListener instanceof SerialPortPacketListener) ?
|
||||
((SerialPortPacketListener)userDataListener).getPacketSize() : 0);
|
||||
serialEventListener = ((userDataListener instanceof SerialPortPacketListener) ? new SerialPortEventListener(((SerialPortPacketListener)userDataListener).getPacketSize()) :
|
||||
((userDataListener instanceof SerialPortMessageListener) ?
|
||||
new SerialPortEventListener(((SerialPortMessageListener)userDataListener).getMessageDelimiter(), ((SerialPortMessageListener)userDataListener).getCharacterEncoding()) :
|
||||
new SerialPortEventListener()));
|
||||
|
||||
eventFlags = 0;
|
||||
if ((listener.getListeningEvents() & LISTENING_EVENT_DATA_AVAILABLE) > 0)
|
||||
|
@ -1139,10 +1145,15 @@ public final class SerialPort
|
|||
{
|
||||
private volatile boolean isListening = false;
|
||||
private final byte[] dataPacket;
|
||||
private final String delimiter, delimiterRegex;
|
||||
private final Charset messageCharset;
|
||||
private volatile int dataPacketIndex = 0;
|
||||
private String messages = "";
|
||||
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()
|
||||
{
|
||||
|
@ -1192,7 +1203,17 @@ public final class SerialPort
|
|||
byte[] newBytes = new byte[numBytesAvailable];
|
||||
newBytesIndex = 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()));
|
||||
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
|
||||
*
|
||||
* Created on: Feb 27, 2015
|
||||
* Last Updated on: Jan 10, 2018
|
||||
* Last Updated on: Mar 14, 2019
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2018 Fazecast, Inc.
|
||||
* Copyright (C) 2012-2019 Fazecast, Inc.
|
||||
*
|
||||
* This file is part of jSerialComm.
|
||||
*
|
||||
|
@ -26,13 +26,14 @@
|
|||
package com.fazecast.jSerialComm;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* This class provides a test case for the jSerialComm library.
|
||||
*
|
||||
* @author Will Hedgecock <will.hedgecock@gmail.com>
|
||||
* @version 2.4.1
|
||||
* @version 2.5.0
|
||||
* @see java.io.InputStream
|
||||
* @see java.io.OutputStream
|
||||
*/
|
||||
|
@ -55,6 +56,22 @@ public class SerialPortTest
|
|||
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)
|
||||
{
|
||||
SerialPort[] ports = SerialPort.getCommPorts();
|
||||
|
@ -169,8 +186,13 @@ public class SerialPortTest
|
|||
PacketListener listener = new PacketListener();
|
||||
ubxPort.addDataListener(listener);
|
||||
try { Thread.sleep(5000); } catch (Exception e) {}
|
||||
System.out.println("\n\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
|
||||
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(); }
|
||||
System.out.println("Reopening " + ubxPort.getDescriptivePortName() + ": " + ubxPort.openPort() + "\n");
|
||||
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 1000, 0);
|
||||
|
|
Loading…
Reference in New Issue