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
*
* Created on: Feb 25, 2012
* Last Updated on: Dec 01, 2021
* Last Updated on: Dec 07, 2021
* Author: Will Hedgecock
*
* Copyright (C) 2012-2021 Fazecast, Inc.
@ -33,6 +33,7 @@
#include <sys/ioctl.h>
#include <sys/time.h>
#include <termios.h>
#include <time.h>
#include <unistd.h>
#if defined(__linux__)
#include <linux/serial.h>
@ -52,6 +53,7 @@ jfieldID eventListenerRunningField;
jfieldID disableConfigField;
jfieldID isDtrEnabledField;
jfieldID isRtsEnabledField;
jfieldID autoFlushIOBuffersField;
jfieldID baudRateField;
jfieldID dataBitsField;
jfieldID stopBitsField;
@ -135,6 +137,7 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z");
isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z");
isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z");
autoFlushIOBuffersField = (*env)->GetFieldID(env, serialCommClass, "autoFlushIOBuffers", "Z");
baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I");
dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "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);
unsigned char disableExclusiveLock = (*env)->GetBooleanField(env, obj, disableExclusiveLockField);
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
serialPort *port = fetchPort(&serialPorts, portName);
@ -220,6 +224,13 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
errno = 0;
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
port->errorNumber = errno;
@ -427,6 +438,18 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
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)
{
// 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
(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
* Method: waitForEvent

View File

@ -2,7 +2,7 @@
* SerialPort_Windows.c
*
* Created on: Feb 25, 2012
* Last Updated on: Dec 06, 2021
* Last Updated on: Dec 07, 2021
* Author: Will Hedgecock
*
* Copyright (C) 2012-2021 Fazecast, Inc.
@ -49,6 +49,7 @@ jfieldID eventListenerRunningField;
jfieldID disableConfigField;
jfieldID isDtrEnabledField;
jfieldID isRtsEnabledField;
jfieldID autoFlushIOBuffersField;
jfieldID baudRateField;
jfieldID dataBitsField;
jfieldID stopBitsField;
@ -366,6 +367,7 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z");
isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z");
isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z");
autoFlushIOBuffersField = (*env)->GetFieldID(env, serialCommClass, "autoFlushIOBuffers", "Z");
baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I");
dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "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);
const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL);
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
serialPort *port = fetchPort(&serialPorts, portName);
@ -423,6 +426,8 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
CloseHandle(port->handle);
port->handle = INVALID_HANDLE_VALUE;
}
else if (autoFlushIOBuffers)
Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(env, obj, (jlong)(intptr_t)port);
}
else
{
@ -573,6 +578,18 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
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)
{
// Create an asynchronous event structure

View File

@ -421,7 +421,7 @@ public final class SerialPort
private volatile String comPort, friendlyName, portDescription;
private volatile boolean eventListenerRunning = false, disableConfig = false, disableExclusiveLock = 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 SerialPortOutputStream outputStream = null;
@ -592,6 +592,7 @@ public final class SerialPort
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 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 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
@ -966,6 +967,27 @@ public final class SerialPort
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.
* <p>