Fix event-based reading in Windows

This commit is contained in:
Will Hedgecock 2021-11-29 21:45:26 -06:00
parent f8ae239887
commit ef97fc62bb
6 changed files with 185 additions and 110 deletions

View File

@ -41,6 +41,8 @@ all :
$(PRINT) C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat x64 $(PRINT) C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat x64
$(PRINT) nmake win64 $(PRINT) nmake win64
$(PRINT). $(PRINT).
clean :
$(RMDIR) $(BUILD_DIR)\..
# Builds 32-bit Windows libraries # Builds 32-bit Windows libraries
win32 : $(BUILD_DIR)\x86 $(BUILD_DIR)\x86\$(LIBRARY_NAME) win32 : $(BUILD_DIR)\x86 $(BUILD_DIR)\x86\$(LIBRARY_NAME)

View File

@ -249,7 +249,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
RegCloseKey(keyHandle5); RegCloseKey(keyHandle5);
// Fetch the length of the "Bus-Reported Device Description" // Fetch the length of the "Bus-Reported Device Description"
if (comPortString && !SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, NULL, 0, &valueLength, 0) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER)) if (comPortString && !SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, NULL, 0, &valueLength, 0) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
{ {
// Allocate memory // Allocate memory
++valueLength; ++valueLength;
@ -419,13 +419,14 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
// Close the port if there was a problem setting the parameters // Close the port if there was a problem setting the parameters
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
CancelIoEx(port->handle, NULL); CancelIoEx(port->handle, NULL);
SetCommMask(port->handle, 0);
CloseHandle(port->handle); CloseHandle(port->handle);
port->handle = INVALID_HANDLE_VALUE; port->handle = INVALID_HANDLE_VALUE;
} }
} }
else else
{ {
port->errorLineNumber = __LINE__ - 14; port->errorLineNumber = __LINE__ - 15;
port->errorNumber = GetLastError(); port->errorNumber = GetLastError();
} }
@ -470,8 +471,12 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
// Retrieve existing port configuration // Retrieve existing port configuration
DCB dcbSerialParams{}; DCB dcbSerialParams{};
dcbSerialParams.DCBlength = sizeof(DCB); dcbSerialParams.DCBlength = sizeof(DCB);
if ((!SetupComm(port->handle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(port->handle, &dcbSerialParams))) if (!SetupComm(port->handle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(port->handle, &dcbSerialParams))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE; return JNI_FALSE;
}
// Set updated port parameters // Set updated port parameters
dcbSerialParams.BaudRate = baudRate; dcbSerialParams.BaudRate = baudRate;
@ -497,24 +502,29 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
dcbSerialParams.XoffChar = xoffStopChar; dcbSerialParams.XoffChar = xoffStopChar;
// Apply changes // Apply changes
return (SetCommState(port->handle, &dcbSerialParams) && Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortPointer, timeoutMode, readTimeout, writeTimeout, eventsToMonitor)); if (!SetCommState(port->handle, &dcbSerialParams))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
}
return Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortPointer, timeoutMode, readTimeout, writeTimeout, eventsToMonitor);
} }
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(JNIEnv *env, jobject obj, jlong serialPortPointer, jint timeoutMode, jint readTimeout, jint writeTimeout, jint eventsToMonitor) JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(JNIEnv *env, jobject obj, jlong serialPortPointer, jint timeoutMode, jint readTimeout, jint writeTimeout, jint eventsToMonitor)
{ {
// Get event flags from Java class // Get event flags from the Java class
int eventFlags = EV_ERR; int eventFlags = EV_ERR;
serialPort *port = (serialPort*)(intptr_t)serialPortPointer; serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) > 0) || if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) || (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED))
((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0))
eventFlags |= EV_RXCHAR; eventFlags |= EV_RXCHAR;
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN) > 0) if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN)
eventFlags |= EV_TXEMPTY; eventFlags |= EV_TXEMPTY;
// Set updated port timeouts // Set updated port timeouts
COMMTIMEOUTS timeouts{}; COMMTIMEOUTS timeouts{};
timeouts.WriteTotalTimeoutMultiplier = 0; timeouts.WriteTotalTimeoutMultiplier = 0;
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0) if (eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED)
{ {
// Force specific read timeouts if we are monitoring data received // Force specific read timeouts if we are monitoring data received
timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.ReadIntervalTimeout = MAXDWORD;
@ -522,102 +532,120 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
timeouts.ReadTotalTimeoutConstant = 1000; timeouts.ReadTotalTimeoutConstant = 1000;
timeouts.WriteTotalTimeoutConstant = 0; timeouts.WriteTotalTimeoutConstant = 0;
} }
else else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER)
{ {
switch (timeoutMode) timeouts.ReadIntervalTimeout = MAXDWORD;
{ timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING: // Read Semi-blocking timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF;
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Semi-blocking/Write Blocking timeouts.WriteTotalTimeoutConstant = writeTimeout;
timeouts.ReadIntervalTimeout = MAXDWORD; }
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING)
timeouts.ReadTotalTimeoutConstant = readTimeout ? readTimeout : 0x0FFFFFFF; {
timeouts.WriteTotalTimeoutConstant = writeTimeout; timeouts.ReadIntervalTimeout = MAXDWORD;
break; timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING: // Read Blocking timeouts.ReadTotalTimeoutConstant = readTimeout ? readTimeout : 0x0FFFFFFF;
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read/Write Blocking timeouts.WriteTotalTimeoutConstant = writeTimeout;
timeouts.ReadIntervalTimeout = 0; }
timeouts.ReadTotalTimeoutMultiplier = 0; else if (timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING)
timeouts.ReadTotalTimeoutConstant = readTimeout; {
timeouts.WriteTotalTimeoutConstant = writeTimeout; timeouts.ReadIntervalTimeout = 0;
break; timeouts.ReadTotalTimeoutMultiplier = 0;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER: // Scanner Mode timeouts.ReadTotalTimeoutConstant = readTimeout;
timeouts.ReadIntervalTimeout = MAXDWORD; timeouts.WriteTotalTimeoutConstant = writeTimeout;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD; }
timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF; else // Non-blocking
timeouts.WriteTotalTimeoutConstant = writeTimeout; {
break; timeouts.ReadIntervalTimeout = MAXDWORD;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING: // Read Non-blocking timeouts.ReadTotalTimeoutMultiplier = 0;
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Non-blocking/Write Blocking timeouts.ReadTotalTimeoutConstant = 0;
default: timeouts.WriteTotalTimeoutConstant = writeTimeout;
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
}
} }
// Apply changes // Apply changes
return (SetCommTimeouts(port->handle, &timeouts) && SetCommMask(port->handle, eventFlags)); if (!SetCommTimeouts(port->handle, &timeouts) || !SetCommMask(port->handle, eventFlags))
{
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
OVERLAPPED overlappedStruct{}; OVERLAPPED overlappedStruct{};
serialPort *port = (serialPort*)(intptr_t)serialPortPointer; serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedStruct.hEvent == NULL) jint event = com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_TIMED_OUT;
if (!overlappedStruct.hEvent)
{ {
port->errorNumber = GetLastError(); port->errorNumber = GetLastError();
port->errorLineNumber = __LINE__ - 4; port->errorLineNumber = __LINE__ - 5;
CloseHandle(overlappedStruct.hEvent); return event;
return 0;
} }
// Wait for a serial port event // Wait for a serial port event
BOOL listenerRunning = TRUE; DWORD eventMask = 0, errorMask = 0, waitValue, numBytesTransferred;
DWORD eventMask = 0, numBytesRead = 0, errorsMask, readResult = WAIT_FAILED; if (!WaitCommEvent(port->handle, &eventMask, &overlappedStruct))
if (WaitCommEvent(port->handle, &eventMask, &overlappedStruct) == FALSE)
{ {
if (GetLastError() != ERROR_IO_PENDING) // Problem occurred if ((GetLastError() == ERROR_IO_PENDING) || (GetLastError() == ERROR_INVALID_PARAMETER))
{ {
port->errorLineNumber = __LINE__ - 4; do { waitValue = WaitForSingleObject(overlappedStruct.hEvent, 500); }
port->errorNumber = GetLastError(); while ((waitValue == WAIT_TIMEOUT) && port->eventListenerRunning);
listenerRunning = FALSE; if ((waitValue != WAIT_OBJECT_0) || !GetOverlappedResult(port->handle, &overlappedStruct, &numBytesTransferred, FALSE))
}
else
{
do
{ {
listenerRunning = env->GetBooleanField(obj, eventListenerRunningField); port->errorNumber = GetLastError();
if (listenerRunning) port->errorLineNumber = __LINE__ - 3;
readResult = WaitForSingleObject(overlappedStruct.hEvent, 500); CloseHandle(overlappedStruct.hEvent);
else return event;
{ }
// Purge any outstanding port operations }
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); else // Problem occurred
CancelIoEx(port->handle, NULL); {
FlushFileBuffers(port->handle); port->errorNumber = GetLastError();
readResult = WaitForSingleObject(overlappedStruct.hEvent, INFINITE); port->errorLineNumber = __LINE__ - 16;
} CloseHandle(overlappedStruct.hEvent);
} while ((readResult == WAIT_TIMEOUT) && listenerRunning); return event;
if ((readResult != WAIT_OBJECT_0) || (GetOverlappedResult(port->handle, &overlappedStruct, &numBytesRead, FALSE) == FALSE))
numBytesRead = 0;
} }
} }
// Ensure that new data actually was received // Retrieve and clear any serial port errors
if (listenerRunning) COMSTAT commInfo;
if (ClearCommError(port->handle, &errorMask, &commInfo))
{ {
COMSTAT commInfo; if (errorMask & CE_BREAK)
if (ClearCommError(port->handle, &errorsMask, &commInfo)) event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT;
numBytesRead = commInfo.cbInQue; if (errorMask & CE_FRAME)
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FRAMING_ERROR;
if (errorMask & CE_OVERRUN)
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR;
if (errorMask & CE_RXOVER)
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR;
if (errorMask & CE_RXPARITY)
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_PARITY_ERROR;
} }
// Return type of event if successful // Parse any received serial port events
DWORD modemStatus;
if (eventMask & EV_BREAK)
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_BREAK_INTERRUPT;
if (eventMask & EV_TXEMPTY)
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN;
if ((eventMask & EV_RXCHAR) && (commInfo.cbInQue > 0))
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE;
if ((eventMask & EV_CTS) && GetCommModemStatus(port->handle, &modemStatus) && (modemStatus & MS_CTS_ON))
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CTS;
if ((eventMask & EV_DSR) && GetCommModemStatus(port->handle, &modemStatus) && (modemStatus & MS_DSR_ON))
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DSR;
if ((eventMask & EV_RING) && GetCommModemStatus(port->handle, &modemStatus) && (modemStatus & MS_RING_ON))
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_RING_INDICATOR;
if ((eventMask & EV_RLSD) && GetCommModemStatus(port->handle, &modemStatus) && (modemStatus & MS_RLSD_ON))
event |= com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_CARRIER_DETECT;
// Return the serial event type
CloseHandle(overlappedStruct.hEvent); CloseHandle(overlappedStruct.hEvent);
return (((eventMask & EV_RXCHAR) > 0) && numBytesRead) ? com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE : return event;
(((eventMask & EV_TXEMPTY) > 0) ? com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN : 0);
} }
JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative(JNIEnv *env, jobject obj, jlong serialPortPointer) JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative(JNIEnv *env, jobject obj, jlong serialPortPointer)
@ -636,8 +664,10 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
CancelIoEx(port->handle, NULL); CancelIoEx(port->handle, NULL);
FlushFileBuffers(port->handle); FlushFileBuffers(port->handle);
SetCommMask(port->handle, 0);
// Close the port // Close the port
port->eventListenerRunning = 0;
if (!CloseHandle(port->handle)) if (!CloseHandle(port->handle))
{ {
port->handle = INVALID_HANDLE_VALUE; port->handle = INVALID_HANDLE_VALUE;
@ -698,32 +728,32 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv
// Create an asynchronous result structure // Create an asynchronous result structure
OVERLAPPED overlappedStruct{}; OVERLAPPED overlappedStruct{};
overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedStruct.hEvent == NULL) if (overlappedStruct.hEvent == NULL)
{ {
port->errorNumber = GetLastError(); port->errorNumber = GetLastError();
port->errorLineNumber = __LINE__ - 4; port->errorLineNumber = __LINE__ - 4;
CloseHandle(overlappedStruct.hEvent); CloseHandle(overlappedStruct.hEvent);
return -1; return -1;
} }
// Read from the serial port // Read from the serial port
BOOL result; BOOL result;
DWORD numBytesRead = 0; DWORD numBytesRead = 0;
if (((result = ReadFile(port->handle, port->readBuffer, bytesToRead, NULL, &overlappedStruct)) == FALSE) && (GetLastError() != ERROR_IO_PENDING)) if (((result = ReadFile(port->handle, port->readBuffer, bytesToRead, NULL, &overlappedStruct)) == FALSE) && (GetLastError() != ERROR_IO_PENDING))
{ {
port->errorLineNumber = __LINE__ - 2; port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError(); port->errorNumber = GetLastError();
} }
else if ((result = GetOverlappedResult(port->handle, &overlappedStruct, &numBytesRead, TRUE)) == FALSE) else if ((result = GetOverlappedResult(port->handle, &overlappedStruct, &numBytesRead, TRUE)) == FALSE)
{ {
port->errorLineNumber = __LINE__ - 2; port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError(); port->errorNumber = GetLastError();
} }
// Return number of bytes read // Return number of bytes read
CloseHandle(overlappedStruct.hEvent); CloseHandle(overlappedStruct.hEvent);
env->SetByteArrayRegion(buffer, offset, numBytesRead, (jbyte*)port->readBuffer); env->SetByteArrayRegion(buffer, offset, numBytesRead, (jbyte*)port->readBuffer);
return (result == TRUE) ? numBytesRead : -1; return (result == TRUE) ? numBytesRead : -1;
} }
@ -735,8 +765,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedStruct.hEvent == NULL) if (overlappedStruct.hEvent == NULL)
{ {
port->errorNumber = GetLastError(); port->errorNumber = GetLastError();
port->errorLineNumber = __LINE__ - 4; port->errorLineNumber = __LINE__ - 4;
CloseHandle(overlappedStruct.hEvent); CloseHandle(overlappedStruct.hEvent);
return -1; return -1;
} }
@ -762,6 +792,11 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
return (result == TRUE) ? numBytesWritten : -1; return (result == TRUE) ? numBytesWritten : -1;
} }
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_setEventListeningStatus(JNIEnv *env, jobject obj, jlong serialPortPointer, jboolean eventListenerRunning)
{
((serialPort*)(intptr_t)serialPortPointer)->eventListenerRunning = eventListenerRunning;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setBreak(JNIEnv *env, jobject obj, jlong serialPortPointer) JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setBreak(JNIEnv *env, jobject obj, jlong serialPortPointer)
{ {
serialPort *port = (serialPort*)(intptr_t)serialPortPointer; serialPort *port = (serialPort*)(intptr_t)serialPortPointer;

View File

@ -2,7 +2,7 @@
* SerialPort.java * SerialPort.java
* *
* Created on: Feb 25, 2012 * Created on: Feb 25, 2012
* Last Updated on: Nov 19, 2021 * Last Updated on: Nov 29, 2021
* Author: Will Hedgecock * Author: Will Hedgecock
* *
* Copyright (C) 2012-2021 Fazecast, Inc. * Copyright (C) 2012-2021 Fazecast, Inc.
@ -395,9 +395,9 @@ public final class SerialPort
static final public int LISTENING_EVENT_DSR = 0x00080000; static final public int LISTENING_EVENT_DSR = 0x00080000;
static final public int LISTENING_EVENT_RING_INDICATOR = 0x00100000; static final public int LISTENING_EVENT_RING_INDICATOR = 0x00100000;
static final public int LISTENING_EVENT_FRAMING_ERROR = 0x00200000; static final public int LISTENING_EVENT_FRAMING_ERROR = 0x00200000;
static final public int LISTENING_EVENT_OVERRUN_ERROR = 0x00400000; static final public int LISTENING_EVENT_FIRMWARE_OVERRUN_ERROR = 0x00400000;
static final public int LISTENING_EVENT_PARITY_ERROR = 0x00800000; static final public int LISTENING_EVENT_SOFTWARE_OVERRUN_ERROR = 0x00800000;
static final public int LISTENING_EVENT_OUTPUT_EMPTY = 0x01000000; static final public int LISTENING_EVENT_PARITY_ERROR = 0x01000000;
// Serial Port Parameters // Serial Port Parameters
private volatile long portHandle = -1; private volatile long portHandle = -1;
@ -434,8 +434,8 @@ public final class SerialPort
{ {
// Set the send/receive internal buffer sizes, and return true if already opened // Set the send/receive internal buffer sizes, and return true if already opened
safetySleepTimeMS = safetySleepTime; safetySleepTimeMS = safetySleepTime;
sendDeviceQueueSize = deviceSendQueueSize; sendDeviceQueueSize = (deviceSendQueueSize > 0) ? deviceSendQueueSize : sendDeviceQueueSize;
receiveDeviceQueueSize = deviceReceiveQueueSize; receiveDeviceQueueSize = (deviceReceiveQueueSize > 0) ? deviceReceiveQueueSize : receiveDeviceQueueSize;
if (portHandle > 0) if (portHandle > 0)
return configPort(portHandle); return configPort(portHandle);
@ -526,7 +526,7 @@ public final class SerialPort
serialEventListener.stopListening(); serialEventListener.stopListening();
if (portHandle > 0) if (portHandle > 0)
portHandle = closePortNative(portHandle); portHandle = closePortNative(portHandle);
return (portHandle < 0); return (portHandle <= 0);
} }
} }
@ -587,6 +587,7 @@ public final class SerialPort
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
private final native int readBytes(long portHandle, byte[] buffer, long bytesToRead, long offset, int timeoutMode, int readTimeout); // Reads bytes from serial port private final native int readBytes(long portHandle, byte[] buffer, long bytesToRead, long offset, int timeoutMode, int readTimeout); // Reads bytes from serial port
private final native int writeBytes(long portHandle, byte[] buffer, long bytesToWrite, long offset, int timeoutMode); // Write bytes to serial port private final native int writeBytes(long portHandle, byte[] buffer, long bytesToWrite, long offset, int timeoutMode); // Write bytes to serial port
private final native void setEventListeningStatus(long portHandle, boolean eventListenerRunning); // Change event listener running flag in native code
private final native boolean setBreak(long portHandle); // Set BREAK status on serial line private final native boolean setBreak(long portHandle); // Set BREAK status on serial line
private final native boolean clearBreak(long portHandle); // Clear BREAK status on serial line private final native boolean clearBreak(long portHandle); // Clear BREAK status on serial line
private final native boolean setRTS(long portHandle); // Set RTS line to 1 private final native boolean setRTS(long portHandle); // Set RTS line to 1
@ -1491,6 +1492,7 @@ public final class SerialPort
eventListenerRunning = true; eventListenerRunning = true;
dataPacketIndex = 0; dataPacketIndex = 0;
setEventListeningStatus(portHandle, true);
serialEventThread = new Thread(new Runnable() serialEventThread = new Thread(new Runnable()
{ {
@Override @Override
@ -1518,6 +1520,7 @@ public final class SerialPort
if (!eventListenerRunning) if (!eventListenerRunning)
return; return;
eventListenerRunning = false; eventListenerRunning = false;
setEventListeningStatus(portHandle, false);
configTimeouts(portHandle, TIMEOUT_NONBLOCKING, 0, 0, 0); configTimeouts(portHandle, TIMEOUT_NONBLOCKING, 0, 0, 0);
try try

View File

@ -2,7 +2,7 @@
* SerialPortTest.java * SerialPortTest.java
* *
* Created on: Feb 27, 2015 * Created on: Feb 27, 2015
* Last Updated on: Nov 16, 2021 * Last Updated on: Nov 29, 2021
* Author: Will Hedgecock * Author: Will Hedgecock
* *
* Copyright (C) 2012-2021 Fazecast, Inc. * Copyright (C) 2012-2021 Fazecast, Inc.
@ -116,7 +116,10 @@ public class SerialPortTest
boolean openedSuccessfully = ubxPort.openPort(0); boolean openedSuccessfully = ubxPort.openPort(0);
System.out.println("\nOpening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + " - " + ubxPort.getPortDescription() + ": " + openedSuccessfully); System.out.println("\nOpening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + " - " + ubxPort.getPortDescription() + ": " + openedSuccessfully);
if (!openedSuccessfully) if (!openedSuccessfully)
{
inputScanner.close();
return; return;
}
System.out.println("Setting read timeout mode to non-blocking"); System.out.println("Setting read timeout mode to non-blocking");
ubxPort.setBaudRate(115200); ubxPort.setBaudRate(115200);
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 1000, 0); ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_NONBLOCKING, 1000, 0);
@ -220,8 +223,40 @@ public class SerialPortTest
openedSuccessfully = ubxPort.openPort(0); openedSuccessfully = ubxPort.openPort(0);
System.out.println("Reopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully); System.out.println("Reopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully);
if (!openedSuccessfully) if (!openedSuccessfully)
{
inputScanner.close();
return; return;
System.out.println("Unplug the device sometime in the next 10 seconds to ensure that it closes properly...\n"); }
System.out.println("\n\nReading for 5 seconds then closing from a separate thread...");
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0);
final SerialPort finalPort = ubxPort;
Thread thread = new Thread(new Runnable()
{
@Override
public void run()
{
byte[] buffer = new byte[2048];
while (finalPort.isOpen())
{
System.out.println("\nStarting blocking read...");
int numRead = finalPort.readBytes(buffer, buffer.length);
System.out.println("Read " + numRead + " bytes");
}
System.out.println("\nPort was successfully closed from a separate thread");
}
});
thread.start();
try { Thread.sleep(5000); } catch (Exception e) { e.printStackTrace(); }
System.out.println("\nClosing " + ubxPort.getDescriptivePortName() + ": " + ubxPort.closePort());
try { thread.join(); } catch (Exception e) { e.printStackTrace(); }
openedSuccessfully = ubxPort.openPort(0);
System.out.println("\nReopening " + ubxPort.getSystemPortName() + ": " + ubxPort.getDescriptivePortName() + ": " + openedSuccessfully);
if (!openedSuccessfully)
{
inputScanner.close();
return;
}
System.out.println("\n\nUnplug the device sometime in the next 10 seconds to ensure that it closes properly...\n");
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0); ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_BLOCKING, 0, 0);
ubxPort.addDataListener(new SerialPortDataListener() { ubxPort.addDataListener(new SerialPortDataListener() {
@Override @Override