Implement write-blocking mode across all OSs
This commit is contained in:
parent
a02a311823
commit
1624c1b1e8
|
@ -534,6 +534,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
|
|||
{
|
||||
if (serialPortFD <= 0)
|
||||
return -1;
|
||||
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
|
||||
jbyte *writeBuffer = (*env)->GetByteArrayElements(env, buffer, 0);
|
||||
int numBytesWritten;
|
||||
|
||||
|
@ -541,13 +542,19 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
|
|||
do { numBytesWritten = write(serialPortFD, writeBuffer+offset, bytesToWrite); } while ((numBytesWritten < 0) && (errno == EINTR));
|
||||
if (numBytesWritten == -1)
|
||||
{
|
||||
// Problem writing, close port
|
||||
// Problem writing, allow others to open the port and close it ourselves
|
||||
ioctl(serialPortFD, TIOCNXCL);
|
||||
tcdrain(serialPortFD);
|
||||
while ((close(serialPortFD) == -1) && (errno != EBADF));
|
||||
serialPortFD = -1;
|
||||
(*env)->SetLongField(env, obj, serialPortFdField, -1l);
|
||||
(*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE);
|
||||
}
|
||||
|
||||
// Wait until all bytes were written in write-blocking mode
|
||||
if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0)
|
||||
tcdrain(serialPortFD);
|
||||
|
||||
// Return number of bytes written if successful
|
||||
(*env)->ReleaseByteArrayElements(env, buffer, writeBuffer, JNI_ABORT);
|
||||
return numBytesWritten;
|
||||
|
|
|
@ -41,14 +41,12 @@ extern "C" {
|
|||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING 0L
|
||||
#undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING 1L
|
||||
#undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_SEMI_BLOCKING
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_SEMI_BLOCKING 16L
|
||||
#undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING 256L
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING 16L
|
||||
#undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING 4096L
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING 256L
|
||||
#undef com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER 65536L
|
||||
#define com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER 4096L
|
||||
#undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE
|
||||
#define com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE 1L
|
||||
#undef com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED
|
||||
|
|
|
@ -489,6 +489,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
|
|||
{
|
||||
if (serialPortFD <= 0)
|
||||
return -1;
|
||||
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
|
||||
jbyte *writeBuffer = (*env)->GetByteArrayElements(env, buffer, 0);
|
||||
int numBytesWritten, result = 0;
|
||||
|
||||
|
@ -510,6 +511,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
|
|||
(*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE);
|
||||
}
|
||||
|
||||
// Wait until all bytes were written in write-blocking mode
|
||||
if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0)
|
||||
tcdrain(serialPortFD);
|
||||
|
||||
// Clear the DTR line if using RS-422
|
||||
//#ifdef TIOCSERGETLSR
|
||||
//do
|
||||
|
|
|
@ -527,6 +527,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
|
|||
{
|
||||
if (serialPortFD <= 0)
|
||||
return -1;
|
||||
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
|
||||
jbyte *writeBuffer = (*env)->GetByteArrayElements(env, buffer, 0);
|
||||
int numBytesWritten;
|
||||
|
||||
|
@ -543,6 +544,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
|
|||
(*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE);
|
||||
}
|
||||
|
||||
// Wait until all bytes were written in write-blocking mode
|
||||
if ((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING) > 0)
|
||||
tcdrain(serialPortFD);
|
||||
|
||||
// Return number of bytes written if successful
|
||||
(*env)->ReleaseByteArrayElements(env, buffer, writeBuffer, JNI_ABORT);
|
||||
return numBytesWritten;
|
||||
|
|
|
@ -478,7 +478,6 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
|
|||
switch (timeoutMode)
|
||||
{
|
||||
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING: // Read Semi-blocking
|
||||
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_SEMI_BLOCKING): // Read/Write Semi-blocking
|
||||
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Semi-blocking/Write Blocking
|
||||
timeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
|
||||
|
@ -486,7 +485,6 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
|
|||
timeouts.WriteTotalTimeoutConstant = writeTimeout;
|
||||
break;
|
||||
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING: // Read Blocking
|
||||
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_SEMI_BLOCKING): // Read Blocking/Write Semi-blocking
|
||||
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read/Write Blocking
|
||||
timeouts.ReadIntervalTimeout = 0;
|
||||
timeouts.ReadTotalTimeoutMultiplier = 0;
|
||||
|
@ -497,10 +495,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
|
|||
timeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
|
||||
timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF;
|
||||
timeouts.WriteTotalTimeoutConstant = 0;
|
||||
timeouts.WriteTotalTimeoutConstant = writeTimeout;
|
||||
break;
|
||||
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING: // Read Non-blocking
|
||||
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_SEMI_BLOCKING): // Read Non-blocking/Write Semi-blocking
|
||||
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Non-blocking/Write Blocking
|
||||
default:
|
||||
timeouts.ReadIntervalTimeout = MAXDWORD;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* SerialPort.java
|
||||
*
|
||||
* Created on: Feb 25, 2012
|
||||
* Last Updated on: Oct 07, 2018
|
||||
* Last Updated on: Oct 08, 2018
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2018 Fazecast, Inc.
|
||||
|
@ -332,10 +332,9 @@ public final class SerialPort
|
|||
// Timeout Modes
|
||||
static final public int TIMEOUT_NONBLOCKING = 0x00000000;
|
||||
static final public int TIMEOUT_READ_SEMI_BLOCKING = 0x00000001;
|
||||
static final public int TIMEOUT_WRITE_SEMI_BLOCKING = 0x00000010;
|
||||
static final public int TIMEOUT_READ_BLOCKING = 0x00000100;
|
||||
static final public int TIMEOUT_WRITE_BLOCKING = 0x00001000;
|
||||
static final public int TIMEOUT_SCANNER = 0x00010000;
|
||||
static final public int TIMEOUT_READ_BLOCKING = 0x00000010;
|
||||
static final public int TIMEOUT_WRITE_BLOCKING = 0x00000100;
|
||||
static final public int TIMEOUT_SCANNER = 0x00001000;
|
||||
|
||||
// Serial Port Listening Events
|
||||
static final public int LISTENING_EVENT_DATA_AVAILABLE = 0x00000001;
|
||||
|
@ -528,9 +527,9 @@ public final class SerialPort
|
|||
* <p>
|
||||
* The length of the byte buffer must be greater than or equal to the value passed in for <i>bytesToRead</i>
|
||||
* <p>
|
||||
* If no timeouts were specified or the read timeout was set to 0, this call will block until <i>bytesToRead</i> bytes of data have been successfully read from the serial port.
|
||||
* Otherwise, this method will return after <i>bytesToRead</i> bytes of data have been read or the number of milliseconds specified by the read timeout have elapsed,
|
||||
* whichever comes first, regardless of the availability of more data.
|
||||
* In blocking-read mode, if no timeouts were specified or the read timeout was set to 0, this call will block until <i>bytesToRead</i> bytes of data have been successfully
|
||||
* read from the serial port. Otherwise, this method will return after <i>bytesToRead</i> bytes of data have been read or the number of milliseconds specified by the read timeout
|
||||
* have elapsed, whichever comes first, regardless of the availability of more data.
|
||||
*
|
||||
* @param buffer The buffer into which the raw data is read.
|
||||
* @param bytesToRead The number of bytes to read from the serial port.
|
||||
|
@ -543,9 +542,9 @@ public final class SerialPort
|
|||
* <p>
|
||||
* The length of the byte buffer minus the offset must be greater than or equal to the value passed in for <i>bytesToRead</i>
|
||||
* <p>
|
||||
* If no timeouts were specified or the read timeout was set to 0, this call will block until <i>bytesToRead</i> bytes of data have been successfully read from the serial port.
|
||||
* Otherwise, this method will return after <i>bytesToRead</i> bytes of data have been read or the number of milliseconds specified by the read timeout have elapsed,
|
||||
* whichever comes first, regardless of the availability of more data.
|
||||
* In blocking-read mode, if no timeouts were specified or the read timeout was set to 0, this call will block until <i>bytesToRead</i> bytes of data have been successfully
|
||||
* read from the serial port. Otherwise, this method will return after <i>bytesToRead</i> bytes of data have been read or the number of milliseconds specified by the read timeout
|
||||
* have elapsed, whichever comes first, regardless of the availability of more data.
|
||||
*
|
||||
* @param buffer The buffer into which the raw data is read.
|
||||
* @param bytesToRead The number of bytes to read from the serial port.
|
||||
|
@ -559,9 +558,9 @@ public final class SerialPort
|
|||
* <p>
|
||||
* The length of the byte buffer must be greater than or equal to the value passed in for <i>bytesToWrite</i>
|
||||
* <p>
|
||||
* If no timeouts were specified or the write timeout was set to 0, this call will block until <i>bytesToWrite</i> bytes of data have been successfully written the serial port.
|
||||
* Otherwise, this method will return after <i>bytesToWrite</i> bytes of data have been written or the number of milliseconds specified by the write timeout have elapsed,
|
||||
* whichever comes first, regardless of the availability of more data.
|
||||
* In blocking-write mode, this call will block until <i>bytesToWrite</i> bytes of data have been successfully written to the serial port. Otherwise, this method will return
|
||||
* after <i>bytesToWrite</i> bytes of data have been written to the device driver's internal data buffer, which, in most cases, should be almost instantaneous unless the data
|
||||
* buffer is full.
|
||||
*
|
||||
* @param buffer The buffer containing the raw data to write to the serial port.
|
||||
* @param bytesToWrite The number of bytes to write to the serial port.
|
||||
|
@ -574,9 +573,9 @@ public final class SerialPort
|
|||
* <p>
|
||||
* The length of the byte buffer minus the offset must be greater than or equal to the value passed in for <i>bytesToWrite</i>
|
||||
* <p>
|
||||
* If no timeouts were specified or the write timeout was set to 0, this call will block until <i>bytesToWrite</i> bytes of data have been successfully written the serial port.
|
||||
* Otherwise, this method will return after <i>bytesToWrite</i> bytes of data have been written or the number of milliseconds specified by the write timeout have elapsed,
|
||||
* whichever comes first, regardless of the availability of more data.
|
||||
* In blocking-write mode, this call will block until <i>bytesToWrite</i> bytes of data have been successfully written to the serial port. Otherwise, this method will return
|
||||
* after <i>bytesToWrite</i> bytes of data have been written to the device driver's internal data buffer, which, in most cases, should be almost instantaneous unless the data
|
||||
* buffer is full.
|
||||
*
|
||||
* @param buffer The buffer containing the raw data to write to the serial port.
|
||||
* @param bytesToWrite The number of bytes to write to the serial port.
|
||||
|
@ -794,24 +793,29 @@ public final class SerialPort
|
|||
/**
|
||||
* Sets the serial port read and write timeout parameters.
|
||||
* <p>
|
||||
* <i>Note that write timeouts are only available on Windows-based systems. There is no functionality to set a write timeout on other operating systems.</i>
|
||||
* <i>Note that time-based write timeouts are only available on Windows systems. There is no functionality to set a write timeout on other operating systems.</i>
|
||||
* <p>
|
||||
* The built-in timeout mode constants should be used ({@link #TIMEOUT_NONBLOCKING}, {@link #TIMEOUT_READ_SEMI_BLOCKING}, {@link #TIMEOUT_READ_BLOCKING},
|
||||
* {@link #TIMEOUT_SCANNER}) to specify how timeouts are to be handled.
|
||||
* {@link #TIMEOUT_WRITE_BLOCKING}, {@link #TIMEOUT_SCANNER}) to specify how timeouts are to be handled.
|
||||
* <p>
|
||||
* Valid modes are:
|
||||
* <p>
|
||||
* Read Non-blocking: {@link #TIMEOUT_NONBLOCKING}<br>
|
||||
* Non-blocking: {@link #TIMEOUT_NONBLOCKING}<br>
|
||||
* Write Blocking: {@link #TIMEOUT_WRITE_BLOCKING}<br>
|
||||
* Read Semi-blocking: {@link #TIMEOUT_READ_SEMI_BLOCKING}<br>
|
||||
* Read Full-blocking: {@link #TIMEOUT_READ_BLOCKING}<br>
|
||||
* Scanner: {@link #TIMEOUT_SCANNER}<br>
|
||||
* <p>
|
||||
* The {@link #TIMEOUT_NONBLOCKING} mode specifies that the corresponding {@link #readBytes(byte[],long)} call will return immediately with any available data.
|
||||
* The {@link #TIMEOUT_NONBLOCKING} mode specifies that corresponding {@link #readBytes(byte[],long)} and {@link #writeBytes(byte[],long)} calls will return
|
||||
* immediately with any available data.
|
||||
* <p>
|
||||
* The {@link #TIMEOUT_READ_SEMI_BLOCKING} mode specifies that the corresponding call will block until either <i>newReadTimeout</i> milliseconds of inactivity
|
||||
* The {@link #TIMEOUT_WRITE_BLOCKING} mode specifies that a corresponding write call will block until all data bytes have been successfully written to the
|
||||
* output serial device.
|
||||
* <p>
|
||||
* The {@link #TIMEOUT_READ_SEMI_BLOCKING} mode specifies that a corresponding read call will block until either <i>newReadTimeout</i> milliseconds of inactivity
|
||||
* have elapsed or at least 1 byte of data can be read.
|
||||
* <p>
|
||||
* The {@link #TIMEOUT_READ_BLOCKING} mode specifies that the corresponding call will block until either <i>newReadTimeout</i> milliseconds have elapsed since
|
||||
* The {@link #TIMEOUT_READ_BLOCKING} mode specifies that a corresponding read call will block until either <i>newReadTimeout</i> milliseconds have elapsed since
|
||||
* the start of the call or the total number of requested bytes can be returned.
|
||||
* <p>
|
||||
* The {@link #TIMEOUT_SCANNER} mode is intended for use with the Java {@link java.util.Scanner} class for reading from the serial port. In this mode,
|
||||
|
@ -820,13 +824,16 @@ public final class SerialPort
|
|||
* A value of 0 for either <i>newReadTimeout</i> or <i>newWriteTimeout</i> indicates that a {@link #readBytes(byte[],long)} or
|
||||
* {@link #writeBytes(byte[],long)} call should block forever until it can return successfully (based upon the current timeout mode specified).
|
||||
* <p>
|
||||
* In order to specify that both a blocking read and write mode should be used, {@link #TIMEOUT_WRITE_BLOCKING} can be OR'd together with any of the read modes to pass
|
||||
* to the first parameter.
|
||||
* <p>
|
||||
* It is important to note that non-Windows operating systems only allow decisecond (1/10th of a second) granularity for serial port timeouts. As such, your
|
||||
* millisecond timeout value will be rounded to the nearest decisecond under Linux or Mac OS. To ensure consistent performance across multiple platforms, it is
|
||||
* advisable that you set your timeout values to be multiples of 100, although this is not strictly enforced.
|
||||
*
|
||||
* @param newTimeoutMode The new timeout mode as specified above.
|
||||
* @param newReadTimeout The number of milliseconds of inactivity to tolerate before returning from a {@link #readBytes(byte[],long)} call.
|
||||
* @param newWriteTimeout The number of milliseconds of inactivity to tolerate before returning from a {@link #writeBytes(byte[],long)} call.
|
||||
* @param newWriteTimeout The number of milliseconds of inactivity to tolerate before returning from a {@link #writeBytes(byte[],long)} call (effective only on Windows).
|
||||
*/
|
||||
public final void setComPortTimeouts(int newTimeoutMode, int newReadTimeout, int newWriteTimeout)
|
||||
{
|
||||
|
@ -1049,7 +1056,7 @@ public final class SerialPort
|
|||
/**
|
||||
* Gets the number of milliseconds of inactivity to tolerate before returning from a {@link #readBytes(byte[],long)} call.
|
||||
* <p>
|
||||
* A value of 0 indicates that a {@link #readBytes(byte[],long)} call will block forever until it has successfully read
|
||||
* A value of 0 in blocking-read mode indicates that a {@link #readBytes(byte[],long)} call will block forever until it has successfully read
|
||||
* the indicated number of bytes from the serial port.
|
||||
* <p>
|
||||
* Any value other than 0 indicates the number of milliseconds of inactivity that will be tolerated before the {@link #readBytes(byte[],long)}
|
||||
|
@ -1062,7 +1069,7 @@ public final class SerialPort
|
|||
/**
|
||||
* Gets the number of milliseconds of inactivity to tolerate before returning from a {@link #writeBytes(byte[],long)} call.
|
||||
* <p>
|
||||
* A value of 0 indicates that a {@link #writeBytes(byte[],long)} call will block forever until it has successfully written
|
||||
* A value of 0 in blocking-write mode indicates that a {@link #writeBytes(byte[],long)} call will block forever until it has successfully written
|
||||
* the indicated number of bytes to the serial port.
|
||||
* <p>
|
||||
* Any value other than 0 indicates the number of milliseconds of inactivity that will be tolerated before the {@link #writeBytes(byte[],long)}
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue