Add Windows ability to retrieve physical port location
This commit is contained in:
parent
d456a72eac
commit
2ce74d0e71
|
@ -2,7 +2,7 @@
|
|||
* SerialPort_Windows.c
|
||||
*
|
||||
* Created on: Feb 25, 2012
|
||||
* Last Updated on: Dec 07, 2021
|
||||
* Last Updated on: Dec 16, 2021
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
|
@ -50,6 +50,7 @@ jfieldID disableConfigField;
|
|||
jfieldID isDtrEnabledField;
|
||||
jfieldID isRtsEnabledField;
|
||||
jfieldID autoFlushIOBuffersField;
|
||||
jfieldID portLocationField;
|
||||
jfieldID baudRateField;
|
||||
jfieldID dataBitsField;
|
||||
jfieldID stopBitsField;
|
||||
|
@ -76,7 +77,7 @@ typedef int (__stdcall *FT_OpenFunction)(int, FT_HANDLE*);
|
|||
typedef int (__stdcall *FT_CloseFunction)(FT_HANDLE);
|
||||
|
||||
// List of available serial ports
|
||||
serialPortVector serialPorts = { NULL, 0 };
|
||||
serialPortVector serialPorts = { NULL, 0, 0 };
|
||||
|
||||
JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommPorts(JNIEnv *env, jclass serialComm)
|
||||
{
|
||||
|
@ -86,6 +87,10 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
DWORD maxValueLength, maxComPortLength, valueLength, comPortLength, keyType;
|
||||
DWORD subKeyLength1, subKeyLength2, subKeyLength3, friendlyNameLength;
|
||||
|
||||
// Reset the enumerated flag on all non-open serial ports
|
||||
for (int i = 0; i < serialPorts.length; ++i)
|
||||
serialPorts.ports[i]->enumerated = (serialPorts.ports[i]->handle != INVALID_HANDLE_VALUE);
|
||||
|
||||
// Enumerate serial ports on machine
|
||||
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))
|
||||
|
@ -115,7 +120,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
pushBack(&serialPorts, comPortString, descriptionString, descriptionString);
|
||||
pushBack(&serialPorts, comPortString, descriptionString, descriptionString, L"0-0");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,6 +173,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
// Allocate memory
|
||||
friendlyNameLength = valueLength + 1;
|
||||
WCHAR *friendlyName = (WCHAR*)malloc(friendlyNameLength*sizeof(WCHAR));
|
||||
WCHAR *locationInfo = (WCHAR*)malloc(friendlyNameLength*sizeof(WCHAR));
|
||||
|
||||
if ((RegOpenKeyExW(keyHandle4, L"Device Parameters", 0, KEY_QUERY_VALUE, &keyHandle5) == ERROR_SUCCESS) &&
|
||||
(RegQueryInfoKeyW(keyHandle5, NULL, NULL, NULL, NULL, NULL, NULL, &numValues, NULL, &valueLength, NULL, NULL) == ERROR_SUCCESS))
|
||||
|
@ -178,12 +184,33 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
|
||||
// Attempt to get COM value and friendly port name
|
||||
if ((RegQueryValueExW(keyHandle5, L"PortName", NULL, &keyType, (BYTE*)comPort, &comPortLength) == ERROR_SUCCESS) && (keyType == REG_SZ) &&
|
||||
(RegQueryValueExW(keyHandle4, L"FriendlyName", NULL, &keyType, (BYTE*)friendlyName, &friendlyNameLength) == ERROR_SUCCESS) && (keyType == REG_SZ))
|
||||
(RegQueryValueExW(keyHandle4, L"FriendlyName", NULL, &keyType, (BYTE*)friendlyName, &friendlyNameLength) == ERROR_SUCCESS) && (keyType == REG_SZ) &&
|
||||
(RegQueryValueExW(keyHandle4, L"LocationInformation", NULL, &keyType, (BYTE*)locationInfo, &friendlyNameLength) == ERROR_SUCCESS) && (keyType == REG_SZ))
|
||||
{
|
||||
// Set port name and description
|
||||
wchar_t* comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
|
||||
wchar_t* descriptionString = friendlyName;
|
||||
|
||||
// Parse the port location
|
||||
int hub = 0, port = 0, bufferLength = 128;
|
||||
wchar_t *portLocation = (wchar_t*)malloc(bufferLength*sizeof(wchar_t));
|
||||
if (wcsstr(locationInfo, L"Port_#") && wcsstr(locationInfo, L"Hub_#"))
|
||||
{
|
||||
wchar_t *hubString = wcsrchr(locationInfo, L'#') + 1;
|
||||
hub = _wtoi(hubString);
|
||||
wchar_t *portString = wcschr(locationInfo, L'#') + 1;
|
||||
if (portString)
|
||||
{
|
||||
hubString = wcschr(portString, L'.');
|
||||
if (hubString)
|
||||
*hubString = L'\0';
|
||||
}
|
||||
port = _wtoi(portString);
|
||||
_snwprintf(portLocation, bufferLength, L"1-%d.%d", hub, port);
|
||||
}
|
||||
else
|
||||
wcscpy(portLocation, L"0-0");
|
||||
|
||||
// Update friendly name if COM port is actually connected and present in the port list
|
||||
for (int i = 0; i < serialPorts.length; ++i)
|
||||
if (wcscmp(serialPorts.ports[i]->portPath, comPortString) == 0)
|
||||
|
@ -194,8 +221,17 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
serialPorts.ports[i]->friendlyName = newMemory;
|
||||
wcscpy(serialPorts.ports[i]->friendlyName, descriptionString);
|
||||
}
|
||||
newMemory = (wchar_t*)realloc(serialPorts.ports[i]->portLocation, (wcslen(portLocation)+1)*sizeof(wchar_t));
|
||||
if (newMemory)
|
||||
{
|
||||
serialPorts.ports[i]->portLocation = newMemory;
|
||||
wcscpy(serialPorts.ports[i]->portLocation, portLocation);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(portLocation);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
|
@ -204,6 +240,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
|
||||
// Clean up memory and close registry key
|
||||
RegCloseKey(keyHandle5);
|
||||
free(locationInfo);
|
||||
free(friendlyName);
|
||||
}
|
||||
|
||||
|
@ -290,7 +327,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
FT_OpenFunction FT_Open = (FT_OpenFunction)GetProcAddress(ftdiLibInstance, "FT_Open");
|
||||
FT_CloseFunction FT_Close = (FT_CloseFunction)GetProcAddress(ftdiLibInstance, "FT_Close");
|
||||
FT_SetLatencyTimerFunction FT_SetLatencyTimer = (FT_SetLatencyTimerFunction)GetProcAddress(ftdiLibInstance, "FT_SetLatencyTimer");
|
||||
if ((FT_CreateDeviceInfoList != NULL) && (FT_GetDeviceInfoList != NULL) && (FT_GetComPortNumber != NULL) && (FT_Open != NULL) && (FT_Close != NULL))
|
||||
if (FT_CreateDeviceInfoList && FT_GetDeviceInfoList && FT_GetComPortNumber && FT_Open && FT_Close && FT_SetLatencyTimer)
|
||||
{
|
||||
DWORD numDevs;
|
||||
if ((FT_CreateDeviceInfoList(&numDevs) == FT_OK) && (numDevs > 0))
|
||||
|
@ -301,29 +338,44 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
wchar_t comPortString[128];
|
||||
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))
|
||||
{
|
||||
if (FT_SetLatencyTimer != NULL)
|
||||
{
|
||||
// Reduce latency timer
|
||||
FT_SetLatencyTimer(devInfo[i].ftHandle, 2); // Minimum value is 2. Ignore errors
|
||||
}
|
||||
// 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);
|
||||
// Determine if the port is currently enumerated and already open
|
||||
char isOpen = (devInfo[i].Flags & FT_FLAGS_OPENED) ? 1 : 0;
|
||||
if (!isOpen)
|
||||
for (int j = 0; j < serialPorts.length; ++j)
|
||||
if (wcscmp(serialPorts.ports[j]->portPath, comPortString) == 0)
|
||||
if ((memcmp(serialPorts.ports[j]->serialNumber, devInfo[i].SerialNumber, sizeof(serialPorts.ports[j]->serialNumber)) == 0) && (serialPorts.ports[j]->handle != INVALID_HANDLE_VALUE))
|
||||
{
|
||||
size_t descLength = 8+strlen(devInfo[i].Description);
|
||||
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);
|
||||
}
|
||||
serialPorts.ports[j]->enumerated = 1;
|
||||
isOpen = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
// Update the port description and latency if not already open
|
||||
if (!isOpen)
|
||||
{
|
||||
LONG comPortNumber = 0;
|
||||
if ((FT_Open(i, &devInfo[i].ftHandle) == FT_OK) && (FT_GetComPortNumber(devInfo[i].ftHandle, &comPortNumber) == FT_OK))
|
||||
{
|
||||
// Reduce latency timer to minimum value of 2
|
||||
FT_SetLatencyTimer(devInfo[i].ftHandle, 2);
|
||||
|
||||
// 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 (int j = 0; j < serialPorts.length; ++j)
|
||||
if (wcscmp(serialPorts.ports[j]->portPath, comPortString) == 0)
|
||||
{
|
||||
serialPorts.ports[j]->enumerated = 1;
|
||||
size_t descLength = 8+strlen(devInfo[i].Description);
|
||||
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);
|
||||
}
|
||||
memcpy(serialPorts.ports[j]->serialNumber, devInfo[i].SerialNumber, sizeof(serialPorts.ports[j]->serialNumber));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -333,6 +385,14 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
FreeLibrary(ftdiLibInstance);
|
||||
}
|
||||
|
||||
// Remove all non-enumerated ports from the serial port listing
|
||||
for (int i = 0; i < serialPorts.length; ++i)
|
||||
if (!serialPorts.ports[i]->enumerated)
|
||||
{
|
||||
removePort(&serialPorts, serialPorts.ports[i]);
|
||||
i--;
|
||||
}
|
||||
|
||||
// Get relevant SerialComm methods and fill in com port array
|
||||
wchar_t systemPortName[128];
|
||||
jobjectArray arrayObject = (*env)->NewObjectArray(env, serialPorts.length, serialCommClass, 0);
|
||||
|
@ -345,6 +405,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewString(env, (jchar*)systemPortName, wcslen(systemPortName)));
|
||||
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->friendlyName, wcslen(serialPorts.ports[i]->friendlyName)));
|
||||
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portDescription, wcslen(serialPorts.ports[i]->portDescription)));
|
||||
(*env)->SetObjectField(env, serialCommObject, portLocationField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portLocation, wcslen(serialPorts.ports[i]->portLocation)));
|
||||
|
||||
// Add new SerialComm object to array
|
||||
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
|
||||
|
@ -363,6 +424,7 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
|
|||
comPortField = (*env)->GetFieldID(env, serialCommClass, "comPort", "Ljava/lang/String;");
|
||||
friendlyNameField = (*env)->GetFieldID(env, serialCommClass, "friendlyName", "Ljava/lang/String;");
|
||||
portDescriptionField = (*env)->GetFieldID(env, serialCommClass, "portDescription", "Ljava/lang/String;");
|
||||
portLocationField = (*env)->GetFieldID(env, serialCommClass, "portLocation", "Ljava/lang/String;");
|
||||
eventListenerRunningField = (*env)->GetFieldID(env, serialCommClass, "eventListenerRunning", "Z");
|
||||
disableConfigField = (*env)->GetFieldID(env, serialCommClass, "disableConfig", "Z");
|
||||
isDtrEnabledField = (*env)->GetFieldID(env, serialCommClass, "isDtrEnabled", "Z");
|
||||
|
@ -405,7 +467,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
|||
if (!port)
|
||||
{
|
||||
// Create port representation and add to serial port listing
|
||||
port = pushBack(&serialPorts, portName, L"User-Specified Port", L"User-Specified Port");
|
||||
port = pushBack(&serialPorts, portName, L"User-Specified Port", L"User-Specified Port", L"0-0");
|
||||
}
|
||||
if (!port || (port->handle != INVALID_HANDLE_VALUE))
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WindowsHelperFunctions.c
|
||||
*
|
||||
* Created on: May 05, 2015
|
||||
* Last Updated on: Nov 14, 2021
|
||||
* Last Updated on: Dec 16, 2021
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
|
@ -29,7 +29,7 @@
|
|||
#include "WindowsHelperFunctions.h"
|
||||
|
||||
// Common storage functionality
|
||||
serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description)
|
||||
serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location)
|
||||
{
|
||||
// Allocate memory for the new SerialPort storage structure
|
||||
if (vector->capacity == vector->length)
|
||||
|
@ -54,11 +54,13 @@ serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t
|
|||
port->handle = (void*)-1;
|
||||
port->enumerated = 1;
|
||||
port->portPath = (wchar_t*)malloc((wcslen(key)+1)*sizeof(wchar_t));
|
||||
port->portLocation = (wchar_t*)malloc((wcslen(location)+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->portLocation, location);
|
||||
wcscpy(port->friendlyName, friendlyName);
|
||||
wcscpy(port->portDescription, description);
|
||||
|
||||
|
@ -78,6 +80,7 @@ void removePort(serialPortVector* vector, serialPort* port)
|
|||
{
|
||||
// Clean up memory associated with the port
|
||||
free(port->portPath);
|
||||
free(port->portLocation);
|
||||
free(port->friendlyName);
|
||||
free(port->portDescription);
|
||||
if (port->readBuffer)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WindowsHelperFunctions.h
|
||||
*
|
||||
* Created on: May 05, 2015
|
||||
* Last Updated on: Nov 14, 2021
|
||||
* Last Updated on: Dec 16, 2021
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
|
@ -34,9 +34,10 @@ typedef struct serialPort
|
|||
{
|
||||
void *handle;
|
||||
char *readBuffer;
|
||||
wchar_t *portPath, *friendlyName, *portDescription;
|
||||
wchar_t *portPath, *friendlyName, *portDescription, *portLocation;
|
||||
int errorLineNumber, errorNumber, readBufferLength;
|
||||
volatile char enumerated, eventListenerRunning;
|
||||
char serialNumber[16];
|
||||
} serialPort;
|
||||
|
||||
// Common storage functionality
|
||||
|
@ -45,7 +46,7 @@ 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* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location);
|
||||
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
|
||||
void removePort(serialPortVector* vector, serialPort* port);
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue