Move all global/class sync to native code
This commit is contained in:
parent
60ed45bb5d
commit
7330e76913
|
@ -2,7 +2,7 @@
|
||||||
* SerialPort_Posix.c
|
* SerialPort_Posix.c
|
||||||
*
|
*
|
||||||
* Created on: Feb 25, 2012
|
* Created on: Feb 25, 2012
|
||||||
* Last Updated on: Feb 14, 2022
|
* Last Updated on: Feb 15, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -79,8 +79,9 @@ jfieldID readTimeoutField;
|
||||||
jfieldID writeTimeoutField;
|
jfieldID writeTimeoutField;
|
||||||
jfieldID eventFlagsField;
|
jfieldID eventFlagsField;
|
||||||
|
|
||||||
// List of available serial ports
|
// Global list of available serial ports
|
||||||
char portsEnumerated = 0;
|
char portsEnumerated = 0;
|
||||||
|
pthread_mutex_t criticalSection;
|
||||||
serialPortVector serialPorts = { NULL, 0, 0 };
|
serialPortVector serialPorts = { NULL, 0, 0 };
|
||||||
|
|
||||||
// JNI exception handler
|
// JNI exception handler
|
||||||
|
@ -240,30 +241,36 @@ void* eventReadingThread2(void *serialPortPointer)
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm)
|
JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm)
|
||||||
{
|
{
|
||||||
|
// Mark this entire function as a critical section
|
||||||
|
pthread_mutex_lock(&criticalSection);
|
||||||
|
|
||||||
// Enumerate all ports on the current system
|
// Enumerate all ports on the current system
|
||||||
enumeratePorts();
|
enumeratePorts();
|
||||||
|
|
||||||
// Create a Java-based port listing
|
// Create a Java-based port listing
|
||||||
jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0);
|
jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
char stopLooping = checkJniError(env, __LINE__ - 1) ? 1 : 0;
|
||||||
for (int i = 0; i < serialPorts.length; ++i)
|
for (int i = 0; !stopLooping && (i < serialPorts.length); ++i)
|
||||||
{
|
{
|
||||||
// Create a new SerialComm object containing the enumerated values
|
// Create a new SerialComm object containing the enumerated values
|
||||||
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portDescription));
|
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portDescription));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewStringUTF(env, serialPorts.ports[i]->friendlyName));
|
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewStringUTF(env, serialPorts.ports[i]->friendlyName));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portPath));
|
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portPath));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
(*env)->SetObjectField(env, serialCommObject, portLocationField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portLocation));
|
(*env)->SetObjectField(env, serialCommObject, portLocationField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portLocation));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
|
|
||||||
// Add new SerialComm object to array
|
// Add new SerialComm object to array
|
||||||
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
|
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exit critical section and return the com port array
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
return arrayObject;
|
return arrayObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,6 +361,9 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
|
||||||
sigaction(SIGUSR2, &ignoreAction, NULL);
|
sigaction(SIGUSR2, &ignoreAction, NULL);
|
||||||
sigaction(SIGTTOU, &ignoreAction, NULL);
|
sigaction(SIGTTOU, &ignoreAction, NULL);
|
||||||
sigaction(SIGTTIN, &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)
|
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm)
|
||||||
|
@ -366,6 +376,9 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibr
|
||||||
// Delete the cached global reference
|
// Delete the cached global reference
|
||||||
(*env)->DeleteGlobalRef(env, serialCommClass);
|
(*env)->DeleteGlobalRef(env, serialCommClass);
|
||||||
checkJniError(env, __LINE__ - 1);
|
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)
|
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDetails(JNIEnv *env, jobject obj)
|
||||||
|
@ -377,25 +390,33 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDeta
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) return;
|
||||||
|
|
||||||
// Ensure that the serial port exists
|
// Ensure that the serial port exists
|
||||||
|
char continueRetrieval = 1;
|
||||||
|
pthread_mutex_lock(&criticalSection);
|
||||||
if (!portsEnumerated)
|
if (!portsEnumerated)
|
||||||
enumeratePorts();
|
enumeratePorts();
|
||||||
serialPort *port = fetchPort(&serialPorts, portName);
|
serialPort *port = fetchPort(&serialPorts, portName);
|
||||||
if (!port)
|
if (!port)
|
||||||
{
|
continueRetrieval = 0;
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
|
||||||
checkJniError(env, __LINE__ - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in the Java-side port details
|
// Fill in the Java-side port details
|
||||||
(*env)->SetObjectField(env, obj, portDescriptionField, (*env)->NewStringUTF(env, port->portDescription));
|
if (continueRetrieval)
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
{
|
||||||
(*env)->SetObjectField(env, obj, friendlyNameField, (*env)->NewStringUTF(env, port->friendlyName));
|
(*env)->SetObjectField(env, obj, portDescriptionField, (*env)->NewStringUTF(env, port->portDescription));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) continueRetrieval = 0;
|
||||||
(*env)->SetObjectField(env, obj, portLocationField, (*env)->NewStringUTF(env, port->portLocation));
|
}
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (continueRetrieval)
|
||||||
|
{
|
||||||
|
(*env)->SetObjectField(env, obj, friendlyNameField, (*env)->NewStringUTF(env, port->friendlyName));
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) continueRetrieval = 0;
|
||||||
|
}
|
||||||
|
if (continueRetrieval)
|
||||||
|
{
|
||||||
|
(*env)->SetObjectField(env, obj, portLocationField, (*env)->NewStringUTF(env, port->portLocation));
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) continueRetrieval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Release all JNI structures
|
// Release all JNI structures
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
||||||
checkJniError(env, __LINE__ - 1);
|
checkJniError(env, __LINE__ - 1);
|
||||||
}
|
}
|
||||||
|
@ -405,8 +426,6 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
// Retrieve the serial port parameter fields
|
// Retrieve the serial port parameter fields
|
||||||
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
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);
|
unsigned char disableExclusiveLock = (*env)->GetBooleanField(env, obj, disableExclusiveLockField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
|
unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
|
||||||
|
@ -415,14 +434,18 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
|
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
|
const char *portName = (*env)->GetStringUTFChars(env, portNameJString, NULL);
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
|
|
||||||
// Ensure that the serial port still exists and is not already open
|
// Ensure that the serial port still exists and is not already open
|
||||||
|
pthread_mutex_lock(&criticalSection);
|
||||||
serialPort *port = fetchPort(&serialPorts, portName);
|
serialPort *port = fetchPort(&serialPorts, portName);
|
||||||
if (!port)
|
if (!port)
|
||||||
{
|
{
|
||||||
// Create port representation and add to serial port listing
|
// Create port representation and add to serial port listing
|
||||||
port = pushBack(&serialPorts, portName, "User-Specified Port", "User-Specified Port", "0-0");
|
port = pushBack(&serialPorts, portName, "User-Specified Port", "User-Specified Port", "0-0");
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
if (!port || (port->handle > 0))
|
if (!port || (port->handle > 0))
|
||||||
{
|
{
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
||||||
|
@ -437,17 +460,21 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
verifyAndSetUserPortGroup(portName);
|
verifyAndSetUserPortGroup(portName);
|
||||||
|
|
||||||
// Try to open the serial port with read/write access
|
// Try to open the serial port with read/write access
|
||||||
|
pthread_mutex_lock(&criticalSection);
|
||||||
port->errorLineNumber = lastErrorLineNumber = __LINE__ + 1;
|
port->errorLineNumber = lastErrorLineNumber = __LINE__ + 1;
|
||||||
if ((port->handle = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC)) > 0)
|
if ((port->handle = open(portName, O_RDWR | O_NOCTTY | O_NONBLOCK | O_CLOEXEC)) > 0)
|
||||||
{
|
{
|
||||||
// Ensure that multiple root users cannot access the device simultaneously
|
// Ensure that multiple root users cannot access the device simultaneously
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
if (!disableExclusiveLock && flock(port->handle, LOCK_EX | LOCK_NB))
|
if (!disableExclusiveLock && flock(port->handle, LOCK_EX | LOCK_NB))
|
||||||
{
|
{
|
||||||
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
|
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 2;
|
||||||
port->errorNumber = lastErrorNumber = errno;
|
port->errorNumber = lastErrorNumber = errno;
|
||||||
while (close(port->handle) && (errno == EINTR))
|
while (close(port->handle) && (errno == EINTR))
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
pthread_mutex_lock(&criticalSection);
|
||||||
port->handle = -1;
|
port->handle = -1;
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
}
|
}
|
||||||
else if (!disableAutoConfig && !Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
|
else if (!disableAutoConfig && !Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
|
||||||
{
|
{
|
||||||
|
@ -455,7 +482,9 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
fcntl(port->handle, F_SETFL, O_NONBLOCK);
|
fcntl(port->handle, F_SETFL, O_NONBLOCK);
|
||||||
while (close(port->handle) && (errno == EINTR))
|
while (close(port->handle) && (errno == EINTR))
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
pthread_mutex_lock(&criticalSection);
|
||||||
port->handle = -1;
|
port->handle = -1;
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
}
|
}
|
||||||
else if (autoFlushIOBuffers)
|
else if (autoFlushIOBuffers)
|
||||||
{
|
{
|
||||||
|
@ -466,7 +495,10 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
port->errorNumber = lastErrorNumber = errno;
|
port->errorNumber = lastErrorNumber = errno;
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
|
}
|
||||||
|
|
||||||
// Return a pointer to the serial port data structure
|
// Return a pointer to the serial port data structure
|
||||||
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
(*env)->ReleaseStringUTFChars(env, portNameJString, portName);
|
||||||
|
@ -808,7 +840,9 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative
|
||||||
flock(port->handle, LOCK_UN | LOCK_NB);
|
flock(port->handle, LOCK_UN | LOCK_NB);
|
||||||
while (close(port->handle) && (errno == EINTR))
|
while (close(port->handle) && (errno == EINTR))
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
pthread_mutex_lock(&criticalSection);
|
||||||
port->handle = -1;
|
port->handle = -1;
|
||||||
|
pthread_mutex_unlock(&criticalSection);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* SerialPort_Windows.c
|
* SerialPort_Windows.c
|
||||||
*
|
*
|
||||||
* Created on: Feb 25, 2012
|
* Created on: Feb 25, 2012
|
||||||
* Last Updated on: Jan 28, 2022
|
* Last Updated on: Feb 15, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -78,8 +78,9 @@ jfieldID eventFlagsField;
|
||||||
typedef int (__stdcall *FT_CreateDeviceInfoListFunction)(LPDWORD);
|
typedef int (__stdcall *FT_CreateDeviceInfoListFunction)(LPDWORD);
|
||||||
typedef int (__stdcall *FT_GetDeviceInfoListFunction)(FT_DEVICE_LIST_INFO_NODE*, LPDWORD);
|
typedef int (__stdcall *FT_GetDeviceInfoListFunction)(FT_DEVICE_LIST_INFO_NODE*, LPDWORD);
|
||||||
|
|
||||||
// List of available serial ports
|
// Global list of available serial ports
|
||||||
char portsEnumerated = 0;
|
char portsEnumerated = 0;
|
||||||
|
CRITICAL_SECTION criticalSection;
|
||||||
serialPortVector serialPorts = { NULL, 0, 0 };
|
serialPortVector serialPorts = { NULL, 0, 0 };
|
||||||
|
|
||||||
// JNI exception handler
|
// JNI exception handler
|
||||||
|
@ -320,31 +321,37 @@ static void enumeratePorts(void)
|
||||||
|
|
||||||
JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm)
|
JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm)
|
||||||
{
|
{
|
||||||
|
// Mark this entire function as a critical section
|
||||||
|
EnterCriticalSection(&criticalSection);
|
||||||
|
|
||||||
// Enumerate all ports on the current system
|
// Enumerate all ports on the current system
|
||||||
enumeratePorts();
|
enumeratePorts();
|
||||||
|
|
||||||
// Get relevant SerialComm methods and fill in com port array
|
// Get relevant SerialComm methods and fill in com port array
|
||||||
wchar_t comPort[128];
|
wchar_t comPort[128];
|
||||||
jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0);
|
jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
char stopLooping = checkJniError(env, __LINE__ - 1) ? 1 : 0;
|
||||||
for (int i = 0; i < serialPorts.length; ++i)
|
for (int i = 0; !stopLooping && (i < serialPorts.length); ++i)
|
||||||
{
|
{
|
||||||
// Create new SerialComm object containing the enumerated values
|
// Create new SerialComm object containing the enumerated values
|
||||||
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
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)));
|
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portPath, wcslen(serialPorts.ports[i]->portPath)));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->friendlyName, wcslen(serialPorts.ports[i]->friendlyName)));
|
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->friendlyName, wcslen(serialPorts.ports[i]->friendlyName)));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portDescription, wcslen(serialPorts.ports[i]->portDescription)));
|
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portDescription, wcslen(serialPorts.ports[i]->portDescription)));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
(*env)->SetObjectField(env, serialCommObject, portLocationField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portLocation, wcslen(serialPorts.ports[i]->portLocation)));
|
(*env)->SetObjectField(env, serialCommObject, portLocationField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portLocation, wcslen(serialPorts.ports[i]->portLocation)));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
|
|
||||||
// Add new SerialComm object to array
|
// Add new SerialComm object to array
|
||||||
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
|
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) stopLooping = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exit critical section and return the com port array
|
||||||
|
LeaveCriticalSection(&criticalSection);
|
||||||
return arrayObject;
|
return arrayObject;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,6 +419,9 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) return;
|
||||||
eventFlagsField = (*env)->GetFieldID(env, serialCommClass, "eventFlags", "I");
|
eventFlagsField = (*env)->GetFieldID(env, serialCommClass, "eventFlags", "I");
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
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)
|
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibrary(JNIEnv *env, jclass serialComm)
|
||||||
|
@ -424,6 +434,9 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibr
|
||||||
// Delete the cached global reference
|
// Delete the cached global reference
|
||||||
(*env)->DeleteGlobalRef(env, serialCommClass);
|
(*env)->DeleteGlobalRef(env, serialCommClass);
|
||||||
checkJniError(env, __LINE__ - 1);
|
checkJniError(env, __LINE__ - 1);
|
||||||
|
|
||||||
|
// Delete the critical section lock
|
||||||
|
DeleteCriticalSection(&criticalSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDetails(JNIEnv *env, jobject obj)
|
JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDetails(JNIEnv *env, jobject obj)
|
||||||
|
@ -435,25 +448,33 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_retrievePortDeta
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) return;
|
||||||
|
|
||||||
// Ensure that the serial port exists
|
// Ensure that the serial port exists
|
||||||
|
char continueRetrieval = 1;
|
||||||
|
EnterCriticalSection(&criticalSection);
|
||||||
if (!portsEnumerated)
|
if (!portsEnumerated)
|
||||||
enumeratePorts();
|
enumeratePorts();
|
||||||
serialPort *port = fetchPort(&serialPorts, portName);
|
serialPort *port = fetchPort(&serialPorts, portName);
|
||||||
if (!port)
|
if (!port)
|
||||||
{
|
continueRetrieval = 0;
|
||||||
(*env)->ReleaseStringChars(env, portNameJString, (const jchar*)portName);
|
|
||||||
checkJniError(env, __LINE__ - 1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill in the Java-side port details
|
// Fill in the Java-side port details
|
||||||
(*env)->SetObjectField(env, obj, friendlyNameField, (*env)->NewString(env, (jchar*)port->friendlyName, wcslen(port->friendlyName)));
|
if (continueRetrieval)
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
{
|
||||||
(*env)->SetObjectField(env, obj, portDescriptionField, (*env)->NewString(env, (jchar*)port->portDescription, wcslen(port->portDescription)));
|
(*env)->SetObjectField(env, obj, friendlyNameField, (*env)->NewString(env, (jchar*)port->friendlyName, wcslen(port->friendlyName)));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) continueRetrieval = 0;
|
||||||
(*env)->SetObjectField(env, obj, portLocationField, (*env)->NewString(env, (jchar*)port->portLocation, wcslen(port->portLocation)));
|
}
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (continueRetrieval)
|
||||||
|
{
|
||||||
|
(*env)->SetObjectField(env, obj, portDescriptionField, (*env)->NewString(env, (jchar*)port->portDescription, wcslen(port->portDescription)));
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) continueRetrieval = 0;
|
||||||
|
}
|
||||||
|
if (continueRetrieval)
|
||||||
|
{
|
||||||
|
(*env)->SetObjectField(env, obj, portLocationField, (*env)->NewString(env, (jchar*)port->portLocation, wcslen(port->portLocation)));
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) continueRetrieval = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Release all JNI structures
|
// Release all JNI structures
|
||||||
|
LeaveCriticalSection(&criticalSection);
|
||||||
(*env)->ReleaseStringChars(env, portNameJString, (const jchar*)portName);
|
(*env)->ReleaseStringChars(env, portNameJString, (const jchar*)portName);
|
||||||
checkJniError(env, __LINE__ - 1);
|
checkJniError(env, __LINE__ - 1);
|
||||||
}
|
}
|
||||||
|
@ -463,22 +484,24 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
// Retrieve the serial port parameter fields
|
// Retrieve the serial port parameter fields
|
||||||
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
jstring portNameJString = (jstring)(*env)->GetObjectField(env, obj, comPortField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL);
|
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
|
||||||
unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
|
unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
|
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
|
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
|
const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL);
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
|
|
||||||
// Ensure that the serial port still exists and is not already open
|
// Ensure that the serial port still exists and is not already open
|
||||||
|
EnterCriticalSection(&criticalSection);
|
||||||
serialPort *port = fetchPort(&serialPorts, portName);
|
serialPort *port = fetchPort(&serialPorts, portName);
|
||||||
if (!port)
|
if (!port)
|
||||||
{
|
{
|
||||||
// Create port representation and add to serial port listing
|
// Create port representation and add to serial port listing
|
||||||
port = pushBack(&serialPorts, portName, L"User-Specified Port", L"User-Specified Port", L"0-0");
|
port = pushBack(&serialPorts, portName, L"User-Specified Port", L"User-Specified Port", L"0-0");
|
||||||
}
|
}
|
||||||
|
LeaveCriticalSection(&criticalSection);
|
||||||
if (!port || (port->handle != INVALID_HANDLE_VALUE))
|
if (!port || (port->handle != INVALID_HANDLE_VALUE))
|
||||||
{
|
{
|
||||||
(*env)->ReleaseStringChars(env, portNameJString, (const jchar*)portName);
|
(*env)->ReleaseStringChars(env, portNameJString, (const jchar*)portName);
|
||||||
|
@ -492,9 +515,12 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
reduceLatencyToMinimum(portName + 4, requestElevatedPermissions);
|
reduceLatencyToMinimum(portName + 4, requestElevatedPermissions);
|
||||||
|
|
||||||
// Try to open the serial port with read/write access
|
// Try to open the serial port with read/write access
|
||||||
|
EnterCriticalSection(&criticalSection);
|
||||||
|
port->errorLineNumber = lastErrorLineNumber = __LINE__ + 1;
|
||||||
if ((port->handle = CreateFileW(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL)) != INVALID_HANDLE_VALUE)
|
if ((port->handle = CreateFileW(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL)) != INVALID_HANDLE_VALUE)
|
||||||
{
|
{
|
||||||
// Configure the port parameters and timeouts
|
// Configure the port parameters and timeouts
|
||||||
|
LeaveCriticalSection(&criticalSection);
|
||||||
if (!disableAutoConfig && !Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
|
if (!disableAutoConfig && !Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)(intptr_t)port))
|
||||||
{
|
{
|
||||||
// Close the port if there was a problem setting the parameters
|
// Close the port if there was a problem setting the parameters
|
||||||
|
@ -502,15 +528,17 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
CancelIoEx(port->handle, NULL);
|
CancelIoEx(port->handle, NULL);
|
||||||
SetCommMask(port->handle, 0);
|
SetCommMask(port->handle, 0);
|
||||||
CloseHandle(port->handle);
|
CloseHandle(port->handle);
|
||||||
|
EnterCriticalSection(&criticalSection);
|
||||||
port->handle = INVALID_HANDLE_VALUE;
|
port->handle = INVALID_HANDLE_VALUE;
|
||||||
|
LeaveCriticalSection(&criticalSection);
|
||||||
}
|
}
|
||||||
else if (autoFlushIOBuffers)
|
else if (autoFlushIOBuffers)
|
||||||
Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(env, obj, (jlong)(intptr_t)port);
|
Java_com_fazecast_jSerialComm_SerialPort_flushRxTxBuffers(env, obj, (jlong)(intptr_t)port);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
port->errorLineNumber = lastErrorLineNumber = __LINE__ - 15;
|
|
||||||
port->errorNumber = lastErrorNumber = GetLastError();
|
port->errorNumber = lastErrorNumber = GetLastError();
|
||||||
|
LeaveCriticalSection(&criticalSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return a pointer to the serial port data structure
|
// Return a pointer to the serial port data structure
|
||||||
|
@ -790,14 +818,15 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative
|
||||||
// Purge any outstanding port operations
|
// Purge any outstanding port operations
|
||||||
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
|
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
|
||||||
CancelIoEx(port->handle, NULL);
|
CancelIoEx(port->handle, NULL);
|
||||||
FlushFileBuffers(port->handle);
|
|
||||||
SetCommMask(port->handle, 0);
|
SetCommMask(port->handle, 0);
|
||||||
|
|
||||||
// Close the port
|
// Close the port
|
||||||
port->eventListenerRunning = 0;
|
port->eventListenerRunning = 0;
|
||||||
port->errorLineNumber = lastErrorLineNumber = __LINE__ + 1;
|
port->errorLineNumber = lastErrorLineNumber = __LINE__ + 1;
|
||||||
port->errorNumber = lastErrorNumber = (!CloseHandle(port->handle) ? GetLastError() : 0);
|
port->errorNumber = lastErrorNumber = (!CloseHandle(port->handle) ? GetLastError() : 0);
|
||||||
|
EnterCriticalSection(&criticalSection);
|
||||||
port->handle = INVALID_HANDLE_VALUE;
|
port->handle = INVALID_HANDLE_VALUE;
|
||||||
|
LeaveCriticalSection(&criticalSection);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* SerialPort.java
|
* SerialPort.java
|
||||||
*
|
*
|
||||||
* Created on: Feb 25, 2012
|
* Created on: Feb 25, 2012
|
||||||
* Last Updated on: Feb 14, 2022
|
* Last Updated on: Feb 15, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -444,10 +444,16 @@ public final class SerialPort
|
||||||
* <p>
|
* <p>
|
||||||
* The serial ports can be accessed by iterating through each of the SerialPort objects in this array.
|
* The serial ports can be accessed by iterating through each of the SerialPort objects in this array.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that the {@link #openPort()} method must be called before any attempts to read from or write to the port.
|
* Note that the array will also include any serial ports that your application currently has open, even if
|
||||||
|
* the devices attached to those ports become disconnected. As such, it is important that you always call
|
||||||
|
* {@link #closePort()} on a SerialPort object if it becomes disconnected, which is detectable by inspecting
|
||||||
|
* the return values from the various read calls or by registering a {@link SerialPortDataListener} for the
|
||||||
|
* {@link SerialPort#LISTENING_EVENT_PORT_DISCONNECTED} event.
|
||||||
|
* <p>
|
||||||
|
* The {@link #openPort()} method must be called before any attempts to read from or write to the port.
|
||||||
* Likewise, {@link #closePort()} should be called when you are finished accessing the port.
|
* Likewise, {@link #closePort()} should be called when you are finished accessing the port.
|
||||||
* <p>
|
* <p>
|
||||||
* Also note that repeated calls to this function will re-enumerate all serial ports and will return a completely
|
* Note that repeated calls to this function will re-enumerate all serial ports and will return a completely
|
||||||
* unique set of array objects. As such, you should store a reference to the serial port object(s) you are
|
* unique set of array objects. As such, you should store a reference to the serial port object(s) you are
|
||||||
* interested in in your own application code.
|
* interested in in your own application code.
|
||||||
* <p>
|
* <p>
|
||||||
|
@ -501,9 +507,7 @@ public final class SerialPort
|
||||||
serialPort.friendlyName = "User-Specified Port";
|
serialPort.friendlyName = "User-Specified Port";
|
||||||
serialPort.portDescription = "User-Specified Port";
|
serialPort.portDescription = "User-Specified Port";
|
||||||
serialPort.portLocation = "0-0";
|
serialPort.portLocation = "0-0";
|
||||||
synchronized (SerialPort.class) {
|
serialPort.retrievePortDetails();
|
||||||
serialPort.retrievePortDetails();
|
|
||||||
}
|
|
||||||
return serialPort;
|
return serialPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -629,13 +633,8 @@ public final class SerialPort
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Natively open the serial port, and synchronize to the class scope since port enumeration methods are class-based,
|
// Natively open the serial port, and start an event-based listener if registered
|
||||||
// and this method may alter or read a global class structure in native code
|
portHandle = openPortNative();
|
||||||
synchronized (SerialPort.class) {
|
|
||||||
portHandle = openPortNative();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start an event-based listener if registered and the port is open
|
|
||||||
if ((portHandle != 0) && (serialEventListener != null))
|
if ((portHandle != 0) && (serialEventListener != null))
|
||||||
serialEventListener.startListening();
|
serialEventListener.startListening();
|
||||||
return (portHandle != 0);
|
return (portHandle != 0);
|
||||||
|
@ -689,14 +688,9 @@ public final class SerialPort
|
||||||
if (serialEventListener != null)
|
if (serialEventListener != null)
|
||||||
serialEventListener.stopListening();
|
serialEventListener.stopListening();
|
||||||
|
|
||||||
// Natively close the port, and synchronize to the class scope since port enumeration methods are class-based,
|
// Natively close the port
|
||||||
// and this method may alter or read a global class structure in native code
|
|
||||||
if (portHandle != 0)
|
if (portHandle != 0)
|
||||||
{
|
portHandle = closePortNative(portHandle);
|
||||||
synchronized (SerialPort.class) {
|
|
||||||
portHandle = closePortNative(portHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return (portHandle == 0);
|
return (portHandle == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,8 +745,8 @@ public final class SerialPort
|
||||||
* Returns the source code line location of the latest error encountered during execution of
|
* Returns the source code line location of the latest error encountered during execution of
|
||||||
* the native code for this port.
|
* the native code for this port.
|
||||||
* <p>
|
* <p>
|
||||||
* This function must be called while the port is still open as soon as an error is encountered,
|
* This function must be called as soon as an error is encountered, or it may return an incorrect source
|
||||||
* or it may return an incorrect source code line location.
|
* code line location.
|
||||||
*
|
*
|
||||||
* @return Source line of latest native code error.
|
* @return Source line of latest native code error.
|
||||||
*/
|
*/
|
||||||
|
@ -761,8 +755,8 @@ public final class SerialPort
|
||||||
/**
|
/**
|
||||||
* Returns the error number returned by the most recent native source code line that failed execution.
|
* Returns the error number returned by the most recent native source code line that failed execution.
|
||||||
* <p>
|
* <p>
|
||||||
* This function must be called while the port is still open as soon as an error is encountered,
|
* This function must be called as soon as an error is encountered, or it may return an incorrect or
|
||||||
* or it may return an incorrect or invalid error code.
|
* invalid error code.
|
||||||
*
|
*
|
||||||
* @return Error number of the latest native code error.
|
* @return Error number of the latest native code error.
|
||||||
*/
|
*/
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue