diff --git a/src/main/c/Posix/SerialPort_Posix.c b/src/main/c/Posix/SerialPort_Posix.c index ce004d0..e268875 100644 --- a/src/main/c/Posix/SerialPort_Posix.c +++ b/src/main/c/Posix/SerialPort_Posix.c @@ -2,7 +2,7 @@ * SerialPort_Posix.c * * Created on: Feb 25, 2012 - * Last Updated on: Feb 16, 2022 + * Last Updated on: Feb 18, 2022 * Author: Will Hedgecock * * Copyright (C) 2012-2022 Fazecast, Inc. @@ -45,7 +45,6 @@ // Cached class, method, and field IDs jclass jniErrorClass; -jclass serialCommClass; jmethodID serialCommConstructor; jfieldID serialPortFdField; jfieldID comPortField; @@ -81,6 +80,7 @@ jfieldID eventFlagsField; // Global list of available serial ports char portsEnumerated = 0; +char classInitialized = 0; pthread_mutex_t criticalSection; serialPortVector serialPorts = { NULL, 0, 0 }; @@ -239,6 +239,133 @@ void* eventReadingThread2(void *serialPortPointer) #endif // #if defined(__linux__) +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + // Retrieve the JNI environment and class + JNIEnv *env; + jint jniVersion = JNI_VERSION_1_2; + if ((*jvm)->GetEnv(jvm, (void**)&env, jniVersion)) + return JNI_ERR; + jclass serialCommClass = (*env)->FindClass(env, "com/fazecast/jSerialComm/SerialPort"); + if (!serialCommClass) return JNI_ERR; + jniErrorClass = (*env)->FindClass(env, "java/lang/Exception"); + if (!jniErrorClass) return JNI_ERR; + + // Cache Java fields as global references + serialCommConstructor = (*env)->GetMethodID(env, serialCommClass, "", "()V"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + serialPortFdField = (*env)->GetFieldID(env, serialCommClass, "portHandle", "J"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + comPortField = (*env)->GetFieldID(env, serialCommClass, "comPort", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + friendlyNameField = (*env)->GetFieldID(env, serialCommClass, "friendlyName", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + portDescriptionField = (*env)->GetFieldID(env, serialCommClass, "portDescription", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + portLocationField = (*env)->GetFieldID(env, serialCommClass, "portLocation", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + eventListenerRunningField = (*env)->GetFieldID(env, serialCommClass, "eventListenerRunning", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + autoFlushIOBuffersField = (*env)->GetFieldID(env, serialCommClass, "autoFlushIOBuffers", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + parityField = (*env)->GetFieldID(env, serialCommClass, "parity", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + flowControlField = (*env)->GetFieldID(env, serialCommClass, "flowControl", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + sendDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "sendDeviceQueueSize", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + receiveDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "receiveDeviceQueueSize", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + disableExclusiveLockField = (*env)->GetFieldID(env, serialCommClass, "disableExclusiveLock", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + requestElevatedPermissionsField = (*env)->GetFieldID(env, serialCommClass, "requestElevatedPermissions", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485ModeField = (*env)->GetFieldID(env, serialCommClass, "rs485Mode", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485ActiveHighField = (*env)->GetFieldID(env, serialCommClass, "rs485ActiveHigh", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485EnableTerminationField = (*env)->GetFieldID(env, serialCommClass, "rs485EnableTermination", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485RxDuringTxField = (*env)->GetFieldID(env, serialCommClass, "rs485RxDuringTx", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485DelayBeforeField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayBefore", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485DelayAfterField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayAfter", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + xonStartCharField = (*env)->GetFieldID(env, serialCommClass, "xonStartChar", "B"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + xoffStopCharField = (*env)->GetFieldID(env, serialCommClass, "xoffStopChar", "B"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + timeoutModeField = (*env)->GetFieldID(env, serialCommClass, "timeoutMode", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + readTimeoutField = (*env)->GetFieldID(env, serialCommClass, "readTimeout", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + writeTimeoutField = (*env)->GetFieldID(env, serialCommClass, "writeTimeout", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + eventFlagsField = (*env)->GetFieldID(env, serialCommClass, "eventFlags", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + + // Disable handling of various POSIX signals + sigset_t blockMask; + memset(&blockMask, 0, sizeof(blockMask)); + struct sigaction ignoreAction = { 0 }; + ignoreAction.sa_handler = SIG_IGN; + ignoreAction.sa_mask = blockMask; + sigaction(SIGIO, &ignoreAction, NULL); + sigaction(SIGHUP, &ignoreAction, NULL); + sigaction(SIGCONT, &ignoreAction, NULL); + sigaction(SIGUSR1, &ignoreAction, NULL); + sigaction(SIGUSR2, &ignoreAction, NULL); + sigaction(SIGTTOU, &ignoreAction, NULL); + sigaction(SIGTTIN, &ignoreAction, NULL); + + // Initialize the critical section lock + pthread_mutex_init(&criticalSection, NULL); + classInitialized = 1; + return jniVersion; +} + +JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) +{ + // Ensure that the class has not already been uninitialized + if (!classInitialized) + return; + classInitialized = 0; + + // Retrieve the JNI environment + JNIEnv *env; + jint jniVersion = JNI_VERSION_1_2; + (*jvm)->GetEnv(jvm, (void**)&env, jniVersion); + + // Close all open ports + for (int i = 0; i < serialPorts.length; ++i) + if (serialPorts.ports[i]->handle > 0) + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, jniErrorClass, (jlong)(intptr_t)serialPorts.ports[i]); + + // Delete the critical section lock + pthread_mutex_destroy(&criticalSection); +} + +JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm) +{ + // Call the JNI Unload function + JavaVM *jvm; + (*env)->GetJavaVM(env, &jvm); + JNI_OnUnload(jvm, NULL); +} + JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm) { // Mark this entire function as a critical section @@ -248,12 +375,12 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP enumeratePorts(); // Create a Java-based port listing - jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0); + jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialComm, 0); char stopLooping = checkJniError(env, __LINE__ - 1) ? 1 : 0; for (int i = 0; !stopLooping && (i < serialPorts.length); ++i) { // Create a new SerialComm object containing the enumerated values - jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor); + jobject serialCommObject = (*env)->NewObject(env, serialComm, serialCommConstructor); if (checkJniError(env, __LINE__ - 1)) stopLooping = 1; (*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portDescription)); if (checkJniError(env, __LINE__ - 1)) stopLooping = 1; @@ -274,112 +401,6 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP return arrayObject; } -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, "", "()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; - requestElevatedPermissionsField = (*env)->GetFieldID(env, serialCommClass, "requestElevatedPermissions", "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; - memset(&blockMask, 0, sizeof(blockMask)); - struct sigaction ignoreAction = { 0 }; - ignoreAction.sa_handler = SIG_IGN; - ignoreAction.sa_mask = blockMask; - sigaction(SIGIO, &ignoreAction, NULL); - sigaction(SIGHUP, &ignoreAction, NULL); - sigaction(SIGCONT, &ignoreAction, NULL); - sigaction(SIGUSR1, &ignoreAction, NULL); - sigaction(SIGUSR2, &ignoreAction, NULL); - sigaction(SIGTTOU, &ignoreAction, NULL); - sigaction(SIGTTIN, &ignoreAction, NULL); - - // Initialize the critical section lock - pthread_mutex_init(&criticalSection, NULL); -} - -JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm) -{ - // Close all open ports - for (int i = 0; i < serialPorts.length; ++i) - if (serialPorts.ports[i]->handle > 0) - Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, serialComm, (jlong)(intptr_t)serialPorts.ports[i]); - - // Delete the cached global reference - (*env)->DeleteGlobalRef(env, serialCommClass); - checkJniError(env, __LINE__ - 1); - - // Delete the critical section lock - pthread_mutex_destroy(&criticalSection); -} - JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDetails(JNIEnv *env, jobject obj) { // Retrieve the serial port parameter fields diff --git a/src/main/c/Posix/com_fazecast_jSerialComm_SerialPort.h b/src/main/c/Posix/com_fazecast_jSerialComm_SerialPort.h index 9500c5e..0ca6944 100644 --- a/src/main/c/Posix/com_fazecast_jSerialComm_SerialPort.h +++ b/src/main/c/Posix/com_fazecast_jSerialComm_SerialPort.h @@ -83,14 +83,6 @@ extern "C" { JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts (JNIEnv *, jclass); -/* - * Class: com_fazecast_jSerialComm_SerialPort - * Method: initializeLibrary - * Signature: ()V - */ -JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrary - (JNIEnv *, jclass); - /* * Class: com_fazecast_jSerialComm_SerialPort * Method: uninitializeLibrary diff --git a/src/main/c/Windows/SerialPort_Windows.c b/src/main/c/Windows/SerialPort_Windows.c index b6a7157..56f90e0 100644 --- a/src/main/c/Windows/SerialPort_Windows.c +++ b/src/main/c/Windows/SerialPort_Windows.c @@ -2,7 +2,7 @@ * SerialPort_Windows.c * * Created on: Feb 25, 2012 - * Last Updated on: Feb 17, 2022 + * Last Updated on: Feb 18, 2022 * Author: Will Hedgecock * * Copyright (C) 2012-2022 Fazecast, Inc. @@ -44,7 +44,6 @@ // Cached class, method, and field IDs jclass jniErrorClass; -jclass serialCommClass; jmethodID serialCommConstructor; jfieldID serialPortHandleField; jfieldID comPortField; @@ -80,6 +79,7 @@ typedef int (__stdcall *FT_GetDeviceInfoListFunction)(FT_DEVICE_LIST_INFO_NODE*, // Global list of available serial ports char portsEnumerated = 0; +char classInitialized = 0; CRITICAL_SECTION criticalSection; serialPortVector serialPorts = { NULL, 0, 0 }; @@ -370,6 +370,111 @@ static void enumeratePorts(void) portsEnumerated = 1; } +JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) +{ + // Retrieve the JNI environment and class + JNIEnv *env; + jint jniVersion = JNI_VERSION_1_2; + if ((*jvm)->GetEnv(jvm, (void**)&env, jniVersion)) + return JNI_ERR; + jclass serialCommClass = (*env)->FindClass(env, "com/fazecast/jSerialComm/SerialPort"); + if (!serialCommClass) return JNI_ERR; + jniErrorClass = (*env)->FindClass(env, "java/lang/Exception"); + if (!jniErrorClass) return JNI_ERR; + + // Cache Java fields as global references + serialCommConstructor = (*env)->GetMethodID(env, serialCommClass, "", "()V"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + serialPortHandleField = (*env)->GetFieldID(env, serialCommClass, "portHandle", "J"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + comPortField = (*env)->GetFieldID(env, serialCommClass, "comPort", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + friendlyNameField = (*env)->GetFieldID(env, serialCommClass, "friendlyName", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + portDescriptionField = (*env)->GetFieldID(env, serialCommClass, "portDescription", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + portLocationField = (*env)->GetFieldID(env, serialCommClass, "portLocation", "Ljava/lang/String;"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + eventListenerRunningField = (*env)->GetFieldID(env, serialCommClass, "eventListenerRunning", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + isRtsEnabledField = (*env)->GetFieldID(env, serialCommClass, "isRtsEnabled", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + autoFlushIOBuffersField = (*env)->GetFieldID(env, serialCommClass, "autoFlushIOBuffers", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + baudRateField = (*env)->GetFieldID(env, serialCommClass, "baudRate", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + dataBitsField = (*env)->GetFieldID(env, serialCommClass, "dataBits", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + stopBitsField = (*env)->GetFieldID(env, serialCommClass, "stopBits", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + parityField = (*env)->GetFieldID(env, serialCommClass, "parity", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + flowControlField = (*env)->GetFieldID(env, serialCommClass, "flowControl", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + sendDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "sendDeviceQueueSize", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + receiveDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "receiveDeviceQueueSize", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + requestElevatedPermissionsField = (*env)->GetFieldID(env, serialCommClass, "requestElevatedPermissions", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485ModeField = (*env)->GetFieldID(env, serialCommClass, "rs485Mode", "Z"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485DelayBeforeField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayBefore", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + rs485DelayAfterField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayAfter", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + xonStartCharField = (*env)->GetFieldID(env, serialCommClass, "xonStartChar", "B"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + xoffStopCharField = (*env)->GetFieldID(env, serialCommClass, "xoffStopChar", "B"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + timeoutModeField = (*env)->GetFieldID(env, serialCommClass, "timeoutMode", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + readTimeoutField = (*env)->GetFieldID(env, serialCommClass, "readTimeout", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + writeTimeoutField = (*env)->GetFieldID(env, serialCommClass, "writeTimeout", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + eventFlagsField = (*env)->GetFieldID(env, serialCommClass, "eventFlags", "I"); + if (checkJniError(env, __LINE__ - 1)) return JNI_ERR; + + // Initialize the critical section lock + InitializeCriticalSection(&criticalSection); + classInitialized = 1; + return jniVersion; +} + +JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *jvm, void *reserved) +{ + // Ensure that the class has not already been uninitialized + if (!classInitialized) + return; + classInitialized = 0; + + // Retrieve the JNI environment + JNIEnv *env; + jint jniVersion = JNI_VERSION_1_2; + (*jvm)->GetEnv(jvm, (void**)&env, jniVersion); + + // Close all open ports + for (int i = 0; i < serialPorts.length; ++i) + if (serialPorts.ports[i]->handle != INVALID_HANDLE_VALUE) + Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, jniErrorClass, (jlong)(intptr_t)serialPorts.ports[i]); + + // Delete the critical section lock + DeleteCriticalSection(&criticalSection); +} + +JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm) +{ + // Call the JNI Unload function + JavaVM *jvm; + (*env)->GetJavaVM(env, &jvm); + JNI_OnUnload(jvm, NULL); +} + JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm) { // Mark this entire function as a critical section @@ -379,12 +484,12 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP enumeratePorts(); // Get relevant SerialComm methods and fill in com port array - jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0); + jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialComm, 0); char stopLooping = checkJniError(env, __LINE__ - 1) ? 1 : 0; for (int i = 0; !stopLooping && (i < serialPorts.length); ++i) { // Create new SerialComm object containing the enumerated values - jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor); + jobject serialCommObject = (*env)->NewObject(env, serialComm, serialCommConstructor); if (checkJniError(env, __LINE__ - 1)) stopLooping = 1; (*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portPath, wcslen(serialPorts.ports[i]->portPath))); if (checkJniError(env, __LINE__ - 1)) stopLooping = 1; @@ -405,90 +510,6 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP return arrayObject; } -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, "", "()V"); - if (checkJniError(env, __LINE__ - 1)) return; - - // Cache Java fields as global references - serialPortHandleField = (*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; - requestElevatedPermissionsField = (*env)->GetFieldID(env, serialCommClass, "requestElevatedPermissions", "Z"); - if (checkJniError(env, __LINE__ - 1)) return; - rs485ModeField = (*env)->GetFieldID(env, serialCommClass, "rs485Mode", "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; - - // Initialize the critical section lock - InitializeCriticalSection(&criticalSection); -} - -JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm) -{ - // Close all open ports - for (int i = 0; i < serialPorts.length; ++i) - if (serialPorts.ports[i]->handle != INVALID_HANDLE_VALUE) - Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, serialComm, (jlong)(intptr_t)serialPorts.ports[i]); - - // Delete the cached global reference - (*env)->DeleteGlobalRef(env, serialCommClass); - checkJniError(env, __LINE__ - 1); - - // Delete the critical section lock - DeleteCriticalSection(&criticalSection); -} - JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDetails(JNIEnv *env, jobject obj) { // Retrieve the serial port parameter fields diff --git a/src/main/java/com/fazecast/jSerialComm/SerialPort.java b/src/main/java/com/fazecast/jSerialComm/SerialPort.java index 78a4813..be443b4 100644 --- a/src/main/java/com/fazecast/jSerialComm/SerialPort.java +++ b/src/main/java/com/fazecast/jSerialComm/SerialPort.java @@ -396,16 +396,12 @@ public final class SerialPort else backupFileContents.close(); } - - // Initialize native library - if (libraryLoaded) - initializeLibrary(); } } } catch (Exception e) { e.printStackTrace(); } - // Add a shutdown hook to ensure all ports get closed + // Add a shutdown hook to ensure that all ports get closed Runtime.getRuntime().addShutdownHook(new Thread() { public void run() @@ -765,7 +761,6 @@ public final class SerialPort public final synchronized int getLastErrorCode() { return getLastErrorCode(portHandle); } // Serial Port Setup Methods - private static native void initializeLibrary(); // Initializes the JNI code private static native void uninitializeLibrary(); // Un-initializes the JNI code private final native void retrievePortDetails(); // Retrieves port descriptions, names, and details private final native long openPortNative(); // Opens serial port diff --git a/src/main/resources/Android/arm64-v8a/libjSerialComm.so b/src/main/resources/Android/arm64-v8a/libjSerialComm.so index 7a8ea21..1776737 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 7f831dd..cd85b65 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/x86/libjSerialComm.so b/src/main/resources/Android/x86/libjSerialComm.so index 27c1c91..725c15c 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 0286199..5fa9b31 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/FreeBSD/arm64/libjSerialComm.so b/src/main/resources/FreeBSD/arm64/libjSerialComm.so index 5885a90..e584667 100644 Binary files a/src/main/resources/FreeBSD/arm64/libjSerialComm.so and b/src/main/resources/FreeBSD/arm64/libjSerialComm.so differ diff --git a/src/main/resources/FreeBSD/x86/libjSerialComm.so b/src/main/resources/FreeBSD/x86/libjSerialComm.so index 731bb38..5279748 100644 Binary files a/src/main/resources/FreeBSD/x86/libjSerialComm.so and b/src/main/resources/FreeBSD/x86/libjSerialComm.so differ diff --git a/src/main/resources/FreeBSD/x86_64/libjSerialComm.so b/src/main/resources/FreeBSD/x86_64/libjSerialComm.so index bf864b9..5cb2f0b 100644 Binary files a/src/main/resources/FreeBSD/x86_64/libjSerialComm.so and b/src/main/resources/FreeBSD/x86_64/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv5/libjSerialComm.so b/src/main/resources/Linux/armv5/libjSerialComm.so index 0ce964d..0341b5a 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/libjSerialComm.so b/src/main/resources/Linux/armv6/libjSerialComm.so index 4f9fc3b..78ffab1 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/armv6hf/libjSerialComm.so b/src/main/resources/Linux/armv6hf/libjSerialComm.so index 4065032..4afbec3 100644 Binary files a/src/main/resources/Linux/armv6hf/libjSerialComm.so and b/src/main/resources/Linux/armv6hf/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv7/libjSerialComm.so b/src/main/resources/Linux/armv7/libjSerialComm.so index e982950..a759089 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/armv7hf/libjSerialComm.so b/src/main/resources/Linux/armv7hf/libjSerialComm.so index cb71346..b7375b1 100644 Binary files a/src/main/resources/Linux/armv7hf/libjSerialComm.so and b/src/main/resources/Linux/armv7hf/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv8_32/libjSerialComm.so b/src/main/resources/Linux/armv8_32/libjSerialComm.so index b6ab780..b593f2f 100644 Binary files a/src/main/resources/Linux/armv8_32/libjSerialComm.so and b/src/main/resources/Linux/armv8_32/libjSerialComm.so differ diff --git a/src/main/resources/Linux/armv8_64/libjSerialComm.so b/src/main/resources/Linux/armv8_64/libjSerialComm.so index 8a66c61..7e4a384 100644 Binary files a/src/main/resources/Linux/armv8_64/libjSerialComm.so and b/src/main/resources/Linux/armv8_64/libjSerialComm.so differ diff --git a/src/main/resources/Linux/ppc64le/libjSerialComm.so b/src/main/resources/Linux/ppc64le/libjSerialComm.so index 3ff2717..cba257f 100644 Binary files a/src/main/resources/Linux/ppc64le/libjSerialComm.so and b/src/main/resources/Linux/ppc64le/libjSerialComm.so differ diff --git a/src/main/resources/Linux/x86/libjSerialComm.so b/src/main/resources/Linux/x86/libjSerialComm.so index 60e07fe..1454a0e 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 019b2a5..f46cc04 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/main/resources/OSX/aarch64/libjSerialComm.jnilib b/src/main/resources/OSX/aarch64/libjSerialComm.jnilib index c049db7..310f2b2 100755 Binary files a/src/main/resources/OSX/aarch64/libjSerialComm.jnilib and b/src/main/resources/OSX/aarch64/libjSerialComm.jnilib differ diff --git a/src/main/resources/OSX/x86/libjSerialComm.jnilib b/src/main/resources/OSX/x86/libjSerialComm.jnilib index 394ddf8..0eada16 100644 Binary files a/src/main/resources/OSX/x86/libjSerialComm.jnilib and b/src/main/resources/OSX/x86/libjSerialComm.jnilib differ diff --git a/src/main/resources/OSX/x86_64/libjSerialComm.jnilib b/src/main/resources/OSX/x86_64/libjSerialComm.jnilib index 80ccfd1..6a3d721 100755 Binary files a/src/main/resources/OSX/x86_64/libjSerialComm.jnilib and b/src/main/resources/OSX/x86_64/libjSerialComm.jnilib differ diff --git a/src/main/resources/OpenBSD/amd64/libjSerialComm.so b/src/main/resources/OpenBSD/amd64/libjSerialComm.so index 7243bdc..946864f 100644 Binary files a/src/main/resources/OpenBSD/amd64/libjSerialComm.so and b/src/main/resources/OpenBSD/amd64/libjSerialComm.so differ diff --git a/src/main/resources/OpenBSD/x86/libjSerialComm.so b/src/main/resources/OpenBSD/x86/libjSerialComm.so index 16becdd..6d26c92 100644 Binary files a/src/main/resources/OpenBSD/x86/libjSerialComm.so and b/src/main/resources/OpenBSD/x86/libjSerialComm.so differ diff --git a/src/main/resources/Solaris/sparcv8plus_32/libjSerialComm.so b/src/main/resources/Solaris/sparcv8plus_32/libjSerialComm.so index 16bf348..ee430ef 100644 Binary files a/src/main/resources/Solaris/sparcv8plus_32/libjSerialComm.so and b/src/main/resources/Solaris/sparcv8plus_32/libjSerialComm.so differ diff --git a/src/main/resources/Solaris/sparcv9_64/libjSerialComm.so b/src/main/resources/Solaris/sparcv9_64/libjSerialComm.so index 804eb2c..3895590 100644 Binary files a/src/main/resources/Solaris/sparcv9_64/libjSerialComm.so and b/src/main/resources/Solaris/sparcv9_64/libjSerialComm.so differ diff --git a/src/main/resources/Solaris/x86/libjSerialComm.so b/src/main/resources/Solaris/x86/libjSerialComm.so index 4bbe4d8..a99f349 100644 Binary files a/src/main/resources/Solaris/x86/libjSerialComm.so and b/src/main/resources/Solaris/x86/libjSerialComm.so differ diff --git a/src/main/resources/Solaris/x86_64/libjSerialComm.so b/src/main/resources/Solaris/x86_64/libjSerialComm.so index a5eec0e..35aa4bc 100644 Binary files a/src/main/resources/Solaris/x86_64/libjSerialComm.so and b/src/main/resources/Solaris/x86_64/libjSerialComm.so differ diff --git a/src/main/resources/Windows/aarch64/jSerialComm.dll b/src/main/resources/Windows/aarch64/jSerialComm.dll index 8ce50b9..04ac06c 100644 Binary files a/src/main/resources/Windows/aarch64/jSerialComm.dll and b/src/main/resources/Windows/aarch64/jSerialComm.dll differ diff --git a/src/main/resources/Windows/armv7/jSerialComm.dll b/src/main/resources/Windows/armv7/jSerialComm.dll index 640f312..04a9c5d 100644 Binary files a/src/main/resources/Windows/armv7/jSerialComm.dll and b/src/main/resources/Windows/armv7/jSerialComm.dll differ diff --git a/src/main/resources/Windows/x86/jSerialComm.dll b/src/main/resources/Windows/x86/jSerialComm.dll index c3496c9..8de7873 100644 Binary files a/src/main/resources/Windows/x86/jSerialComm.dll and b/src/main/resources/Windows/x86/jSerialComm.dll differ diff --git a/src/main/resources/Windows/x86_64/jSerialComm.dll b/src/main/resources/Windows/x86_64/jSerialComm.dll index 5cd43fd..17ca152 100644 Binary files a/src/main/resources/Windows/x86_64/jSerialComm.dll and b/src/main/resources/Windows/x86_64/jSerialComm.dll differ