Make sure port handle is exactly 0 upon error

This commit is contained in:
Will Hedgecock 2022-01-17 21:52:47 -06:00
parent 101739df33
commit 18d9daf552
36 changed files with 189 additions and 87 deletions

View File

@ -12,7 +12,7 @@ plugins {
group = 'com.fazecast'
archivesBaseName = 'jSerialComm'
version = '2.8.2'
version = '2.8.3'
ext.moduleName = 'com.fazecast.jSerialComm'
if (hasProperty('manualBuild'))

View File

@ -2,7 +2,7 @@
* SerialPort_Posix.c
*
* Created on: Feb 25, 2012
* Last Updated on: Jan 13, 2022
* Last Updated on: Jan 17, 2022
* Author: Will Hedgecock
*
* Copyright (C) 2012-2022 Fazecast, Inc.
@ -43,6 +43,7 @@
#include "PosixHelperFunctions.h"
// Cached class, method, and field IDs
jclass jniErrorClass;
jclass serialCommClass;
jmethodID serialCommConstructor;
jfieldID serialPortFdField;
@ -79,6 +80,23 @@ jfieldID eventFlagsField;
// List of available serial ports
serialPortVector serialPorts = { NULL, 0, 0 };
// JNI exception handler
char jniErrorMessage[64] = { 0 };
int lastErrorLineNumber = 0, lastErrorNumber = 0;
static inline jboolean checkJniError(JNIEnv *env, int lineNumber)
{
// Check if a JNI exception has been thrown
if ((*env)->ExceptionCheck(env))
{
(*env)->ExceptionDescribe(env);
(*env)->ExceptionClear(env);
snprintf(jniErrorMessage, sizeof(jniErrorMessage), "Native exception thrown at line %d", lineNumber);
(*env)->ThrowNew(env, jniErrorClass, jniErrorMessage);
return JNI_TRUE;
}
return JNI_FALSE;
}
#if defined(__linux__) && !defined(__ANDROID__)
// Event listening threads
@ -86,7 +104,7 @@ void* eventReadingThread1(void *serialPortPointer)
{
// Make this thread immediately and asynchronously cancellable
int oldValue;
serialPort *port = (serialPort*)serialPortPointer;
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldValue);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldValue);
@ -134,7 +152,7 @@ void* eventReadingThread2(void *serialPortPointer)
{
// Make this thread immediately and asynchronously cancellable
int oldValue;
serialPort *port = (serialPort*)serialPortPointer;
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &oldValue);
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldValue);
struct serial_icounter_struct oldSerialLineInterrupts, newSerialLineInterrupts;
@ -216,17 +234,24 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
// Create a Java-based port listing
jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0);
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
for (int i = 0; i < serialPorts.length; ++i)
{
// Create a new SerialComm object containing the enumerated values
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portDescription));
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewStringUTF(env, serialPorts.ports[i]->friendlyName));
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portPath));
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
(*env)->SetObjectField(env, serialCommObject, portLocationField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portLocation));
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
// Add new SerialComm object to array
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
}
return arrayObject;
}
@ -234,40 +259,73 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrary(JNIEnv *env, jclass serialComm)
{
// Cache class and method ID as global references
jniErrorClass = (*env)->FindClass(env, "java/lang/Exception");
serialCommClass = (jclass)(*env)->NewGlobalRef(env, serialComm);
if (checkJniError(env, __LINE__ - 1)) return;
serialCommConstructor = (*env)->GetMethodID(env, serialCommClass, "<init>", "()V");
if (checkJniError(env, __LINE__ - 1)) return;
// Cache Java fields as global references
serialPortFdField = (*env)->GetFieldID(env, serialCommClass, "portHandle", "J");
if (checkJniError(env, __LINE__ - 1)) return;
comPortField = (*env)->GetFieldID(env, serialCommClass, "comPort", "Ljava/lang/String;");
if (checkJniError(env, __LINE__ - 1)) return;
friendlyNameField = (*env)->GetFieldID(env, serialCommClass, "friendlyName", "Ljava/lang/String;");
if (checkJniError(env, __LINE__ - 1)) return;
portDescriptionField = (*env)->GetFieldID(env, serialCommClass, "portDescription", "Ljava/lang/String;");
if (checkJniError(env, __LINE__ - 1)) return;
portLocationField = (*env)->GetFieldID(env, serialCommClass, "portLocation", "Ljava/lang/String;");
if (checkJniError(env, __LINE__ - 1)) return;
eventListenerRunningField = (*env)->GetFieldID(env, serialCommClass, "eventListenerRunning", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
autoFlushIOBuffersField = (*env)->GetFieldID(env, serialCommClass, "autoFlushIOBuffers", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I");
if (checkJniError(env, __LINE__ - 1)) return;
dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I");
if (checkJniError(env, __LINE__ - 1)) return;
stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I");
if (checkJniError(env, __LINE__ - 1)) return;
parityField = (*env)->GetFieldID(env, serialCommClass, "parity", "I");
if (checkJniError(env, __LINE__ - 1)) return;
flowControlField = (*env)->GetFieldID(env, serialCommClass, "flowControl", "I");
if (checkJniError(env, __LINE__ - 1)) return;
sendDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "sendDeviceQueueSize", "I");
if (checkJniError(env, __LINE__ - 1)) return;
receiveDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "receiveDeviceQueueSize", "I");
if (checkJniError(env, __LINE__ - 1)) return;
disableExclusiveLockField = (*env)->GetFieldID(env, serialCommClass, "disableExclusiveLock", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
rs485ModeField = (*env)->GetFieldID(env, serialCommClass, "rs485Mode", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
rs485ActiveHighField = (*env)->GetFieldID(env, serialCommClass, "rs485ActiveHigh", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
rs485EnableTerminationField = (*env)->GetFieldID(env, serialCommClass, "rs485EnableTermination", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
rs485RxDuringTxField = (*env)->GetFieldID(env, serialCommClass, "rs485RxDuringTx", "Z");
if (checkJniError(env, __LINE__ - 1)) return;
rs485DelayBeforeField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayBefore", "I");
if (checkJniError(env, __LINE__ - 1)) return;
rs485DelayAfterField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayAfter", "I");
if (checkJniError(env, __LINE__ - 1)) return;
xonStartCharField = (*env)->GetFieldID(env, serialCommClass, "xonStartChar", "B");
if (checkJniError(env, __LINE__ - 1)) return;
xoffStopCharField = (*env)->GetFieldID(env, serialCommClass, "xoffStopChar", "B");
if (checkJniError(env, __LINE__ - 1)) return;
timeoutModeField = (*env)->GetFieldID(env, serialCommClass, "timeoutMode", "I");
if (checkJniError(env, __LINE__ - 1)) return;
readTimeoutField = (*env)->GetFieldID(env, serialCommClass, "readTimeout", "I");
if (checkJniError(env, __LINE__ - 1)) return;
writeTimeoutField = (*env)->GetFieldID(env, serialCommClass, "writeTimeout", "I");
if (checkJniError(env, __LINE__ - 1)) return;
eventFlagsField = (*env)->GetFieldID(env, serialCommClass, "eventFlags", "I");
if (checkJniError(env, __LINE__ - 1)) return;
// Disable handling of various POSIX signals
sigset_t blockMask;
@ -294,16 +352,22 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibr
// Delete the cached global reference
(*env)->DeleteGlobalRef(env, serialCommClass);
checkJniError(env, __LINE__ - 1);
}
JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(JNIEnv *env, jobject obj)
{
// Retrieve the serial port parameter fields
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
if (checkJniError(env, __LINE__ - 1)) return 0;
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char disableExclusiveLock = (*env)->GetBooleanField(env, obj, disableExclusiveLockField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
if (checkJniError(env, __LINE__ - 1)) return 0;
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
if (checkJniError(env, __LINE__ - 1)) return 0;
// Ensure that the serial port still exists and is not already open
serialPort *port = fetchPort(&serialPorts, portName);
@ -315,20 +379,21 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
if (!port || (port->handle > 0))
{
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
port->errorLineNumber = __LINE__ - 3;
port->errorNumber = (!port ? 1 : 2);
checkJniError(env, __LINE__ - 1);
lastErrorLineNumber = __LINE__ - 3;
lastErrorNumber = (!port ? 1 : 2);
return 0;
}
// Try to open the serial port with read/write access
port->errorLineNumber = __LINE__ + 1;
port->errorLineNumber = lastErrorLineNumber = __LINE__ + 1;
if ((port->handle = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC)) > 0)
{
// Ensure that multiple root users cannot access the device simultaneously
if (!disableExclusiveLock && flock(port->handle, LOCK_EX | LOCK_NB))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = errno;
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
while (close(port->handle) && (errno == EINTR))
errno = 0;
port->handle = -1;
@ -350,11 +415,12 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
}
}
else
port->errorNumber = errno;
port->errorNumber = lastErrorNumber = errno;
// Return a pointer to the serial port data structure
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
return (port->handle > 0) ? (jlong)(intptr_t)port : -(jlong)(intptr_t)port;
checkJniError(env, __LINE__ - 1);
return (port->handle > 0) ? (jlong)(intptr_t)port : 0;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(JNIEnv *env, jobject obj, jlong serialPortPointer)
@ -362,26 +428,47 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
// Retrieve port parameters from the Java class
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
baud_rate baudRate = (*env)->GetIntField(env, obj, baudRateField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int byteSizeInt = (*env)->GetIntField(env, obj, dataBitsField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int stopBitsInt = (*env)->GetIntField(env, obj, stopBitsField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int parityInt = (*env)->GetIntField(env, obj, parityField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int flowControl = (*env)->GetIntField(env, obj, flowControlField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int sendDeviceQueueSize = (*env)->GetIntField(env, obj, sendDeviceQueueSizeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int receiveDeviceQueueSize = (*env)->GetIntField(env, obj, receiveDeviceQueueSizeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int rs485DelayBefore = (*env)->GetIntField(env, obj, rs485DelayBeforeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int rs485DelayAfter = (*env)->GetIntField(env, obj, rs485DelayAfterField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int timeoutMode = (*env)->GetIntField(env, obj, timeoutModeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int readTimeout = (*env)->GetIntField(env, obj, readTimeoutField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int writeTimeout = (*env)->GetIntField(env, obj, writeTimeoutField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
int eventsToMonitor = (*env)->GetIntField(env, obj, eventFlagsField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485ModeEnabled = (*env)->GetBooleanField(env, obj, rs485ModeField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485ActiveHigh = (*env)->GetBooleanField(env, obj, rs485ActiveHighField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485EnableTermination = (*env)->GetBooleanField(env, obj, rs485EnableTerminationField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char rs485RxDuringTx = (*env)->GetBooleanField(env, obj, rs485RxDuringTxField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char isDtrEnabled = (*env)->GetBooleanField(env, obj, isDtrEnabledField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
unsigned char isRtsEnabled = (*env)->GetBooleanField(env, obj, isRtsEnabledField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
char xonStartChar = (*env)->GetByteField(env, obj, xonStartCharField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
char xoffStopChar = (*env)->GetByteField(env, obj, xoffStopCharField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
// Clear any serial port flags and set up raw non-canonical port parameters
struct termios options = { 0 };
@ -422,8 +509,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
cfsetospeed(&options, baudRateCode);
if (tcsetattr(port->handle, TCSANOW, &options) || tcsetattr(port->handle, TCSANOW, &options))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = errno;
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
return JNI_FALSE;
}
@ -444,7 +531,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
sendDeviceQueueSize = serInfo.xmit_fifo_size;
receiveDeviceQueueSize = sendDeviceQueueSize;
(*env)->SetIntField(env, obj, sendDeviceQueueSizeField, sendDeviceQueueSize);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
(*env)->SetIntField(env, obj, receiveDeviceQueueSizeField, receiveDeviceQueueSize);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
// Attempt to set the requested RS-485 mode
struct serial_rs485 rs485Conf = { 0 };
@ -474,18 +563,15 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
rs485Conf.flags &= ~(SER_RS485_TERMINATE_BUS);
rs485Conf.delay_rts_before_send = rs485DelayBefore / 1000;
rs485Conf.delay_rts_after_send = rs485DelayAfter / 1000;
if (ioctl(port->handle, TIOCSRS485, &rs485Conf) && rs485ModeEnabled)
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = errno;
return JNI_FALSE;
}
ioctl(port->handle, TIOCSRS485, &rs485Conf);
}
#else
(*env)->SetIntField(env, obj, sendDeviceQueueSizeField, sysconf(_SC_PAGESIZE));
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
(*env)->SetIntField(env, obj, receiveDeviceQueueSizeField, sysconf(_SC_PAGESIZE));
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
#endif
@ -500,6 +586,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
struct termios options = { 0 };
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
baud_rate baudRate = (*env)->GetIntField(env, obj, baudRateField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
tcgetattr(port->handle, &options);
// Set up the requested event flags
@ -547,20 +634,20 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou
// Apply changes
if (fcntl(port->handle, F_SETFL, flags))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = errno;
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
return JNI_FALSE;
}
if (tcsetattr(port->handle, TCSANOW, &options) || tcsetattr(port->handle, TCSANOW, &options))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = errno;
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
return JNI_FALSE;
}
if (!getBaudRateCode(baudRate) && setBaudRateCustom(port->handle, baudRate))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = errno;
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
port->errorNumber = lastErrorNumber = errno;
return JNI_FALSE;
}
return JNI_TRUE;
@ -681,7 +768,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(J
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
int numBytesAvailable = -1;
port->errorLineNumber = __LINE__ + 1;
ioctl(((serialPort*)(intptr_t)serialPortPointer)->handle, FIONREAD, &numBytesAvailable);
ioctl(port->handle, FIONREAD, &numBytesAvailable);
port->errorNumber = errno;
return numBytesAvailable;
}
@ -692,7 +779,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAwaitingWri
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
int numBytesToWrite = -1;
port->errorLineNumber = __LINE__ + 1;
ioctl(((serialPort*)(intptr_t)serialPortPointer)->handle, TIOCOUTQ, &numBytesToWrite);
ioctl(port->handle, TIOCOUTQ, &numBytesToWrite);
port->errorNumber = errno;
return numBytesToWrite;
}
@ -771,6 +858,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv
// Return number of bytes read if successful
(*env)->SetByteArrayRegion(env, buffer, offset, numBytesReadTotal, (jbyte*)port->readBuffer);
checkJniError(env, __LINE__ - 1);
return (numBytesRead == -1) ? -1 : numBytesReadTotal;
}
@ -779,6 +867,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
// Retrieve port parameters from the Java class
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
jbyte *writeBuffer = (*env)->GetByteArrayElements(env, buffer, 0);
if (checkJniError(env, __LINE__ - 1)) return -1;
// Write to the port
int numBytesWritten;
@ -795,6 +884,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn
// Return the number of bytes written if successful
(*env)->ReleaseByteArrayElements(env, buffer, writeBuffer, JNI_ABORT);
checkJniError(env, __LINE__ - 1);
return numBytesWritten;
}
@ -888,7 +978,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearRTS(JNI
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetRTS(JNIEnv *env, jobject obj)
{
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
// Send a system command to preset the RTS mode of the serial port
char commandString[128];
@ -900,13 +992,16 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetRTS(JN
int result = system(commandString);
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
checkJniError(env, __LINE__ - 1);
return (result == 0);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearRTS(JNIEnv *env, jobject obj)
{
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
// Send a system command to preset the RTS mode of the serial port
char commandString[128];
@ -918,6 +1013,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearRTS(
int result = system(commandString);
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
checkJniError(env, __LINE__ - 1);
return (result == 0);
}
@ -950,7 +1046,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearDTR(JNI
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetDTR(JNIEnv *env, jobject obj)
{
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
// Send a system command to preset the DTR mode of the serial port
char commandString[128];
@ -962,13 +1060,16 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetDTR(JN
int result = system(commandString);
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
checkJniError(env, __LINE__ - 1);
return (result == 0);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearDTR(JNIEnv *env, jobject obj)
{
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
if (checkJniError(env, __LINE__ - 1)) return JNI_FALSE;
// Send a system command to preclear the DTR mode of the serial port
char commandString[128];
@ -980,6 +1081,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearDTR(
int result = system(commandString);
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
checkJniError(env, __LINE__ - 1);
return (result == 0);
}
@ -1021,10 +1123,10 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRI(JNIEnv
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_getLastErrorLocation(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
return ((serialPort*)(intptr_t)serialPortPointer)->errorLineNumber;
return serialPortPointer ? ((serialPort*)(intptr_t)serialPortPointer)->errorLineNumber : lastErrorLineNumber;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_getLastErrorCode(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
return ((serialPort*)(intptr_t)serialPortPointer)->errorNumber;
return serialPortPointer ? ((serialPort*)(intptr_t)serialPortPointer)->errorNumber : lastErrorNumber;
}

View File

@ -2,7 +2,7 @@
* SerialPort.java
*
* Created on: Feb 25, 2012
* Last Updated on: Jan 11, 2022
* Last Updated on: Jan 17, 2022
* Author: Will Hedgecock
*
* Copyright (C) 2012-2022 Fazecast, Inc.
@ -43,14 +43,14 @@ import java.util.Date;
* This class provides native access to serial ports and devices without requiring external libraries or tools.
*
* @author Will Hedgecock &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see java.io.InputStream
* @see java.io.OutputStream
*/
public final class SerialPort
{
// Static initializer loads correct native library for this machine
static private final String versionString = "2.8.2";
static private final String versionString = "2.8.3";
static private final String tmpdirAppIdProperty = "fazecast.jSerialComm.appid";
static private volatile boolean isAndroid = false;
static private volatile boolean isWindows = false;
@ -560,7 +560,7 @@ public final class SerialPort
safetySleepTimeMS = safetySleepTime;
sendDeviceQueueSize = (deviceSendQueueSize > 0) ? deviceSendQueueSize : sendDeviceQueueSize;
receiveDeviceQueueSize = (deviceReceiveQueueSize > 0) ? deviceReceiveQueueSize : receiveDeviceQueueSize;
if (portHandle > 0)
if (portHandle != 0)
return configPort(portHandle);
// Force a sleep to ensure that the port does not become unusable due to rapid closing/opening on the part of the user
@ -600,12 +600,12 @@ public final class SerialPort
}
// Open the serial port and start an event-based listener if registered
if ((portHandle = openPortNative()) > 0)
if ((portHandle = openPortNative()) != 0)
{
if (serialEventListener != null)
serialEventListener.startListening();
}
return (portHandle > 0);
return (portHandle != 0);
}
}
@ -648,9 +648,9 @@ public final class SerialPort
{
if (serialEventListener != null)
serialEventListener.stopListening();
if (portHandle > 0)
if (portHandle != 0)
portHandle = closePortNative(portHandle);
return (portHandle <= 0);
return (portHandle == 0);
}
}
@ -659,7 +659,7 @@ public final class SerialPort
*
* @return Whether the port is opened.
*/
public final synchronized boolean isOpen() { return (portHandle > 0); }
public final synchronized boolean isOpen() { return (portHandle != 0); }
/**
* Disables the library from calling any of the underlying device driver configuration methods.
@ -687,7 +687,7 @@ public final class SerialPort
*
* @return Source line of latest native code error.
*/
public final synchronized int getLastErrorLocation() { return (portHandle != 0) ? getLastErrorLocation((portHandle > 0) ? portHandle : -portHandle) : -1; }
public final synchronized int getLastErrorLocation() { return getLastErrorLocation(portHandle); }
/**
* Returns the error number returned by the most recent native source code line that failed execution.
@ -697,7 +697,7 @@ public final class SerialPort
*
* @return Error number of the latest native code error.
*/
public final synchronized int getLastErrorCode() { return (portHandle != 0) ? getLastErrorCode((portHandle > 0) ? portHandle : -portHandle) : 0; }
public final synchronized int getLastErrorCode() { return getLastErrorCode(portHandle); }
// Serial Port Setup Methods
private static native void initializeLibrary(); // Initializes the JNI code
@ -738,7 +738,7 @@ public final class SerialPort
*
* @return The number of bytes currently available to be read, or -1 if the port is not open.
*/
public final int bytesAvailable() { return (portHandle > 0) ? bytesAvailable(portHandle) : -1; }
public final int bytesAvailable() { return (portHandle != 0) ? bytesAvailable(portHandle) : -1; }
/**
* Returns the number of bytes still waiting to be written in the device's output queue.
@ -747,7 +747,7 @@ public final class SerialPort
*
* @return The number of bytes currently waiting to be written, or -1 if the port is not open.
*/
public final int bytesAwaitingWrite() { return (portHandle > 0) ? bytesAwaitingWrite(portHandle) : -1; }
public final int bytesAwaitingWrite() { return (portHandle != 0) ? bytesAwaitingWrite(portHandle) : -1; }
/**
* Reads up to <i>bytesToRead</i> raw data bytes from the serial port and stores them in the buffer.
@ -762,7 +762,7 @@ public final class SerialPort
* @param bytesToRead The number of bytes to read from the serial port.
* @return The number of bytes successfully read, or -1 if there was an error reading from the port.
*/
public final int readBytes(byte[] buffer, long bytesToRead) { return (portHandle > 0) ? readBytes(portHandle, buffer, bytesToRead, 0, timeoutMode, readTimeout) : -1; }
public final int readBytes(byte[] buffer, long bytesToRead) { return (portHandle != 0) ? readBytes(portHandle, buffer, bytesToRead, 0, timeoutMode, readTimeout) : -1; }
/**
* Reads up to <i>bytesToRead</i> raw data bytes from the serial port and stores them in the buffer starting at the indicated offset.
@ -778,7 +778,7 @@ public final class SerialPort
* @param offset The read buffer index into which to begin storing data.
* @return The number of bytes successfully read, or -1 if there was an error reading from the port.
*/
public final int readBytes(byte[] buffer, long bytesToRead, long offset) { return (portHandle > 0) ? readBytes(portHandle, buffer, bytesToRead, offset, timeoutMode, readTimeout) : -1; }
public final int readBytes(byte[] buffer, long bytesToRead, long offset) { return (portHandle != 0) ? readBytes(portHandle, buffer, bytesToRead, offset, timeoutMode, readTimeout) : -1; }
/**
* Writes up to <i>bytesToWrite</i> raw data bytes from the buffer parameter to the serial port.
@ -797,7 +797,7 @@ public final class SerialPort
{
// Write to the serial port until all bytes have been consumed
int totalNumWritten = 0;
while ((portHandle > 0) && (totalNumWritten != bytesToWrite))
while ((portHandle != 0) && (totalNumWritten != bytesToWrite))
{
int numWritten = writeBytes(portHandle, buffer, bytesToWrite - totalNumWritten, totalNumWritten, timeoutMode);
if (numWritten > 0)
@ -805,7 +805,7 @@ public final class SerialPort
else
break;
}
return ((portHandle > 0) && (totalNumWritten >= 0)) ? totalNumWritten : -1;
return ((portHandle != 0) && (totalNumWritten >= 0)) ? totalNumWritten : -1;
}
/**
@ -826,7 +826,7 @@ public final class SerialPort
{
// Write to the serial port until all bytes have been consumed
int totalNumWritten = 0;
while ((portHandle > 0) && (totalNumWritten != bytesToWrite))
while ((portHandle != 0) && (totalNumWritten != bytesToWrite))
{
int numWritten = writeBytes(portHandle, buffer, bytesToWrite - totalNumWritten, offset + totalNumWritten, timeoutMode);
if (numWritten > 0)
@ -834,7 +834,7 @@ public final class SerialPort
else
break;
}
return ((portHandle > 0) && (totalNumWritten >= 0)) ? totalNumWritten : -1;
return ((portHandle != 0) && (totalNumWritten >= 0)) ? totalNumWritten : -1;
}
/**
@ -857,13 +857,13 @@ public final class SerialPort
* Sets the BREAK signal on the serial control line.
* @return true if successful, false if not.
*/
public final boolean setBreak() { return (portHandle > 0) && setBreak(portHandle); }
public final boolean setBreak() { return (portHandle != 0) && setBreak(portHandle); }
/**
* Clears the BREAK signal from the serial control line.
* @return true if successful, false if not.
*/
public final boolean clearBreak() { return (portHandle > 0) && clearBreak(portHandle); }
public final boolean clearBreak() { return (portHandle != 0) && clearBreak(portHandle); }
/**
* Sets the state of the RTS line to 1.
@ -872,7 +872,7 @@ public final class SerialPort
public final boolean setRTS()
{
isRtsEnabled = true;
return (portHandle > 0) ? setRTS(portHandle) : presetRTS();
return (portHandle != 0) ? setRTS(portHandle) : presetRTS();
}
/**
@ -882,7 +882,7 @@ public final class SerialPort
public final boolean clearRTS()
{
isRtsEnabled = false;
return (portHandle > 0) ? clearRTS(portHandle) : preclearRTS();
return (portHandle != 0) ? clearRTS(portHandle) : preclearRTS();
}
/**
@ -892,7 +892,7 @@ public final class SerialPort
public final boolean setDTR()
{
isDtrEnabled = true;
return (portHandle > 0) ? setDTR(portHandle) : presetDTR();
return (portHandle != 0) ? setDTR(portHandle) : presetDTR();
}
/**
@ -902,26 +902,26 @@ public final class SerialPort
public final boolean clearDTR()
{
isDtrEnabled = false;
return (portHandle > 0) ? clearDTR(portHandle) : preclearDTR();
return (portHandle != 0) ? clearDTR(portHandle) : preclearDTR();
}
/**
* Returns whether the CTS line is currently asserted.
* @return Whether or not the CTS line is asserted.
*/
public final boolean getCTS() { return (portHandle > 0) && getCTS(portHandle); }
public final boolean getCTS() { return (portHandle != 0) && getCTS(portHandle); }
/**
* Returns whether the DSR line is currently asserted.
* @return Whether or not the DSR line is asserted.
*/
public final boolean getDSR() { return (portHandle > 0) && getDSR(portHandle); }
public final boolean getDSR() { return (portHandle != 0) && getDSR(portHandle); }
/**
* Returns whether the DCD line is currently asserted.
* @return Whether or not the DCD line is asserted.
*/
public final boolean getDCD() { return (portHandle > 0) && getDCD(portHandle); }
public final boolean getDCD() { return (portHandle != 0) && getDCD(portHandle); }
/**
* Returns whether the DTR line is currently asserted.
@ -929,7 +929,7 @@ public final class SerialPort
* Note that polling this line's status is not supported on Windows, so results may be incorrect.
* @return Whether or not the DTR line is asserted.
*/
public final boolean getDTR() { return (portHandle > 0) && getDTR(portHandle); }
public final boolean getDTR() { return (portHandle != 0) && getDTR(portHandle); }
/**
* Returns whether the RTS line is currently asserted.
@ -937,13 +937,13 @@ public final class SerialPort
* Note that polling this line's status is not supported on Windows, so results may be incorrect.
* @return Whether or not the RTS line is asserted.
*/
public final boolean getRTS() { return (portHandle > 0) && getRTS(portHandle); }
public final boolean getRTS() { return (portHandle != 0) && getRTS(portHandle); }
/**
* Returns whether the RI line is currently asserted.
* @return Whether or not the RI line is asserted.
*/
public final boolean getRI() { return (portHandle > 0) && getRI(portHandle); }
public final boolean getRI() { return (portHandle != 0) && getRI(portHandle); }
// Default Constructor
private SerialPort() {}
@ -982,7 +982,7 @@ public final class SerialPort
((userDataListener instanceof SerialPortMessageListener) ?
new SerialPortEventListener(((SerialPortMessageListener)userDataListener).getMessageDelimiter(), ((SerialPortMessageListener)userDataListener).delimiterIndicatesEndOfMessage()) :
new SerialPortEventListener()));
if (portHandle > 0)
if (portHandle != 0)
{
configTimeouts(portHandle, timeoutMode, readTimeout, writeTimeout, eventFlags);
serialEventListener.startListening();
@ -1095,7 +1095,7 @@ public final class SerialPort
{
autoFlushIOBuffers = true;
if (portHandle > 0)
if (portHandle != 0)
return flushRxTxBuffers(portHandle);
return true;
}
@ -1174,7 +1174,7 @@ public final class SerialPort
parity = newParity;
rs485Mode = useRS485Mode;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1245,7 +1245,7 @@ public final class SerialPort
else
readTimeout = Math.round((float)newReadTimeout / 100.0f) * 100;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1266,7 +1266,7 @@ public final class SerialPort
{
baudRate = newBaudRate;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1287,7 +1287,7 @@ public final class SerialPort
{
dataBits = newDataBits;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1314,7 +1314,7 @@ public final class SerialPort
{
stopBits = newStopBits;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1362,7 +1362,7 @@ public final class SerialPort
{
flowControl = newFlowControlSettings;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1389,7 +1389,7 @@ public final class SerialPort
{
parity = newParity;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1449,7 +1449,7 @@ public final class SerialPort
rs485DelayBefore = delayBeforeSendMicroseconds;
rs485DelayAfter = delayAfterSendMicroseconds;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1474,7 +1474,7 @@ public final class SerialPort
xonStartChar = xonStartCharacter;
xoffStopChar = xoffStopCharacter;
if (portHandle > 0)
if (portHandle != 0)
{
if (safetySleepTimeMS > 0)
try { Thread.sleep(safetySleepTimeMS); } catch (Exception e) { Thread.currentThread().interrupt(); }
@ -1778,7 +1778,7 @@ public final class SerialPort
@Override
public final int available() throws SerialPortIOException
{
if (portHandle <= 0)
if (portHandle == 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
return bytesAvailable(portHandle);
}
@ -1787,7 +1787,7 @@ public final class SerialPort
public final int read() throws SerialPortIOException, SerialPortTimeoutException
{
// Perform error checking
if (portHandle <= 0)
if (portHandle == 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
// Read from the serial port
@ -1808,7 +1808,7 @@ public final class SerialPort
// Perform error checking
if (b == null)
throw new NullPointerException("A null pointer was passed in for the read buffer.");
if (portHandle <= 0)
if (portHandle == 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
if (b.length == 0)
return 0;
@ -1828,7 +1828,7 @@ public final class SerialPort
throw new NullPointerException("A null pointer was passed in for the read buffer.");
if ((len < 0) || (off < 0) || (len > (b.length - off)))
throw new IndexOutOfBoundsException("The specified read offset plus length extends past the end of the specified buffer.");
if (portHandle <= 0)
if (portHandle == 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
if ((b.length == 0) || (len == 0))
return 0;
@ -1843,7 +1843,7 @@ public final class SerialPort
@Override
public final long skip(long n) throws SerialPortIOException
{
if (portHandle <= 0)
if (portHandle == 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
byte[] buffer = new byte[(int)n];
return readBytes(portHandle, buffer, n, 0, timeoutMode, readTimeout);
@ -1860,7 +1860,7 @@ public final class SerialPort
@Override
public final void write(int b) throws SerialPortIOException, SerialPortTimeoutException
{
if (portHandle <= 0)
if (portHandle == 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
byteBuffer[0] = (byte)(b & 0xFF);
int bytesWritten = writeBytes(portHandle, byteBuffer, 1L, 0, timeoutMode);
@ -1890,7 +1890,7 @@ public final class SerialPort
while (totalNumWritten != len)
{
// Always ensure that the port has not been closed
if (portHandle <= 0)
if (portHandle == 0)
throw new SerialPortIOException("This port appears to have been shutdown or disconnected.");
// Write the actual bytes to the serial port

View File

@ -31,7 +31,7 @@ import java.util.EventListener;
* This interface must be implemented to enable simple event-based serial port I/O.
*
* @author Will Hedgecock &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see java.util.EventListener
*/
public interface SerialPortDataListener extends EventListener

View File

@ -29,7 +29,7 @@ package com.fazecast.jSerialComm;
* This interface must be implemented to enable simple event-based serial port I/O with a custom Exception callback.
*
* @author Will Hedgecock &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see com.fazecast.jSerialComm.SerialPortDataListener
* @see java.util.EventListener
*/

View File

@ -31,7 +31,7 @@ import java.util.EventObject;
* This class describes an asynchronous serial port event.
*
* @author Will Hedgecock &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see java.util.EventObject
*/
public class SerialPortEvent extends EventObject

View File

@ -31,7 +31,7 @@ import java.io.IOException;
* This class describes a serial port IO exception.
*
* @author Will Hedgecock &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see java.io.IOException
*/
public final class SerialPortIOException extends IOException

View File

@ -29,7 +29,7 @@ package com.fazecast.jSerialComm;
* This class describes a serial port invalid port exception.
*
* @author Will Hedgecock &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see java.lang.RuntimeException
*/
public final class SerialPortInvalidPortException extends RuntimeException

View File

@ -31,7 +31,7 @@ package com.fazecast.jSerialComm;
* <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 &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see com.fazecast.jSerialComm.SerialPortDataListener
* @see java.util.EventListener
*/

View File

@ -31,7 +31,7 @@ package com.fazecast.jSerialComm;
* <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 &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see com.fazecast.jSerialComm.SerialPortMessageListener
* @see com.fazecast.jSerialComm.SerialPortDataListener
* @see java.util.EventListener

View File

@ -31,7 +31,7 @@ package com.fazecast.jSerialComm;
* <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 &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see com.fazecast.jSerialComm.SerialPortDataListener
* @see java.util.EventListener
*/

View File

@ -31,7 +31,7 @@ import java.io.InterruptedIOException;
* This class describes a serial port timeout exception.
*
* @author Will Hedgecock &lt;will.hedgecock@fazecast.com&gt;
* @version 2.8.2
* @version 2.8.3
* @see java.io.InterruptedIOException
*/
public final class SerialPortTimeoutException extends InterruptedIOException