Complete rework of Windows native code

This commit is contained in:
Will Hedgecock 2021-11-17 01:20:30 -06:00
parent 20ea873390
commit 3ee680b155
5 changed files with 372 additions and 315 deletions

View File

@ -2,7 +2,7 @@
* SerialPort_Windows.c
*
* Created on: Feb 25, 2012
* Last Updated on: Nov 03, 2021
* Last Updated on: Nov 12, 2021
* Author: Will Hedgecock
*
* Copyright (C) 2012-2021 Fazecast, Inc.
@ -36,7 +36,6 @@
#include <setupapi.h>
#include <devpkey.h>
#include "ftdi/ftd2xx.h"
#include "../com_fazecast_jSerialComm_SerialPort.h"
#include "WindowsHelperFunctions.h"
// Cached class, method, and field IDs
@ -65,7 +64,7 @@ jfieldID readTimeoutField;
jfieldID writeTimeoutField;
jfieldID eventFlagsField;
// Run-time loadable DLL function
// Runtime-loadable DLL functions
typedef int (__stdcall *FT_CreateDeviceInfoListFunction)(LPDWORD);
typedef int (__stdcall *FT_GetDeviceInfoListFunction)(FT_DEVICE_LIST_INFO_NODE*, LPDWORD);
typedef int (__stdcall *FT_GetComPortNumberFunction)(FT_HANDLE, LPLONG);
@ -73,6 +72,9 @@ typedef int (__stdcall *FT_SetLatencyTimerFunction)(FT_HANDLE, UCHAR);
typedef int (__stdcall *FT_OpenFunction)(int, FT_HANDLE*);
typedef int (__stdcall *FT_CloseFunction)(FT_HANDLE);
// List of available serial ports
serialPortVector serialPorts = { NULL, 0 };
JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm)
{
HKEY keyHandle1, keyHandle2, keyHandle3, keyHandle4, keyHandle5;
@ -82,7 +84,6 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
DWORD subKeyLength1, subKeyLength2, subKeyLength3, friendlyNameLength;
// Enumerate serial ports on machine
charTupleVector serialCommPorts = { (wchar_t**)malloc(sizeof(wchar_t*)), (wchar_t**)malloc(sizeof(wchar_t*)), (wchar_t**)malloc(sizeof(wchar_t*)), 0 };
if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\SERIALCOMM", 0, KEY_QUERY_VALUE, &keyHandle1) == ERROR_SUCCESS) &&
(RegQueryInfoKeyW(keyHandle1, NULL, NULL, NULL, NULL, NULL, NULL, &numValues, &maxValueLength, &maxComPortLength, NULL, NULL) == ERROR_SUCCESS))
{
@ -106,8 +107,12 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
wchar_t* comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
wchar_t* descriptionString = wcsrchr(valueName, L'\\') ? (wcsrchr(valueName, L'\\') + 1) : valueName;
// Add new SerialComm object to vector
pushBack(&serialCommPorts, comPortString, descriptionString, descriptionString);
// Check if port is already enumerated
serialPort *port = fetchPort(&serialPorts, comPortString);
if (port)
port->enumerated = 1;
else
pushBack(&serialPorts, comPortString, descriptionString, descriptionString);
}
}
@ -177,13 +182,15 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
wchar_t* descriptionString = friendlyName;
// Update friendly name if COM port is actually connected and present in the port list
int i;
for (i = 0; i < serialCommPorts.length; ++i)
if (wcscmp(serialCommPorts.first[i], comPortString) == 0)
for (int i = 0; i < serialPorts.length; ++i)
if (wcscmp(serialPorts.ports[i]->portPath, comPortString) == 0)
{
free(serialCommPorts.second[i]);
serialCommPorts.second[i] = (wchar_t*)malloc((wcslen(descriptionString)+1)*sizeof(wchar_t));
wcscpy(serialCommPorts.second[i], descriptionString);
wchar_t *newMemory = (wchar_t*)realloc(serialPorts.ports[i]->friendlyName, (wcslen(descriptionString)+1)*sizeof(wchar_t));
if (newMemory)
{
serialPorts.ports[i]->friendlyName = newMemory;
wcscpy(serialPorts.ports[i]->friendlyName, descriptionString);
}
break;
}
}
@ -250,14 +257,15 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
if (SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, (BYTE*)portDescription, valueLength, NULL, 0))
{
// Update port description if COM port is actually connected and present in the port list
int i;
for (i = 0; i < serialCommPorts.length; ++i)
if (wcscmp(serialCommPorts.first[i], comPortString) == 0)
for (int i = 0; i < serialPorts.length; ++i)
if (wcscmp(serialPorts.ports[i]->portPath, comPortString) == 0)
{
free(serialCommPorts.third[i]);
serialCommPorts.third[i] = (wchar_t*)malloc((wcslen(portDescription)+1)*sizeof(wchar_t));
wcscpy(serialCommPorts.third[i], portDescription);
break;
wchar_t *newMemory = (wchar_t*)realloc(serialPorts.ports[i]->portDescription, (wcslen(portDescription)+1)*sizeof(wchar_t));
if (newMemory)
{
serialPorts.ports[i]->portDescription = newMemory;
wcscpy(serialPorts.ports[i]->portDescription, portDescription);
}
}
}
@ -287,9 +295,8 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
FT_DEVICE_LIST_INFO_NODE *devInfo = (FT_DEVICE_LIST_INFO_NODE*)malloc(sizeof(FT_DEVICE_LIST_INFO_NODE)*numDevs);
if (FT_GetDeviceInfoList(devInfo, &numDevs) == FT_OK)
{
int i, j;
wchar_t comPortString[128];
for (i = 0; i < numDevs; ++i)
for (int i = 0; i < numDevs; ++i)
{
LONG comPortNumber = 0;
if ((FT_Open(i, &devInfo[i].ftHandle) == FT_OK) && (FT_GetComPortNumber(devInfo[i].ftHandle, &comPortNumber) == FT_OK))
@ -302,13 +309,16 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
// Update port description if COM port is actually connected and present in the port list
FT_Close(devInfo[i].ftHandle);
swprintf(comPortString, sizeof(comPortString) / sizeof(wchar_t), L"COM%ld", comPortNumber);
for (j = 0; j < serialCommPorts.length; ++j)
if (wcscmp(serialCommPorts.first[j], comPortString) == 0)
for (int j = 0; j < serialPorts.length; ++j)
if (wcscmp(serialPorts.ports[j]->portPath, comPortString) == 0)
{
size_t descLength = 8+strlen(devInfo[i].Description);
free(serialCommPorts.third[j]);
serialCommPorts.third[j] = (wchar_t*)malloc(descLength*sizeof(wchar_t));
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, devInfo[i].Description, -1, serialCommPorts.third[j], descLength);
wchar_t *newMemory = (wchar_t*)realloc(serialPorts.ports[j]->portDescription, descLength*sizeof(wchar_t));
if (newMemory)
{
serialPorts.ports[j]->portDescription = newMemory;
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, devInfo[i].Description, -1, serialPorts.ports[j]->portDescription, descLength);
}
break;
}
}
@ -321,28 +331,21 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
}
// Get relevant SerialComm methods and fill in com port array
jobjectArray arrayObject = env->NewObjectArray(serialCommPorts.length, serialCommClass, 0);
wchar_t systemPortName[128];
int i;
for (i = 0; i < serialCommPorts.length; ++i)
jobjectArray arrayObject = env->NewObjectArray(serialPorts.length, serialCommClass, 0);
for (int i = 0; i < serialPorts.length; ++i)
{
// Create new SerialComm object containing the enumerated values
jobject serialCommObject = env->NewObject(serialCommClass, serialCommConstructor);
wcscpy(systemPortName, L"\\\\.\\");
wcscat(systemPortName, serialCommPorts.first[i]);
wcscat(systemPortName, serialPorts.ports[i]->portPath);
env->SetObjectField(serialCommObject, comPortField, env->NewString((jchar*)systemPortName, wcslen(systemPortName)));
env->SetObjectField(serialCommObject, friendlyNameField, env->NewString((jchar*)serialCommPorts.second[i], wcslen(serialCommPorts.second[i])));
env->SetObjectField(serialCommObject, portDescriptionField, env->NewString((jchar*)serialCommPorts.third[i], wcslen(serialCommPorts.third[i])));
free(serialCommPorts.first[i]);
free(serialCommPorts.second[i]);
free(serialCommPorts.third[i]);
env->SetObjectField(serialCommObject, friendlyNameField, env->NewString((jchar*)serialPorts.ports[i]->friendlyName, wcslen(serialPorts.ports[i]->friendlyName)));
env->SetObjectField(serialCommObject, portDescriptionField, env->NewString((jchar*)serialPorts.ports[i]->portDescription, wcslen(serialPorts.ports[i]->portDescription)));
// Add new SerialComm object to array
env->SetObjectArrayElement(arrayObject, i, serialCommObject);
}
free(serialCommPorts.first);
free(serialCommPorts.second);
free(serialCommPorts.third);
return arrayObject;
}
@ -385,48 +388,63 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_uninitializeLibr
JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(JNIEnv *env, jobject obj)
{
// Retrieve the serial port parameter fields
jstring portNameJString = (jstring)env->GetObjectField(obj, comPortField);
const char *portName = env->GetStringUTFChars(portNameJString, NULL);
const wchar_t *portName = (wchar_t*)env->GetStringChars(portNameJString, NULL);
unsigned char disableAutoConfig = env->GetBooleanField(obj, disableConfigField);
// Try to open existing serial port with read/write access
HANDLE serialPortHandle = INVALID_HANDLE_VALUE;
if ((serialPortHandle = CreateFile(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL)) != INVALID_HANDLE_VALUE)
// Ensure that the serial port still exists and is not already open
serialPort *port = fetchPort(&serialPorts, portName);
if (!port)
{
// Configure the port parameters and timeouts
if (Java_com_fazecast_jSerialComm_SerialPort_configPort(env, obj, (jlong)serialPortHandle))
env->SetLongField(obj, serialPortHandleField, (jlong)serialPortHandle);
else
{
// Close the port if there was a problem setting the parameters
int numRetries = 10;
PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
while (!CloseHandle(serialPortHandle) && (numRetries-- > 0));
serialPortHandle = INVALID_HANDLE_VALUE;
env->SetLongField(obj, serialPortHandleField, -1l);
}
// Create port representation and add to serial port listing
port = pushBack(&serialPorts, portName, L"User-Specified Port", L"User-Specified Port");
}
if (!port || (port->handle != INVALID_HANDLE_VALUE))
{
env->ReleaseStringChars(portNameJString, (const jchar*)portName);
return 0;
}
env->ReleaseStringUTFChars(portNameJString, portName);
return (jlong)serialPortHandle;
// Try to open the serial port with read/write access
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
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
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
CancelIoEx(port->handle, NULL);
CloseHandle(port->handle);
port->handle = INVALID_HANDLE_VALUE;
}
}
else
{
port->errorLineNumber = __LINE__ - 14;
port->errorNumber = GetLastError();
}
// Return a pointer to the serial port data structure
env->ReleaseStringChars(portNameJString, (const jchar*)portName);
return (port->handle != INVALID_HANDLE_VALUE) ? (jlong)(intptr_t)port : 0;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
DCB dcbSerialParams{};
dcbSerialParams.DCBlength = sizeof(DCB);
// Get port parameters from Java class
// Retrieve port parameters from the Java class
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
DWORD baudRate = (DWORD)env->GetIntField(obj, baudRateField);
BYTE byteSize = (BYTE)env->GetIntField(obj, dataBitsField);
int stopBitsInt = env->GetIntField(obj, stopBitsField);
int parityInt = env->GetIntField(obj, parityField);
int flowControl = env->GetIntField(obj, flowControlField);
int timeoutMode = env->GetIntField(obj, timeoutModeField);
int readTimeout = env->GetIntField(obj, readTimeoutField);
int writeTimeout = env->GetIntField(obj, writeTimeoutField);
int eventsToMonitor = env->GetIntField(obj, eventFlagsField);
DWORD sendDeviceQueueSize = (DWORD)env->GetIntField(obj, sendDeviceQueueSizeField);
DWORD receiveDeviceQueueSize = (DWORD)env->GetIntField(obj, receiveDeviceQueueSizeField);
BYTE configDisabled = (BYTE)env->GetBooleanField(obj, disableConfigField);
BYTE rs485ModeEnabled = (BYTE)env->GetBooleanField(obj, rs485ModeField);
BYTE isDtrEnabled = env->GetBooleanField(obj, isDtrEnabledField);
BYTE isRtsEnabled = env->GetBooleanField(obj, isRtsEnabledField);
@ -444,7 +462,9 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
BOOL XonXoffOutEnabled = ((flowControl & com_fazecast_jSerialComm_SerialPort_FLOW_CONTROL_XONXOFF_OUT_ENABLED) > 0);
// Retrieve existing port configuration
if (!configDisabled && (!SetupComm(serialPortHandle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(serialPortHandle, &dcbSerialParams)))
DCB dcbSerialParams{};
dcbSerialParams.DCBlength = sizeof(DCB);
if ((!SetupComm(port->handle, receiveDeviceQueueSize, sendDeviceQueueSize) || !GetCommState(port->handle, &dcbSerialParams)))
return JNI_FALSE;
// Set updated port parameters
@ -471,101 +491,79 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configPort(J
dcbSerialParams.XoffChar = (char)19;
// Apply changes
return (configDisabled ? Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(env, obj, serialPortFD) :
(SetCommState(serialPortHandle, &dcbSerialParams) && Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(env, obj, serialPortFD)));
return (SetCommState(port->handle, &dcbSerialParams) && Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortPointer, timeoutMode, readTimeout, writeTimeout, eventsToMonitor));
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(JNIEnv *env, jobject obj, jlong serialPortPointer, jint timeoutMode, jint readTimeout, jint writeTimeout, jint eventsToMonitor)
{
// Get port timeouts from Java class
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
COMMTIMEOUTS timeouts{};
int timeoutMode = env->GetIntField(obj, timeoutModeField);
DWORD readTimeout = (DWORD)env->GetIntField(obj, readTimeoutField);
DWORD writeTimeout = (DWORD)env->GetIntField(obj, writeTimeoutField);
// Set updated port timeouts
timeouts.WriteTotalTimeoutMultiplier = 0;
switch (timeoutMode)
{
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING: // Read Semi-blocking
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Semi-blocking/Write Blocking
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = readTimeout ? readTimeout : 0x0FFFFFFF;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING: // Read Blocking
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read/Write Blocking
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = readTimeout;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER: // Scanner Mode
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING: // Read Non-blocking
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Non-blocking/Write Blocking
default:
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
}
// Apply changes
return SetCommTimeouts(serialPortHandle, &timeouts);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(JNIEnv *env, jobject obj, jlong serialPortFD)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
// Get event flags from Java class
int eventsToMonitor = env->GetIntField(obj, eventFlagsField);
int eventFlags = EV_ERR;
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_AVAILABLE) > 0) ||
((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0))
eventFlags |= EV_RXCHAR;
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN) > 0)
eventFlags |= EV_TXEMPTY;
// Change read timeouts if we are monitoring data received
// Set updated port timeouts
COMMTIMEOUTS timeouts{};
timeouts.WriteTotalTimeoutMultiplier = 0;
if ((eventsToMonitor & com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_RECEIVED) > 0)
{
COMMTIMEOUTS timeouts{};
// Force specific read timeouts if we are monitoring data received
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 1000;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(serialPortHandle, &timeouts);
}
else
Java_com_fazecast_jSerialComm_SerialPort_configTimeouts(env, obj, serialPortFD);
{
switch (timeoutMode)
{
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING: // Read Semi-blocking
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_SEMI_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Semi-blocking/Write Blocking
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = readTimeout ? readTimeout : 0x0FFFFFFF;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING: // Read Blocking
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_READ_BLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read/Write Blocking
timeouts.ReadIntervalTimeout = 0;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = readTimeout;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_SCANNER: // Scanner Mode
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = MAXDWORD;
timeouts.ReadTotalTimeoutConstant = 0x0FFFFFFF;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
case com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING: // Read Non-blocking
case (com_fazecast_jSerialComm_SerialPort_TIMEOUT_NONBLOCKING | com_fazecast_jSerialComm_SerialPort_TIMEOUT_WRITE_BLOCKING): // Read Non-blocking/Write Blocking
default:
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutConstant = writeTimeout;
break;
}
}
// Apply changes
return SetCommMask(serialPortHandle, eventFlags);
return (SetCommTimeouts(port->handle, &timeouts) && SetCommMask(port->handle, eventFlags));
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return 0;
OVERLAPPED overlappedStruct{};
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedStruct.hEvent == NULL)
{
port->errorNumber = GetLastError();
port->errorLineNumber = __LINE__ - 4;
CloseHandle(overlappedStruct.hEvent);
return 0;
}
@ -573,12 +571,12 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI
// Wait for a serial port event
BOOL listenerRunning = TRUE;
DWORD eventMask = 0, numBytesRead = 0, errorsMask, readResult = WAIT_FAILED;
if (WaitCommEvent(serialPortHandle, &eventMask, &overlappedStruct) == FALSE)
if (WaitCommEvent(port->handle, &eventMask, &overlappedStruct) == FALSE)
{
if (GetLastError() != ERROR_IO_PENDING) // Problem occurred
{
// Problem reading, close port
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
port->errorLineNumber = __LINE__ - 4;
port->errorNumber = GetLastError();
listenerRunning = FALSE;
}
else
@ -590,11 +588,14 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI
readResult = WaitForSingleObject(overlappedStruct.hEvent, 500);
else
{
CancelIo(serialPortHandle);
// Purge any outstanding port operations
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
CancelIoEx(port->handle, NULL);
FlushFileBuffers(port->handle);
readResult = WaitForSingleObject(overlappedStruct.hEvent, INFINITE);
}
} while ((readResult == WAIT_TIMEOUT) && listenerRunning);
if ((readResult != WAIT_OBJECT_0) || (GetOverlappedResult(serialPortHandle, &overlappedStruct, &numBytesRead, FALSE) == FALSE))
if ((readResult != WAIT_OBJECT_0) || (GetOverlappedResult(port->handle, &overlappedStruct, &numBytesRead, FALSE) == FALSE))
numBytesRead = 0;
}
}
@ -603,9 +604,7 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI
if (listenerRunning)
{
COMSTAT commInfo;
if (!ClearCommError(serialPortHandle, &errorsMask, &commInfo))
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
else
if (ClearCommError(port->handle, &errorsMask, &commInfo))
numBytesRead = commInfo.cbInQue;
}
@ -615,88 +614,80 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_waitForEvent(JNI
(((eventMask & EV_TXEMPTY) > 0) ? com_fazecast_jSerialComm_SerialPort_LISTENING_EVENT_DATA_WRITTEN : 0);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_closePortNative(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
// Purge any outstanding port operations
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_TRUE;
PurgeComm(serialPortHandle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
// Force the port to enter non-blocking mode to ensure that any current reads return
COMMTIMEOUTS timeouts{};
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
timeouts.WriteTotalTimeoutMultiplier = 0;
timeouts.ReadIntervalTimeout = MAXDWORD;
timeouts.ReadTotalTimeoutMultiplier = 0;
timeouts.ReadTotalTimeoutConstant = 0;
timeouts.WriteTotalTimeoutConstant = 0;
SetCommTimeouts(serialPortHandle, &timeouts);
SetCommTimeouts(port->handle, &timeouts);
// Purge any outstanding port operations
PurgeComm(port->handle, PURGE_RXABORT | PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR);
CancelIoEx(port->handle, NULL);
FlushFileBuffers(port->handle);
// Close the port
int numRetries = 10;
while (!CloseHandle(serialPortHandle) && (GetLastError() != ERROR_INVALID_HANDLE) && (numRetries-- > 0));
if (numRetries > 0)
if (!CloseHandle(port->handle))
{
env->SetLongField(obj, serialPortHandleField, -1l);
return JNI_TRUE;
port->handle = INVALID_HANDLE_VALUE;
port->errorLineNumber = __LINE__ - 3;
port->errorNumber = GetLastError();
return 0;
}
// Error closing port, reconfigure port settings
Java_com_fazecast_jSerialComm_SerialPort_configEventFlags(env, obj, serialPortFD);
return JNI_FALSE;
port->handle = INVALID_HANDLE_VALUE;
return -1;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAvailable(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return -1;
// Retrieve bytes available to read
COMSTAT commInfo;
DWORD errorsMask;
if (!ClearCommError(serialPortHandle, &errorsMask, &commInfo))
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (ClearCommError(port->handle, NULL, &commInfo))
return commInfo.cbInQue;
else
{
// Problem detected, close port
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
serialPortHandle = INVALID_HANDLE_VALUE;
port->errorLineNumber = __LINE__ - 4;
port->errorNumber = GetLastError();
}
return (serialPortHandle == INVALID_HANDLE_VALUE) ? -1 : commInfo.cbInQue;
return -1;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAwaitingWrite(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_bytesAwaitingWrite(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return -1;
// Retrieve bytes awaiting write
COMSTAT commInfo;
DWORD errorsMask;
if (!ClearCommError(serialPortHandle, &errorsMask, &commInfo))
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (ClearCommError(port->handle, NULL, &commInfo))
return commInfo.cbOutQue;
else
{
// Problem detected, close port
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
serialPortHandle = INVALID_HANDLE_VALUE;
port->errorLineNumber = __LINE__ - 4;
port->errorNumber = GetLastError();
}
return (serialPortHandle == INVALID_HANDLE_VALUE) ? -1 : commInfo.cbOutQue;
return -1;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv *env, jobject obj, jlong serialPortFD, jbyteArray buffer, jlong bytesToRead, jlong offset)
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv *env, jobject obj, jlong serialPortPointer, jbyteArray buffer, jlong bytesToRead, jlong offset, jint timeoutMode, jint readTimeout)
{
// Retrieve the serial port handle
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return -1;
// Check for a disconnected serial port
COMSTAT commInfo;
DWORD errorsMask;
if (!ClearCommError(serialPortHandle, &errorsMask, &commInfo))
// Ensure that the allocated read buffer is large enough
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (bytesToRead > port->readBufferLength)
{
// Problem detected, close port
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
return -1;
port->errorLineNumber = __LINE__ + 1;
char *newMemory = (char*)realloc(port->readBuffer, bytesToRead);
if (!newMemory)
{
port->errorNumber = errno;
return -1;
}
port->readBuffer = newMemory;
port->readBufferLength = bytesToRead;
}
// Create an asynchronous result structure
@ -704,97 +695,113 @@ JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_readBytes(JNIEnv
overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedStruct.hEvent == NULL)
{
port->errorNumber = GetLastError();
port->errorLineNumber = __LINE__ - 4;
CloseHandle(overlappedStruct.hEvent);
return -1;
}
char *readBuffer = (char*)malloc(bytesToRead);
DWORD numBytesRead = 0;
// Read from serial port and close upon error
// Read from the serial port
BOOL result;
if (((result = ReadFile(serialPortHandle, readBuffer, bytesToRead, NULL, &overlappedStruct)) == FALSE) && (GetLastError() != ERROR_IO_PENDING))
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
else if ((result = GetOverlappedResult(serialPortHandle, &overlappedStruct, &numBytesRead, TRUE)) == FALSE)
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
DWORD numBytesRead = 0;
if (((result = ReadFile(port->handle, port->readBuffer, bytesToRead, NULL, &overlappedStruct)) == FALSE) && (GetLastError() != ERROR_IO_PENDING))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
}
else if ((result = GetOverlappedResult(port->handle, &overlappedStruct, &numBytesRead, TRUE)) == FALSE)
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
}
// Return number of bytes read if successful
// Return number of bytes read
CloseHandle(overlappedStruct.hEvent);
env->SetByteArrayRegion(buffer, offset, numBytesRead, (jbyte*)readBuffer);
free(readBuffer);
env->SetByteArrayRegion(buffer, offset, numBytesRead, (jbyte*)port->readBuffer);
return (result == TRUE) ? numBytesRead : -1;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEnv *env, jobject obj, jlong serialPortFD, jbyteArray buffer, jlong bytesToWrite, jlong offset)
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_writeBytes(JNIEnv *env, jobject obj, jlong serialPortPointer, jbyteArray buffer, jlong bytesToWrite, jlong offset, jint timeoutMode)
{
// Retrieve the serial port handle
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return -1;
// Check for a disconnected serial port
COMSTAT commInfo;
DWORD errorsMask;
if (!ClearCommError(serialPortHandle, &errorsMask, &commInfo))
{
// Problem detected, close port
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
return -1;
}
// Create an asynchronous result structure
OVERLAPPED overlappedStruct{};
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
overlappedStruct.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (overlappedStruct.hEvent == NULL)
{
port->errorNumber = GetLastError();
port->errorLineNumber = __LINE__ - 4;
CloseHandle(overlappedStruct.hEvent);
return -1;
}
jbyte *writeBuffer = env->GetByteArrayElements(buffer, 0);
DWORD numBytesWritten = 0;
// Write to the serial port
BOOL result;
DWORD numBytesWritten = 0;
jbyte *writeBuffer = env->GetByteArrayElements(buffer, 0);
if (((result = WriteFile(port->handle, writeBuffer+offset, bytesToWrite, NULL, &overlappedStruct)) == FALSE) && (GetLastError() != ERROR_IO_PENDING))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
}
else if ((result = GetOverlappedResult(port->handle, &overlappedStruct, &numBytesWritten, TRUE)) == FALSE)
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
}
// Write to serial port and close upon error
if (((result = WriteFile(serialPortHandle, writeBuffer+offset, bytesToWrite, NULL, &overlappedStruct)) == FALSE) && (GetLastError() != ERROR_IO_PENDING))
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
else if ((result = GetOverlappedResult(serialPortHandle, &overlappedStruct, &numBytesWritten, TRUE)) == FALSE)
Java_com_fazecast_jSerialComm_SerialPort_closePortNative(env, obj, serialPortFD);
// Return number of bytes written if successful
// Return number of bytes written
CloseHandle(overlappedStruct.hEvent);
env->ReleaseByteArrayElements(buffer, writeBuffer, JNI_ABORT);
return (result == TRUE) ? numBytesWritten : -1;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setBreak(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setBreak(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (!SetCommBreak(port->handle))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
return SetCommBreak(serialPortHandle);
}
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearBreak(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearBreak(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (!ClearCommBreak(port->handle))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
return ClearCommBreak(serialPortHandle);
}
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setRTS(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setRTS(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (!EscapeCommFunction(port->handle, SETRTS))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
return EscapeCommFunction(serialPortHandle, SETRTS);
}
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearRTS(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearRTS(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (!EscapeCommFunction(port->handle, CLRRTS))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
return EscapeCommFunction(serialPortHandle, CLRRTS);
}
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetRTS(JNIEnv *env, jobject obj)
@ -855,20 +862,28 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearRTS(
return (result != 0);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setDTR(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_setDTR(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (!EscapeCommFunction(port->handle, SETDTR))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
return EscapeCommFunction(serialPortHandle, SETDTR);
}
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearDTR(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_clearDTR(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
serialPort *port = (serialPort*)(intptr_t)serialPortPointer;
if (!EscapeCommFunction(port->handle, CLRDTR))
{
port->errorLineNumber = __LINE__ - 2;
port->errorNumber = GetLastError();
return JNI_FALSE;
return EscapeCommFunction(serialPortHandle, CLRDTR);
}
return JNI_TRUE;
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_presetDTR(JNIEnv *env, jobject obj)
@ -929,56 +944,48 @@ JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_preclearDTR(
return (result != 0);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCTS(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCTS(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
DWORD modemStatus = 0;
return GetCommModemStatus(serialPortHandle, &modemStatus) && (modemStatus & MS_CTS_ON);
return GetCommModemStatus(((serialPort*)(intptr_t)serialPortPointer)->handle, &modemStatus) && (modemStatus & MS_CTS_ON);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDSR(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDSR(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
DWORD modemStatus = 0;
return GetCommModemStatus(serialPortHandle, &modemStatus) && (modemStatus & MS_DSR_ON);
return GetCommModemStatus(((serialPort*)(intptr_t)serialPortPointer)->handle, &modemStatus) && (modemStatus & MS_DSR_ON);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDCD(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDCD(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
DWORD modemStatus = 0;
return GetCommModemStatus(serialPortHandle, &modemStatus) && (modemStatus & MS_RLSD_ON);
return GetCommModemStatus(((serialPort*)(intptr_t)serialPortPointer)->handle, &modemStatus) && (modemStatus & MS_RLSD_ON);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDTR(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getDTR(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
return env->GetBooleanField(obj, isDtrEnabledField);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRTS(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRTS(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
return env->GetBooleanField(obj, isRtsEnabledField);
}
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRI(JNIEnv *env, jobject obj, jlong serialPortFD)
JNIEXPORT jboolean JNICALL Java_com_fazecast_jSerialComm_SerialPort_getRI(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
HANDLE serialPortHandle = (HANDLE)serialPortFD;
if (serialPortHandle == INVALID_HANDLE_VALUE)
return JNI_FALSE;
DWORD modemStatus = 0;
return GetCommModemStatus(serialPortHandle, &modemStatus) && (modemStatus & MS_RING_ON);
return GetCommModemStatus(((serialPort*)(intptr_t)serialPortPointer)->handle, &modemStatus) && (modemStatus & MS_RING_ON);
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_getLastErrorLocation(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
return ((serialPort*)(intptr_t)serialPortPointer)->errorLineNumber;
}
JNIEXPORT jint JNICALL Java_com_fazecast_jSerialComm_SerialPort_getLastErrorCode(JNIEnv *env, jobject obj, jlong serialPortPointer)
{
return ((serialPort*)(intptr_t)serialPortPointer)->errorNumber;
}
#endif

View File

@ -2,7 +2,7 @@
* WindowsHelperFunctions.c
*
* Created on: May 05, 2015
* Last Updated on: Nov 03, 2021
* Last Updated on: Nov 14, 2021
* Author: Will Hedgecock
*
* Copyright (C) 2012-2021 Fazecast, Inc.
@ -28,37 +28,73 @@
#include <string.h>
#include "WindowsHelperFunctions.h"
void pushBack(struct charTupleVector* vector, const wchar_t* key, const wchar_t* firstString, const wchar_t* secondString)
// Common storage functionality
serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description)
{
// Allocate memory for new string storage
vector->length++;
wchar_t** newMemory = (wchar_t**)realloc(vector->first, vector->length*sizeof(wchar_t*));
if (newMemory)
vector->first = newMemory;
newMemory = (wchar_t**)realloc(vector->second, vector->length*sizeof(wchar_t*));
if (newMemory)
vector->second = newMemory;
newMemory = (wchar_t**)realloc(vector->third, vector->length*sizeof(wchar_t*));
if (newMemory)
vector->third = newMemory;
// Allocate memory for the new SerialPort storage structure
if (vector->capacity == vector->length)
{
serialPort** newArray = (serialPort**)realloc(vector->ports, ++vector->capacity * sizeof(serialPort*));
if (newArray)
vector->ports = newArray;
else
{
vector->capacity--;
return NULL;
}
}
serialPort* port = (serialPort*)malloc(sizeof(serialPort));
if (port)
vector->ports[vector->length++] = port;
else
return NULL;
// Store new strings
vector->first[vector->length-1] = (wchar_t*)malloc((wcslen(key)+1)*sizeof(wchar_t));
vector->second[vector->length-1] = (wchar_t*)malloc((wcslen(firstString)+1)*sizeof(wchar_t));
vector->third[vector->length-1] = (wchar_t*)malloc((wcslen(secondString)+1)*sizeof(wchar_t));
wcscpy(vector->first[vector->length-1], key);
wcscpy(vector->second[vector->length-1], firstString);
wcscpy(vector->third[vector->length-1], secondString);
// Initialize the storage structure
memset(port, 0, sizeof(serialPort));
port->handle = (void*)-1;
port->enumerated = 1;
port->portPath = (wchar_t*)malloc((wcslen(key)+1)*sizeof(wchar_t));
port->friendlyName = (wchar_t*)malloc((wcslen(friendlyName)+1)*sizeof(wchar_t));
port->portDescription = (wchar_t*)malloc((wcslen(description)+1)*sizeof(wchar_t));
// Store port strings
wcscpy(port->portPath, key);
wcscpy(port->friendlyName, friendlyName);
wcscpy(port->portDescription, description);
// Return the newly created serial port structure
return port;
}
char keyExists(struct charTupleVector* vector, const wchar_t* key)
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key)
{
// Search for a vector item with a matching key
size_t i;
for (i = 0; i < vector->length; ++i)
if (wcscmp(key, vector->first[i]) == 0)
return 1;
return 0;
for (int i = 0; i < vector->length; ++i)
if (wcscmp(key, vector->ports[i]->portPath) == 0)
return vector->ports[i];
return NULL;
}
void removePort(serialPortVector* vector, serialPort* port)
{
// Clean up memory associated with the port
free(port->portPath);
free(port->friendlyName);
free(port->portDescription);
if (port->readBuffer)
free(port->readBuffer);
// Move up all remaining ports in the serial port listing
for (int i = 0; i < vector->length; ++i)
if (vector->ports[i] == port)
{
for (int j = i; j < (vector->length - 1); ++j)
vector->ports[j] = vector->ports[j+1];
vector->length--;
break;
}
// Free the serial port structure memory
free(port);
}
#endif

View File

@ -2,7 +2,7 @@
* WindowsHelperFunctions.h
*
* Created on: May 05, 2015
* Last Updated on: Nov 03, 2021
* Last Updated on: Nov 14, 2021
* Author: Will Hedgecock
*
* Copyright (C) 2012-2021 Fazecast, Inc.
@ -26,13 +26,27 @@
#ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
#define __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
typedef struct charTupleVector
{
wchar_t **first, **second, **third;
size_t length;
} charTupleVector;
// Serial port JNI header file
#include "../com_fazecast_jSerialComm_SerialPort.h"
void pushBack(struct charTupleVector* vector, const wchar_t* key, const wchar_t* firstString, const wchar_t* secondString);
char keyExists(struct charTupleVector* vector, const wchar_t* key);
// Serial port data structure
typedef struct serialPort
{
void *handle;
char *readBuffer;
wchar_t *portPath, *friendlyName, *portDescription;
int errorLineNumber, errorNumber, readBufferLength;
volatile char enumerated, eventListenerRunning;
} serialPort;
// Common storage functionality
typedef struct serialPortVector
{
serialPort **ports;
int length, capacity;
} serialPortVector;
serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description);
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
void removePort(serialPortVector* vector, serialPort* port);
#endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__