Add functionality to flush Rx/Tx serial buffers

This commit is contained in:
Will Hedgecock 2021-12-07 13:47:24 -06:00
parent b44e972ffe
commit 5dc13a33d5
32 changed files with 73 additions and 3 deletions

View File

@ -2,7 +2,7 @@
* SerialPort_Posix.c * SerialPort_Posix.c
* *
* Created on: Feb 25, 2012 * Created on: Feb 25, 2012
* Last Updated on: Dec 01, 2021 * Last Updated on: Dec 07, 2021
* Author: Will Hedgecock * Author: Will Hedgecock
* *
* Copyright (C) 2012-2021 Fazecast, Inc. * Copyright (C) 2012-2021 Fazecast, Inc.
@ -33,6 +33,7 @@
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <sys/time.h> #include <sys/time.h>
#include <termios.h> #include <termios.h>
#include <time.h>
#include <unistd.h> #include <unistd.h>
#if defined(__linux__) #if defined(__linux__)
#include <linux/serial.h> #include <linux/serial.h>
@ -52,6 +53,7 @@ jfieldID eventListenerRunningField;
jfieldID disableConfigField; jfieldID disableConfigField;
jfieldID isDtrEnabledField; jfieldID isDtrEnabledField;
jfieldID isRtsEnabledField; jfieldID isRtsEnabledField;
jfieldID autoFlushIOBuffersField;
jfieldID baudRateField; jfieldID baudRateField;
jfieldID dataBitsField; jfieldID dataBitsField;
jfieldID stopBitsField; jfieldID stopBitsField;
@ -135,6 +137,7 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z"); disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z");
isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z"); isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z");
isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z"); isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z");
autoFlushIOBuffersField = (*env)->GetFieldID(env, serialCommClass, "autoFlushIOBuffers", "Z");
baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I"); baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I");
dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I"); dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I");
stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I"); stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I");
@ -185,6 +188,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL); const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
unsigned char disableExclusiveLock = (*env)->GetBooleanField(env, obj, disableExclusiveLockField); unsigned char disableExclusiveLock = (*env)->GetBooleanField(env, obj, disableExclusiveLockField);
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField); unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
// Ensure that the serial port still exists and is not already open // Ensure that the serial port still exists and is not already open
serialPort *port = fetchPort(&serialPorts, portName); serialPort *port = fetchPort(&serialPorts, portName);
@ -220,6 +224,13 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
errno = 0; errno = 0;
port->handle = -1; port->handle = -1;
} }
else if (autoFlushIOBuffers)
{
// Sleep to workaround kernel bug about flushing immediately after opening
const struct timespec sleep_time = { 0, 10000000 };
nanosleep(&sleep_time, NULL);
Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(env, obj, (jlong)(intptr_t)port);
}
} }
else else
port->errorNumber = errno; port->errorNumber = errno;
@ -427,6 +438,18 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
return JNI_TRUE; return JNI_TRUE;
} }
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (tcflush(port->handle, TCIOFLUSH))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = errno;
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortPointer) JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortPointer)
{ {
// Initialize the local variables // Initialize the local variables

View File

@ -129,6 +129,14 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeouts JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeouts
(JNIEnv *, jobject, jlong, jint, jint, jint, jint); (JNIEnv *, jobject, jlong, jint, jint, jint, jint);
/*
* Class: com_fazecast_jSerialComm_SerialPort
* Method: flushRxTxBuffers
* Signature: (J)Z
*/
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers
(JNIEnv *, jobject, jlong);
/* /*
* Class: com_fazecast_jSerialComm_SerialPort * Class: com_fazecast_jSerialComm_SerialPort
* Method: waitForEvent * Method: waitForEvent

View File

@ -2,7 +2,7 @@
* SerialPort_Windows.c * SerialPort_Windows.c
* *
* Created on: Feb 25, 2012 * Created on: Feb 25, 2012
* Last Updated on: Dec 06, 2021 * Last Updated on: Dec 07, 2021
* Author: Will Hedgecock * Author: Will Hedgecock
* *
* Copyright (C) 2012-2021 Fazecast, Inc. * Copyright (C) 2012-2021 Fazecast, Inc.
@ -49,6 +49,7 @@ jfieldID eventListenerRunningField;
jfieldID disableConfigField; jfieldID disableConfigField;
jfieldID isDtrEnabledField; jfieldID isDtrEnabledField;
jfieldID isRtsEnabledField; jfieldID isRtsEnabledField;
jfieldID autoFlushIOBuffersField;
jfieldID baudRateField; jfieldID baudRateField;
jfieldID dataBitsField; jfieldID dataBitsField;
jfieldID stopBitsField; jfieldID stopBitsField;
@ -366,6 +367,7 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z"); disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z");
isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z"); isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z");
isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z"); isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z");
autoFlushIOBuffersField = (*env)->GetFieldID(env, serialCommClass, "autoFlushIOBuffers", "Z");
baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I"); baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I");
dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I"); dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I");
stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I"); stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I");
@ -396,6 +398,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField); jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL); const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL);
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField); unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
// Ensure that the serial port still exists and is not already open // Ensure that the serial port still exists and is not already open
serialPort *port = fetchPort(&serialPorts, portName); serialPort *port = fetchPort(&serialPorts, portName);
@ -423,6 +426,8 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
CloseHandle(port->handle); CloseHandle(port->handle);
port->handle = INVALID_HANDLE_VALUE; port->handle = INVALID_HANDLE_VALUE;
} }
else if (autoFlushIOBuffers)
Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(env, obj, (jlong)(intptr_t)port);
} }
else else
{ {
@ -573,6 +578,18 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
return JNI_TRUE; return JNI_TRUE;
} }
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR) == 0)
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
}
return JNI_TRUE;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortPointer) JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortPointer)
{ {
// Create an asynchronous event structure // Create an asynchronous event structure

View File

@ -421,7 +421,7 @@ public final class SerialPort
private volatile String comPort, friendlyName, portDescription; private volatile String comPort, friendlyName, portDescription;
private volatile boolean eventListenerRunning = false, disableConfig = false, disableExclusiveLock = false; private volatile boolean eventListenerRunning = false, disableConfig = false, disableExclusiveLock = false;
private volatile boolean rs485Mode = false, rs485ActiveHigh = true, rs485RxDuringTx = false, rs485EnableTermination = false; private volatile boolean rs485Mode = false, rs485ActiveHigh = true, rs485RxDuringTx = false, rs485EnableTermination = false;
private volatile boolean isRtsEnabled = true, isDtrEnabled = true; private volatile boolean isRtsEnabled = true, isDtrEnabled = true, autoFlushIOBuffers = false;
private SerialPortInputStream inputStream = null; private SerialPortInputStream inputStream = null;
private SerialPortOutputStream outputStream = null; private SerialPortOutputStream outputStream = null;
@ -592,6 +592,7 @@ public final class SerialPort
private final native long closePortNative(long portHandle); // Closes serial port private final native long closePortNative(long portHandle); // Closes serial port
private final native boolean configPort(long portHandle); // Changes/sets serial port parameters as defined by this class private final native boolean configPort(long portHandle); // Changes/sets serial port parameters as defined by this class
private final native boolean configTimeouts(long portHandle, int timeoutMode, int readTimeout, int writeTimeout, int eventsToMonitor); // Changes/sets serial port timeouts as defined by this class private final native boolean configTimeouts(long portHandle, int timeoutMode, int readTimeout, int writeTimeout, int eventsToMonitor); // Changes/sets serial port timeouts as defined by this class
private final native boolean flushRxTxBuffers(long portHandle); // Flushes underlying RX/TX device buffers
private final native int waitForEvent(long portHandle); // Waits for serial event to occur as specified in eventFlags private final native int waitForEvent(long portHandle); // Waits for serial event to occur as specified in eventFlags
private final native int bytesAvailable(long portHandle); // Returns number of bytes available for reading private final native int bytesAvailable(long portHandle); // Returns number of bytes available for reading
private final native int bytesAwaitingWrite(long portHandle); // Returns number of bytes still waiting to be written private final native int bytesAwaitingWrite(long portHandle); // Returns number of bytes still waiting to be written
@ -966,6 +967,27 @@ public final class SerialPort
return outputStream; return outputStream;
} }
/**
* Flushes the serial port's Rx/Tx device buffers.
* <p>
* If this function is called before the port is open, then the buffers will be flushed immediately after opening the port.
* If called on an already-open port, flushing of the buffers will happen immediately.
* <p>
* Note that flushing serial buffers will always work on real serial ports; however, many USB-to-serial converters
* do not accurately implement this functionality, so the flushing may not always work as expected, especially immediately
* after opening a new port.
*
* @return Whether the IO buffers were (or will be) successfully flushed.
*/
public final synchronized boolean flushIOBuffers()
{
autoFlushIOBuffers = true;
if (portHandle > 0)
return flushRxTxBuffers(portHandle);
return true;
}
/** /**
* Sets all serial port parameters at one time. * Sets all serial port parameters at one time.
* <p> * <p>