diff --git a/INSTALL b/INSTALL index b6c95c8..75c0cb0 100644 --- a/INSTALL +++ b/INSTALL @@ -123,29 +123,29 @@ Maven: com.fazecast jSerialComm - 1.3.8 + 1.3.9 Ivy: - + Groovy: -@Grab(group='com.fazecast', module='jSerialComm', version='1.3.8') +@Grab(group='com.fazecast', module='jSerialComm', version='1.3.9') Gradle: -compile 'com.fazecast:jSerialComm:1.3.8' +compile 'com.fazecast:jSerialComm:1.3.9' Buildr: -compile.with 'com.fazecast:jSerialComm:jar:1.3.8' +compile.with 'com.fazecast:jSerialComm:jar:1.3.9' Scala/SBT: -libraryDependencies += "com.fazecast" % "jSerialComm" % "1.3.8" +libraryDependencies += "com.fazecast" % "jSerialComm" % "1.3.9" Leiningen: -[com.fazecast/jSerialComm "1.3.8"] +[com.fazecast/jSerialComm "1.3.9"] diff --git a/build.gradle b/build.gradle index 3daeeb3..3997663 100644 --- a/build.gradle +++ b/build.gradle @@ -4,7 +4,7 @@ apply plugin: 'maven' group = 'com.fazecast' archivesBaseName = 'jSerialComm' -version = '1.3.8' +version = '1.3.9' sourceCompatibility = 1.6 targetCompatibility = 1.6 diff --git a/src/main/c/Android/jni/Android.mk b/src/main/c/Android/jni/Android.mk index 0379d18..afc3114 100644 --- a/src/main/c/Android/jni/Android.mk +++ b/src/main/c/Android/jni/Android.mk @@ -4,9 +4,10 @@ include $(CLEAR_VARS) LOCAL_MODULE := jSerialComm LOCAL_SRC_FILES := SerialPort_Android.c AndroidHelperFunctions.c +LOCAL_LDLIBS := -llog include $(BUILD_SHARED_LIBRARY) all: cp -rf libs/* ../../resources/Android - rm -rf libs obj/* obj + rm -rf libs/* libs obj diff --git a/src/main/c/Android/jni/AndroidHelperFunctions.c b/src/main/c/Android/jni/AndroidHelperFunctions.c index 75f527c..a0bceae 100644 --- a/src/main/c/Android/jni/AndroidHelperFunctions.c +++ b/src/main/c/Android/jni/AndroidHelperFunctions.c @@ -32,6 +32,8 @@ #include #include #include +#include +#include #ifndef BOTHER #include #endif @@ -245,18 +247,23 @@ void setBaudRate(int portFD, int baudRate) { #ifdef BOTHER struct termios2 options = { 0 }; - ioctl(portFD, TCGETS2, &options); + + if (isatty(portFD)) + ioctl(portFD, TCGETS2, &options); options.c_cflag &= ~CBAUD; options.c_cflag |= BOTHER; options.c_ispeed = baudRate; options.c_ospeed = baudRate; - ioctl(portFD, TCSETS2, &options); + if (isatty(portFD)) + ioctl(portFD, TCSETS2, &options); #else struct termios options = { 0 }; - tcgetattr(portFD, &options); + if (isatty(portFD)) + ioctl(portFD, TCGETS, &options); cfsetispeed(&options, B38400); cfsetospeed(&options, B38400); - tcsetattr(portFD, TCSANOW, &options); + if (isatty(portFD)) + ioctl(portFD, TCSETS, &options); #endif } diff --git a/src/main/c/Android/jni/SerialPort_Android.c b/src/main/c/Android/jni/SerialPort_Android.c index 5341179..9e17c18 100644 --- a/src/main/c/Android/jni/SerialPort_Android.c +++ b/src/main/c/Android/jni/SerialPort_Android.c @@ -2,7 +2,7 @@ * SerialPort_Android.c * * Created on: Mar 13, 2015 - * Last Updated on: May 19, 2015 + * Last Updated on: Oct 09, 2015 * Author: Will Hedgecock * * Copyright (C) 2012-2015 Fazecast, Inc. @@ -27,7 +27,9 @@ #ifndef CMSPAR #define CMSPAR 010000000000 #endif +#include #include +#include #include #include #include @@ -35,9 +37,15 @@ #include #include #include +#include +#include #include "com_fazecast_jSerialComm_SerialPort.h" #include "AndroidHelperFunctions.h" +// Logging defines +#define LOG_TAG "com.fazecast.jSerialComm" +#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) + // Cached class, method, and field IDs jclass serialCommClass; jmethodID serialCommConstructor; @@ -104,7 +112,7 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm) { - // Delete the cache global reference + // Delete the cached global reference (*env)->DeleteGlobalRef(env, serialCommClass); } @@ -124,7 +132,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative( else { // Close the port if there was a problem setting the parameters - close(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); } @@ -150,10 +158,12 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J tcflag_t parity = (parityInt == com_fazecast_jSerialComm_SerialPort_NO_PARITY) ? 0 : (parityInt == com_fazecast_jSerialComm_SerialPort_ODD_PARITY) ? (PARENB | PARODD) : (parityInt == com_fazecast_jSerialComm_SerialPort_EVEN_PARITY) ? PARENB : (parityInt == com_fazecast_jSerialComm_SerialPort_MARK_PARITY) ? (PARENB | CMSPAR | PARODD) : (PARENB | CMSPAR); // Clear any serial port flags - fcntl(serialPortFD, F_SETFL, 0); + if (isatty(serialPortFD)) + fcntl(serialPortFD, F_SETFL, 0); - // Set raw-mode to allow the use of tcsetattr() and ioctl() - tcgetattr(serialPortFD, &options); + // Set raw-mode to allow the use of ioctl() + if (isatty(serialPortFD)) + ioctl(serialPortFD, TCGETS, &options); cfmakeraw(&options); // Set updated port parameters @@ -175,8 +185,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J } // Apply changes - int retVal = tcsetattr(serialPortFD, TCSANOW, &options); - ioctl(serialPortFD, TIOCEXCL); // Block non-root users from using this port + int retVal = -1; + if (isatty(serialPortFD)) + retVal = ioctl(serialPortFD, TCSETS, &options); if (baudRateCode == 0) // Set custom baud rate setBaudRate(serialPortFD, baudRate); return ((retVal == 0) ? JNI_TRUE : JNI_FALSE); @@ -198,14 +209,17 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configFlowCo tcflag_t XonXoffOutEnabled = ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0) ? IXON : 0; // Retrieve existing port configuration - tcgetattr(serialPortFD, &options); + if (isatty(serialPortFD)) + ioctl(serialPortFD, TCGETS, &options); // Set updated port parameters options.c_cflag |= CTSRTSEnabled; options.c_iflag |= XonXoffInEnabled | XonXoffOutEnabled; // Apply changes - int retVal = tcsetattr(serialPortFD, TCSANOW, &options); + int retVal = -1; + if (isatty(serialPortFD)) + retVal = ioctl(serialPortFD, TCSETS, &options); if (baudRateCode == 0) // Set custom baud rate setBaudRate(serialPortFD, baudRate); return ((retVal == 0) ? JNI_TRUE : JNI_FALSE); @@ -223,8 +237,11 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou // Retrieve existing port configuration struct termios options = { 0 }; - tcgetattr(serialPortFD, &options); + if (isatty(serialPortFD)) + ioctl(serialPortFD, TCGETS, &options); int flags = fcntl(serialPortFD, F_GETFL); + if (flags == -1) + return JNI_FALSE; // Set updated port timeouts if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) && (readTimeout > 0)) // Read Semi-blocking with timeout @@ -265,8 +282,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou } // Apply changes - fcntl(serialPortFD, F_SETFL, flags); - int retVal = tcsetattr(serialPortFD, TCSANOW, &options); + int retVal = fcntl(serialPortFD, F_SETFL, flags); + if ((retVal != -1) && isatty(serialPortFD)) + retVal = ioctl(serialPortFD, TCSETS, &options); if (baudRateCode == 0) // Set custom baud rate setBaudRate(serialPortFD, baudRate); return ((retVal == 0) ? JNI_TRUE : JNI_FALSE); @@ -283,24 +301,27 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventF int eventsToMonitor = (*env)->GetIntField(env, obj, eventFlagsField); // Change read timeouts if we are monitoring data received + jboolean retVal; if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0) { struct termios options = { 0 }; - tcgetattr(serialPortFD, &options); + ioctl(serialPortFD, TCGETS, &options); int flags = fcntl(serialPortFD, F_GETFL); + if (flags == -1) + return JNI_FALSE; flags &= ~O_NONBLOCK; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; - fcntl(serialPortFD, F_SETFL, flags); - tcsetattr(serialPortFD, TCSANOW, &options); + retVal = ((fcntl(serialPortFD, F_SETFL, flags) == -1) || (ioctl(serialPortFD, TCSETS, &options) == -1)) ? + JNI_FALSE : JNI_TRUE; if (baudRateCode == 0) // Set custom baud rate setBaudRate(serialPortFD, baudRate); } else - Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortFD); + retVal = Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortFD); // Apply changes - return JNI_TRUE; + return retVal; } JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortFD) @@ -315,7 +336,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI FD_SET(serialPortFD, &waitingSet); // Wait for a serial port event - int retVal = select(serialPortFD + 1, &waitingSet, NULL, NULL, &timeout); + int retVal; + do { retVal = select(serialPortFD + 1, &waitingSet, NULL, NULL, &timeout); } while ((retVal < 0) && (errno == EINTR)); if (retVal <= 0) return 0; return (FD_ISSET(serialPortFD, &waitingSet)) ? com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE : 0; @@ -326,7 +348,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat // Close port if (serialPortFD <= 0) return JNI_TRUE; - close(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetLongField(env, obj, serialPortFdField, -1l); (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); @@ -359,10 +381,11 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv // While there are more bytes we are supposed to read while (bytesRemaining > 0) { - if ((numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining)) == -1) + do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); + if (numBytesRead == -1) { // Problem reading, close port - close(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetLongField(env, obj, serialPortFdField, -1l); (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); @@ -389,10 +412,11 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv // While there are more bytes we are supposed to read and the timeout has not elapsed do { - if ((numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining)) == -1) + do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); + if (numBytesRead == -1) { // Problem reading, close port - close(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetLongField(env, obj, serialPortFdField, -1l); (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); @@ -411,10 +435,11 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv else // Semi- or non-blocking specified { // Read from port - if ((numBytesRead = read(serialPortFD, readBuffer, bytesToRead)) == -1) + do { numBytesRead = read(serialPortFD, readBuffer, bytesToRead); } while ((numBytesRead < 0) && (errno == EINTR)); + if (numBytesRead == -1) { // Problem reading, close port - close(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetLongField(env, obj, serialPortFdField, -1l); (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); @@ -437,10 +462,11 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn int numBytesWritten; // Write to port - if ((numBytesWritten = write(serialPortFD, writeBuffer, bytesToWrite)) == -1) + do { numBytesWritten = write(serialPortFD, writeBuffer, bytesToWrite); } while ((numBytesWritten < 0) && (errno == EINTR)); + if (numBytesWritten == -1) { // Problem writing, close port - close(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetLongField(env, obj, serialPortFdField, -1l); (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); diff --git a/src/main/c/Android/jni/com_fazecast_jSerialComm_SerialPort.h b/src/main/c/Android/jni/com_fazecast_jSerialComm_SerialPort.h index 17f91d2..333a0c2 100644 --- a/src/main/c/Android/jni/com_fazecast_jSerialComm_SerialPort.h +++ b/src/main/c/Android/jni/com_fazecast_jSerialComm_SerialPort.h @@ -87,6 +87,14 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibr JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative (JNIEnv *, jobject); +/* + * Class: com_fazecast_jSerialComm_SerialPort + * Method: associateNativeHandle + * Signature: (J)Z + */ +JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_associateNativeHandle + (JNIEnv *, jobject, jlong); + /* * Class: com_fazecast_jSerialComm_SerialPort * Method: closePortNative diff --git a/src/main/c/Linux/SerialPort_Linux.c b/src/main/c/Linux/SerialPort_Linux.c index f55675a..8bbeb15 100644 --- a/src/main/c/Linux/SerialPort_Linux.c +++ b/src/main/c/Linux/SerialPort_Linux.c @@ -2,7 +2,7 @@ * SerialPort_Linux.c * * Created on: Feb 25, 2012 - * Last Updated on: May 04, 2015 + * Last Updated on: Oct 09, 2015 * Author: Will Hedgecock * * Copyright (C) 2012-2015 Fazecast, Inc. @@ -126,7 +126,9 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative( else { // Close the port if there was a problem setting the parameters - close(serialPortFD); + ioctl(serialPortFD, TIOCNXCL); + tcdrain(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); } @@ -179,7 +181,7 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J // Apply changes int retVal = tcsetattr(serialPortFD, TCSANOW, &options); - ioctl(serialPortFD, TIOCEXCL); // Block non-root users from using this port + ioctl(serialPortFD, TIOCEXCL); // Block non-root users from opening this port if (baudRateCode == 0) // Set custom baud rate setBaudRate(serialPortFD, baudRate); return ((retVal == 0) ? JNI_TRUE : JNI_FALSE); @@ -228,6 +230,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou struct termios options = { 0 }; tcgetattr(serialPortFD, &options); int flags = fcntl(serialPortFD, F_GETFL); + if (flags == -1) + return JNI_FALSE; // Set updated port timeouts if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) && (readTimeout > 0)) // Read Semi-blocking with timeout @@ -268,8 +272,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou } // Apply changes - fcntl(serialPortFD, F_SETFL, flags); - int retVal = tcsetattr(serialPortFD, TCSANOW, &options); + int retVal = fcntl(serialPortFD, F_SETFL, flags); + if (retVal != -1) + retVal = tcsetattr(serialPortFD, TCSANOW, &options); if (baudRateCode == 0) // Set custom baud rate setBaudRate(serialPortFD, baudRate); return ((retVal == 0) ? JNI_TRUE : JNI_FALSE); @@ -286,24 +291,27 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventF int eventsToMonitor = (*env)->GetIntField(env, obj, eventFlagsField); // Change read timeouts if we are monitoring data received + jboolean retVal; if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0) { struct termios options = { 0 }; tcgetattr(serialPortFD, &options); int flags = fcntl(serialPortFD, F_GETFL); + if (flags == -1) + return JNI_FALSE; flags &= ~O_NONBLOCK; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; - fcntl(serialPortFD, F_SETFL, flags); - tcsetattr(serialPortFD, TCSANOW, &options); + retVal = ((fcntl(serialPortFD, F_SETFL, flags) == -1) || (tcsetattr(serialPortFD, TCSANOW, &options) == -1)) ? + JNI_FALSE : JNI_TRUE; if (baudRateCode == 0) // Set custom baud rate setBaudRate(serialPortFD, baudRate); } else - Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortFD); + retVal = Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortFD); // Apply changes - return JNI_TRUE; + return retVal; } JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortFD) @@ -330,7 +338,11 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat // Close port if (serialPortFD <= 0) return JNI_TRUE; - close(serialPortFD); + + // Allow others to open this port + 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); @@ -366,8 +378,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); if (numBytesRead == -1) { - // Problem reading, close port - close(serialPortFD); + // Problem reading, 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); @@ -397,8 +411,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); if (numBytesRead == -1) { - // Problem reading, close port - close(serialPortFD); + // Problem reading, 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); @@ -420,8 +436,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer, bytesToRead); } while ((numBytesRead < 0) && (errno == EINTR)); if (numBytesRead == -1) { - // Problem reading, close port - close(serialPortFD); + // Problem reading, 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); @@ -447,8 +465,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn do { numBytesWritten = write(serialPortFD, writeBuffer, bytesToWrite); } while ((numBytesWritten < 0) && (errno == EINTR)); if (numBytesWritten == -1) { - // Problem writing, close port - close(serialPortFD); + // 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); diff --git a/src/main/c/OSX/SerialPort_OSX.c b/src/main/c/OSX/SerialPort_OSX.c index 10d5c8b..2bcacb1 100644 --- a/src/main/c/OSX/SerialPort_OSX.c +++ b/src/main/c/OSX/SerialPort_OSX.c @@ -2,7 +2,7 @@ * SerialPort_OSX.c * * Created on: Feb 25, 2012 - * Last Updated on: July 1, 2015 + * Last Updated on: Oct 09, 2015 * Author: Will Hedgecock * * Copyright (C) 2012-2015 Fazecast, Inc. @@ -177,7 +177,9 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative( else { // Close the port if there was a problem setting the parameters - close(serialPortFD); + ioctl(serialPortFD, TIOCNXCL); + tcdrain(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); } @@ -273,6 +275,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou struct termios options; tcgetattr(serialPortFD, &options); int flags = fcntl(serialPortFD, F_GETFL); + if (flags == -1) + return JNI_FALSE; // Set updated port timeouts if (((timeoutMode & com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING) > 0) && (readTimeout > 0)) // Read Semi-blocking with timeout @@ -313,8 +317,8 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeou } // Apply changes - fcntl(serialPortFD, F_SETFL, flags); - return (tcsetattr(serialPortFD, TCSANOW, &options) == 0) ? JNI_TRUE : JNI_FALSE; + int retVal = fcntl(serialPortFD, F_SETFL, flags); + return ((retVal != -1) && (tcsetattr(serialPortFD, TCSANOW, &options) == 0)) ? JNI_TRUE : JNI_FALSE; } JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(JNIEnv *env, jobject obj, jlong serialPortFD) @@ -332,11 +336,13 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventF struct termios options; tcgetattr(serialPortFD, &options); int flags = fcntl(serialPortFD, F_GETFL); + if (flags == -1) + return JNI_FALSE; flags &= ~O_NONBLOCK; options.c_cc[VMIN] = 0; options.c_cc[VTIME] = 10; - fcntl(serialPortFD, F_SETFL, flags); - retVal = (tcsetattr(serialPortFD, TCSANOW, &options) == 0) ? JNI_TRUE : JNI_FALSE; + retVal = ((fcntl(serialPortFD, F_SETFL, flags) != -1) && (tcsetattr(serialPortFD, TCSANOW, &options) != -1)) ? + JNI_TRUE : JNI_FALSE; } else retVal = Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortFD); @@ -368,8 +374,11 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat // Close port if (serialPortFD <= 0) return JNI_TRUE; + + // Allow others to open the port and close it ourselves + ioctl(serialPortFD, TIOCNXCL); tcdrain(serialPortFD); - close(serialPortFD); + while ((close(serialPortFD) == -1) && (errno != EBADF)); serialPortFD = -1; (*env)->SetLongField(env, obj, serialPortFdField, -1l); (*env)->SetBooleanField(env, obj, isOpenedField, JNI_FALSE); @@ -405,8 +414,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); if (numBytesRead == -1) { - // Problem reading, close port - close(serialPortFD); + // Problem reading, 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); @@ -436,8 +447,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer+numBytesReadTotal, bytesRemaining); } while ((numBytesRead < 0) && (errno == EINTR)); if (numBytesRead == -1) { - // Problem reading, close port - close(serialPortFD); + // Problem reading, 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); @@ -459,8 +472,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv do { numBytesRead = read(serialPortFD, readBuffer, bytesToRead); } while ((numBytesRead < 0) && (errno == EINTR)); if (numBytesRead == -1) { - // Problem reading, close port - close(serialPortFD); + // Problem reading, 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); @@ -486,8 +501,10 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn do { numBytesWritten = write(serialPortFD, writeBuffer, bytesToWrite); } while ((numBytesWritten < 0) && (errno == EINTR)); if (numBytesWritten == -1) { - // Problem writing, close port - close(serialPortFD); + // 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); diff --git a/src/main/c/Windows/SerialPort_Windows.c b/src/main/c/Windows/SerialPort_Windows.c index 046cfa7..5e851ea 100644 --- a/src/main/c/Windows/SerialPort_Windows.c +++ b/src/main/c/Windows/SerialPort_Windows.c @@ -263,7 +263,8 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative( else { // Close the port if there was a problem setting the parameters - CloseHandle(serialPortHandle); + PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + while (!CloseHandle(serialPortHandle)); serialPortHandle = INVALID_HANDLE_VALUE; env->SetBooleanField(obj, isOpenedField, JNI_FALSE); } @@ -474,7 +475,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI if (GetLastError() != ERROR_IO_PENDING) // Problem occurred { // Problem reading, close port - CloseHandle(serialPortHandle); + PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + while (!CloseHandle(serialPortHandle)); serialPortHandle = INVALID_HANDLE_VALUE; env->SetLongField(obj, serialPortHandleField, -1l); env->SetBooleanField(obj, isOpenedField, JNI_FALSE); @@ -498,12 +500,12 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNat PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); // Close port - BOOL retVal = CloseHandle(serialPortHandle); + while (!CloseHandle(serialPortHandle)); serialPortHandle = INVALID_HANDLE_VALUE; env->SetLongField(obj, serialPortHandleField, -1l); env->SetBooleanField(obj, isOpenedField, JNI_FALSE); - return (retVal == 0) ? JNI_FALSE : JNI_TRUE; + return JNI_TRUE; } JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(JNIEnv *env, jobject obj, jlong serialPortFD) @@ -542,7 +544,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv if (GetLastError() != ERROR_IO_PENDING) // Problem occurred { // Problem reading, close port - CloseHandle(serialPortHandle); + PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + while (!CloseHandle(serialPortHandle)); serialPortHandle = INVALID_HANDLE_VALUE; env->SetLongField(obj, serialPortHandleField, -1l); env->SetBooleanField(obj, isOpenedField, JNI_FALSE); @@ -550,7 +553,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv else if ((result = GetOverlappedResult(serialPortHandle, &overlappedStruct, &numBytesRead, TRUE)) == FALSE) { // Problem reading, close port - CloseHandle(serialPortHandle); + PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + while (!CloseHandle(serialPortHandle)); serialPortHandle = INVALID_HANDLE_VALUE; env->SetLongField(obj, serialPortHandleField, -1l); env->SetBooleanField(obj, isOpenedField, JNI_FALSE); @@ -586,7 +590,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn if (GetLastError() != ERROR_IO_PENDING) { // Problem writing, close port - CloseHandle(serialPortHandle); + PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + while (!CloseHandle(serialPortHandle)); serialPortHandle = INVALID_HANDLE_VALUE; env->SetLongField(obj, serialPortHandleField, -1l); env->SetBooleanField(obj, isOpenedField, JNI_FALSE); @@ -594,7 +599,8 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEn else if ((result = GetOverlappedResult(serialPortHandle, &overlappedStruct, &numBytesWritten, TRUE)) == FALSE) { // Problem reading, close port - CloseHandle(serialPortHandle); + PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR); + while (!CloseHandle(serialPortHandle)); serialPortHandle = INVALID_HANDLE_VALUE; env->SetLongField(obj, serialPortHandleField, -1l); env->SetBooleanField(obj, isOpenedField, JNI_FALSE); diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java b/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java index f195e44..29d9789 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPortDataListener.java @@ -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 <will.hedgecock@fazecast.com> - * @version 1.3.8 + * @version 1.3.9 * @see java.util.EventListener */ public interface SerialPortDataListener extends EventListener diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java b/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java index 1a48e84..b78c32b 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPortEvent.java @@ -31,7 +31,7 @@ import java.util.EventObject; * This class describes an asynchronous serial port event. * * @author Will Hedgecock <will.hedgecock@fazecast.com> - * @version 1.3.8 + * @version 1.3.9 * @see java.util.EventObject */ public final class SerialPortEvent extends EventObject diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPortPacketListener.java b/src/main/java/com/fazecast/jSerialComm/SerialPortPacketListener.java index 2d34e0f..fa6e8fe 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPortPacketListener.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPortPacketListener.java @@ -31,7 +31,7 @@ package com.fazecast.jSerialComm; * Note: Using this interface will negate any serial port read timeout settings since they make no sense in an asynchronous context. * * @author Will Hedgecock <will.hedgecock@fazecast.com> - * @version 1.3.8 + * @version 1.3.9 * @see com.fazecast.jSerialComm.SerialPortDataListener * @see java.util.EventListener */ diff --git a/src/main/resources/Android/arm64-v8a/libjSerialComm.so b/src/main/resources/Android/arm64-v8a/libjSerialComm.so index 69ca98e..796fdae 100644 Binary files a/src/main/resources/Android/arm64-v8a/libjSerialComm.so and b/src/main/resources/Android/arm64-v8a/libjSerialComm.so differ diff --git a/src/main/resources/Android/armeabi-v7a/libjSerialComm.so b/src/main/resources/Android/armeabi-v7a/libjSerialComm.so index d1fbbfe..76df292 100644 Binary files a/src/main/resources/Android/armeabi-v7a/libjSerialComm.so and b/src/main/resources/Android/armeabi-v7a/libjSerialComm.so differ diff --git a/src/main/resources/Android/armeabi/libjSerialComm.so b/src/main/resources/Android/armeabi/libjSerialComm.so index 2f3ef77..00b5906 100644 Binary files a/src/main/resources/Android/armeabi/libjSerialComm.so and b/src/main/resources/Android/armeabi/libjSerialComm.so differ diff --git a/src/main/resources/Android/mips/libjSerialComm.so b/src/main/resources/Android/mips/libjSerialComm.so index f91e7bd..764c7ff 100644 Binary files a/src/main/resources/Android/mips/libjSerialComm.so and b/src/main/resources/Android/mips/libjSerialComm.so differ diff --git a/src/main/resources/Android/mips64/libjSerialComm.so b/src/main/resources/Android/mips64/libjSerialComm.so index d456d62..a503d4c 100644 Binary files a/src/main/resources/Android/mips64/libjSerialComm.so and b/src/main/resources/Android/mips64/libjSerialComm.so differ diff --git a/src/main/resources/Android/x86/libjSerialComm.so b/src/main/resources/Android/x86/libjSerialComm.so index a5075b8..d218b02 100644 Binary files a/src/main/resources/Android/x86/libjSerialComm.so and b/src/main/resources/Android/x86/libjSerialComm.so differ diff --git a/src/main/resources/Android/x86_64/libjSerialComm.so b/src/main/resources/Android/x86_64/libjSerialComm.so index 289932f..26e27d6 100644 Binary files a/src/main/resources/Android/x86_64/libjSerialComm.so and b/src/main/resources/Android/x86_64/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv5/libjSerialComm.so b/src/main/resources/Linux/armv5/libjSerialComm.so index e2e97ea..d6a4900 100644 Binary files a/src/main/resources/Linux/armv5/libjSerialComm.so and b/src/main/resources/Linux/armv5/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv6-hf/libjSerialComm.so b/src/main/resources/Linux/armv6-hf/libjSerialComm.so index dc42eb8..88e2861 100644 Binary files a/src/main/resources/Linux/armv6-hf/libjSerialComm.so and b/src/main/resources/Linux/armv6-hf/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv6/libjSerialComm.so b/src/main/resources/Linux/armv6/libjSerialComm.so index b1f4c2a..fd7bd06 100644 Binary files a/src/main/resources/Linux/armv6/libjSerialComm.so and b/src/main/resources/Linux/armv6/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv7-hf/libjSerialComm.so b/src/main/resources/Linux/armv7-hf/libjSerialComm.so index 3669a83..cf1163b 100644 Binary files a/src/main/resources/Linux/armv7-hf/libjSerialComm.so and b/src/main/resources/Linux/armv7-hf/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv7/libjSerialComm.so b/src/main/resources/Linux/armv7/libjSerialComm.so index 21d8430..9990bfc 100644 Binary files a/src/main/resources/Linux/armv7/libjSerialComm.so and b/src/main/resources/Linux/armv7/libjSerialComm.so differ diff --git a/src/main/resources/Linux/x86/libjSerialComm.so b/src/main/resources/Linux/x86/libjSerialComm.so index a1d864c..e91fe41 100644 Binary files a/src/main/resources/Linux/x86/libjSerialComm.so and b/src/main/resources/Linux/x86/libjSerialComm.so differ diff --git a/src/main/resources/Linux/x86_64/libjSerialComm.so b/src/main/resources/Linux/x86_64/libjSerialComm.so index fd57cde..c5010c3 100644 Binary files a/src/main/resources/Linux/x86_64/libjSerialComm.so and b/src/main/resources/Linux/x86_64/libjSerialComm.so differ diff --git a/src/test/java/com/fazecast/jSerialComm/SerialPortTest.java b/src/test/java/com/fazecast/jSerialComm/SerialPortTest.java index 54ac6b1..044826b 100644 --- a/src/test/java/com/fazecast/jSerialComm/SerialPortTest.java +++ b/src/test/java/com/fazecast/jSerialComm/SerialPortTest.java @@ -32,7 +32,7 @@ import java.util.Scanner; * This class provides a test case for the jSerialComm library. * * @author Will Hedgecock <will.hedgecock@gmail.com> - * @version 1.3.8 + * @version 1.3.9 * @see java.io.InputStream * @see java.io.OutputStream */