Do not use FTDI driver to fetch COM name, and search for MODEM devices
This commit is contained in:
parent
ba48714bcb
commit
d0aab972b6
|
@ -2,7 +2,7 @@
|
||||||
* SerialPort_Windows.c
|
* SerialPort_Windows.c
|
||||||
*
|
*
|
||||||
* Created on: Feb 25, 2012
|
* Created on: Feb 25, 2012
|
||||||
* Last Updated on: Jan 20, 2022
|
* Last Updated on: Jan 21, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -32,10 +32,11 @@
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <delayimp.h>
|
#include <delayimp.h>
|
||||||
#include <direct.h>
|
#include <direct.h>
|
||||||
|
#include <ntddmodm.h>
|
||||||
|
#include <ntddser.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <setupapi.h>
|
#include <setupapi.h>
|
||||||
#include <shellapi.h>
|
|
||||||
#include <devpkey.h>
|
#include <devpkey.h>
|
||||||
#include <devguid.h>
|
#include <devguid.h>
|
||||||
#include "ftdi/ftd2xx.h"
|
#include "ftdi/ftd2xx.h"
|
||||||
|
@ -75,9 +76,6 @@ jfieldID eventFlagsField;
|
||||||
// Runtime-loadable DLL functions
|
// Runtime-loadable DLL functions
|
||||||
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);
|
||||||
typedef int (__stdcall *FT_GetComPortNumberFunction)(FT_HANDLE, LPLONG);
|
|
||||||
typedef int (__stdcall *FT_OpenFunction)(int, FT_HANDLE*);
|
|
||||||
typedef int (__stdcall *FT_CloseFunction)(FT_HANDLE);
|
|
||||||
|
|
||||||
// List of available serial ports
|
// List of available serial ports
|
||||||
serialPortVector serialPorts = { NULL, 0, 0 };
|
serialPortVector serialPorts = { NULL, 0, 0 };
|
||||||
|
@ -107,139 +105,149 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
||||||
|
|
||||||
// Enumerate all serial ports present on the current system
|
// Enumerate all serial ports present on the current system
|
||||||
wchar_t comPort[128];
|
wchar_t comPort[128];
|
||||||
HDEVINFO devList = SetupDiGetClassDevsW(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
|
const struct { GUID guid; DWORD flags; } setupClasses[] = {
|
||||||
if (devList != INVALID_HANDLE_VALUE)
|
{ .guid = GUID_DEVCLASS_PORTS, .flags = DIGCF_PRESENT },
|
||||||
|
{ .guid = GUID_DEVCLASS_MODEM, .flags = DIGCF_PRESENT },
|
||||||
|
{ .guid = GUID_DEVCLASS_MULTIPORTSERIAL, .flags = DIGCF_PRESENT },
|
||||||
|
{ .guid = GUID_DEVINTERFACE_COMPORT, .flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE },
|
||||||
|
{ .guid = GUID_DEVINTERFACE_MODEM, .flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE }
|
||||||
|
};
|
||||||
|
for (int i = 0; i < (sizeof(setupClasses) / sizeof(setupClasses[0])); ++i)
|
||||||
{
|
{
|
||||||
// Iterate through all devices
|
HDEVINFO devList = SetupDiGetClassDevsW(&setupClasses[i].guid, NULL, NULL, setupClasses[i].flags);
|
||||||
DWORD devInterfaceIndex = 0;
|
if (devList != INVALID_HANDLE_VALUE)
|
||||||
DEVPROPTYPE devInfoPropType;
|
|
||||||
SP_DEVINFO_DATA devInfoData;
|
|
||||||
devInfoData.cbSize = sizeof(devInfoData);
|
|
||||||
while (SetupDiEnumDeviceInfo(devList, devInterfaceIndex++, &devInfoData))
|
|
||||||
{
|
{
|
||||||
// Fetch the corresponding COM port for this device
|
// Iterate through all devices
|
||||||
wchar_t *comPortString = NULL;
|
DWORD devInterfaceIndex = 0;
|
||||||
DWORD comPortLength = sizeof(comPort) / sizeof(wchar_t);
|
DEVPROPTYPE devInfoPropType;
|
||||||
HKEY key = SetupDiOpenDevRegKey(devList, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
SP_DEVINFO_DATA devInfoData;
|
||||||
if ((key != INVALID_HANDLE_VALUE) && (RegQueryValueExW(key, L"PortName", NULL, NULL, (BYTE*)comPort, &comPortLength) == ERROR_SUCCESS))
|
devInfoData.cbSize = sizeof(devInfoData);
|
||||||
comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
|
while (SetupDiEnumDeviceInfo(devList, devInterfaceIndex++, &devInfoData))
|
||||||
if (key != INVALID_HANDLE_VALUE)
|
{
|
||||||
RegCloseKey(key);
|
// Fetch the corresponding COM port for this device
|
||||||
if (!comPortString)
|
wchar_t *comPortString = NULL;
|
||||||
continue;
|
DWORD comPortLength = sizeof(comPort) / sizeof(wchar_t);
|
||||||
|
HKEY key = SetupDiOpenDevRegKey(devList, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
||||||
|
if ((key != INVALID_HANDLE_VALUE) && (RegQueryValueExW(key, L"PortName", NULL, NULL, (BYTE*)comPort, &comPortLength) == ERROR_SUCCESS))
|
||||||
|
comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
|
||||||
|
if (key != INVALID_HANDLE_VALUE)
|
||||||
|
RegCloseKey(key);
|
||||||
|
if (!comPortString)
|
||||||
|
continue;
|
||||||
|
|
||||||
// Fetch the friendly name for this device
|
// Fetch the friendly name for this device
|
||||||
DWORD friendlyNameLength = 0;
|
DWORD friendlyNameLength = 0;
|
||||||
wchar_t *friendlyNameString = NULL;
|
wchar_t *friendlyNameString = NULL;
|
||||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, NULL, 0, &friendlyNameLength, 0);
|
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, NULL, 0, &friendlyNameLength, 0);
|
||||||
if (!friendlyNameLength)
|
if (!friendlyNameLength)
|
||||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, NULL, 0, &friendlyNameLength);
|
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, NULL, 0, &friendlyNameLength);
|
||||||
if (friendlyNameLength)
|
if (friendlyNameLength)
|
||||||
{
|
|
||||||
friendlyNameString = (wchar_t*)malloc(friendlyNameLength);
|
|
||||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, (BYTE*)friendlyNameString, friendlyNameLength, NULL, 0) &&
|
|
||||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (BYTE*)friendlyNameString, friendlyNameLength, NULL))
|
|
||||||
{
|
{
|
||||||
friendlyNameLength = comPortLength;
|
friendlyNameString = (wchar_t*)malloc(friendlyNameLength);
|
||||||
friendlyNameString = (wchar_t*)realloc(friendlyNameString, comPortLength);
|
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, (BYTE*)friendlyNameString, friendlyNameLength, NULL, 0) &&
|
||||||
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (BYTE*)friendlyNameString, friendlyNameLength, NULL))
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
friendlyNameLength = comPortLength;
|
|
||||||
friendlyNameString = (wchar_t*)malloc(comPortLength);
|
|
||||||
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the bus-reported device description
|
|
||||||
DWORD portDescriptionLength = 0;
|
|
||||||
wchar_t *portDescriptionString = NULL;
|
|
||||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, NULL, 0, &portDescriptionLength, 0);
|
|
||||||
if (portDescriptionLength)
|
|
||||||
{
|
|
||||||
portDescriptionString = (wchar_t*)malloc(portDescriptionLength);
|
|
||||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, (BYTE*)portDescriptionString, portDescriptionLength, NULL, 0))
|
|
||||||
{
|
|
||||||
portDescriptionString = (wchar_t*)realloc(portDescriptionString, friendlyNameLength);
|
|
||||||
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
portDescriptionString = (wchar_t*)malloc(friendlyNameLength);
|
|
||||||
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch the physical location for this device
|
|
||||||
wchar_t *locationString = NULL;
|
|
||||||
DWORD locationLength = 0, busNumber = -1, hubNumber = -1, portNumber = -1;
|
|
||||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusNumber, &devInfoPropType, (BYTE*)&busNumber, sizeof(busNumber), NULL, 0) &&
|
|
||||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_BUSNUMBER, NULL, (BYTE*)&busNumber, sizeof(busNumber), NULL))
|
|
||||||
busNumber = -1;
|
|
||||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_Address, &devInfoPropType, (BYTE*)&portNumber, sizeof(portNumber), NULL, 0) &&
|
|
||||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_ADDRESS, NULL, (BYTE*)&portNumber, sizeof(portNumber), NULL))
|
|
||||||
portNumber = -1;
|
|
||||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, NULL, 0, &locationLength, 0);
|
|
||||||
if (!locationLength)
|
|
||||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, NULL, 0, &locationLength);
|
|
||||||
if (locationLength)
|
|
||||||
{
|
|
||||||
locationString = (wchar_t*)malloc(locationLength);
|
|
||||||
if (SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, (BYTE*)locationString, locationLength, NULL, 0) ||
|
|
||||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, (BYTE*)locationString, locationLength, NULL))
|
|
||||||
{
|
|
||||||
if (wcsstr(locationString, L"Hub"))
|
|
||||||
hubNumber = _wtoi(wcschr(wcsstr(locationString, L"Hub"), L'#') + 1);
|
|
||||||
if ((portNumber == -1) && wcsstr(locationString, L"Port"))
|
|
||||||
{
|
{
|
||||||
wchar_t *portString = wcschr(wcsstr(locationString, L"Port"), L'#') + 1;
|
friendlyNameLength = comPortLength;
|
||||||
if (portString)
|
friendlyNameString = (wchar_t*)realloc(friendlyNameString, comPortLength);
|
||||||
{
|
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
||||||
wchar_t *end = wcschr(portString, L'.');
|
|
||||||
if (end)
|
|
||||||
*end = L'\0';
|
|
||||||
}
|
|
||||||
portNumber = _wtoi(portString);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(locationString);
|
else
|
||||||
}
|
|
||||||
if (busNumber == -1)
|
|
||||||
busNumber = 0;
|
|
||||||
if (hubNumber == -1)
|
|
||||||
hubNumber = 0;
|
|
||||||
if (portNumber == -1)
|
|
||||||
portNumber = 0;
|
|
||||||
locationString = (wchar_t*)malloc(32*sizeof(wchar_t));
|
|
||||||
_snwprintf_s(locationString, 32, 32, L"%d-%d.%d", busNumber, hubNumber, portNumber);
|
|
||||||
|
|
||||||
// Check if port is already enumerated
|
|
||||||
serialPort *port = fetchPort(&serialPorts, comPortString);
|
|
||||||
if (port)
|
|
||||||
{
|
|
||||||
// See if device has changed locations
|
|
||||||
port->enumerated = 1;
|
|
||||||
int oldLength = wcslen(port->portLocation);
|
|
||||||
int newLength = wcslen(locationString);
|
|
||||||
if (oldLength != newLength)
|
|
||||||
{
|
{
|
||||||
port->portLocation = (wchar_t*)realloc(port->portLocation, (1 + newLength) * sizeof(wchar_t));
|
friendlyNameLength = comPortLength;
|
||||||
wcscpy_s(port->portLocation, 32, locationString);
|
friendlyNameString = (wchar_t*)malloc(comPortLength);
|
||||||
|
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
||||||
}
|
}
|
||||||
else if (wcscmp(port->portLocation, locationString))
|
|
||||||
wcscpy_s(port->portLocation, 32, locationString);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
pushBack(&serialPorts, comPortString, friendlyNameString, portDescriptionString, locationString);
|
|
||||||
|
|
||||||
// Clean up memory and reset device info structure
|
// Fetch the bus-reported device description
|
||||||
free(locationString);
|
DWORD portDescriptionLength = 0;
|
||||||
free(portDescriptionString);
|
wchar_t *portDescriptionString = NULL;
|
||||||
free(friendlyNameString);
|
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, NULL, 0, &portDescriptionLength, 0);
|
||||||
devInfoData.cbSize = sizeof(devInfoData);
|
if (portDescriptionLength)
|
||||||
|
{
|
||||||
|
portDescriptionString = (wchar_t*)malloc(portDescriptionLength);
|
||||||
|
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, (BYTE*)portDescriptionString, portDescriptionLength, NULL, 0))
|
||||||
|
{
|
||||||
|
portDescriptionString = (wchar_t*)realloc(portDescriptionString, friendlyNameLength);
|
||||||
|
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
portDescriptionString = (wchar_t*)malloc(friendlyNameLength);
|
||||||
|
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch the physical location for this device
|
||||||
|
wchar_t *locationString = NULL;
|
||||||
|
DWORD locationLength = 0, busNumber = -1, hubNumber = -1, portNumber = -1;
|
||||||
|
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusNumber, &devInfoPropType, (BYTE*)&busNumber, sizeof(busNumber), NULL, 0) &&
|
||||||
|
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_BUSNUMBER, NULL, (BYTE*)&busNumber, sizeof(busNumber), NULL))
|
||||||
|
busNumber = -1;
|
||||||
|
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_Address, &devInfoPropType, (BYTE*)&portNumber, sizeof(portNumber), NULL, 0) &&
|
||||||
|
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_ADDRESS, NULL, (BYTE*)&portNumber, sizeof(portNumber), NULL))
|
||||||
|
portNumber = -1;
|
||||||
|
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, NULL, 0, &locationLength, 0);
|
||||||
|
if (!locationLength)
|
||||||
|
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, NULL, 0, &locationLength);
|
||||||
|
if (locationLength)
|
||||||
|
{
|
||||||
|
locationString = (wchar_t*)malloc(locationLength);
|
||||||
|
if (SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, (BYTE*)locationString, locationLength, NULL, 0) ||
|
||||||
|
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, (BYTE*)locationString, locationLength, NULL))
|
||||||
|
{
|
||||||
|
if (wcsstr(locationString, L"Hub"))
|
||||||
|
hubNumber = _wtoi(wcschr(wcsstr(locationString, L"Hub"), L'#') + 1);
|
||||||
|
if ((portNumber == -1) && wcsstr(locationString, L"Port"))
|
||||||
|
{
|
||||||
|
wchar_t *portString = wcschr(wcsstr(locationString, L"Port"), L'#') + 1;
|
||||||
|
if (portString)
|
||||||
|
{
|
||||||
|
wchar_t *end = wcschr(portString, L'.');
|
||||||
|
if (end)
|
||||||
|
*end = L'\0';
|
||||||
|
}
|
||||||
|
portNumber = _wtoi(portString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(locationString);
|
||||||
|
}
|
||||||
|
if (busNumber == -1)
|
||||||
|
busNumber = 0;
|
||||||
|
if (hubNumber == -1)
|
||||||
|
hubNumber = 0;
|
||||||
|
if (portNumber == -1)
|
||||||
|
portNumber = 0;
|
||||||
|
locationString = (wchar_t*)malloc(32*sizeof(wchar_t));
|
||||||
|
_snwprintf_s(locationString, 32, 32, L"%d-%d.%d", busNumber, hubNumber, portNumber);
|
||||||
|
|
||||||
|
// Check if port is already enumerated
|
||||||
|
serialPort *port = fetchPort(&serialPorts, comPortString);
|
||||||
|
if (port)
|
||||||
|
{
|
||||||
|
// See if device has changed locations
|
||||||
|
port->enumerated = 1;
|
||||||
|
int oldLength = wcslen(port->portLocation);
|
||||||
|
int newLength = wcslen(locationString);
|
||||||
|
if (oldLength != newLength)
|
||||||
|
{
|
||||||
|
port->portLocation = (wchar_t*)realloc(port->portLocation, (1 + newLength) * sizeof(wchar_t));
|
||||||
|
wcscpy_s(port->portLocation, 32, locationString);
|
||||||
|
}
|
||||||
|
else if (wcscmp(port->portLocation, locationString))
|
||||||
|
wcscpy_s(port->portLocation, 32, locationString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pushBack(&serialPorts, comPortString, friendlyNameString, portDescriptionString, locationString);
|
||||||
|
|
||||||
|
// Clean up memory and reset device info structure
|
||||||
|
free(locationString);
|
||||||
|
free(portDescriptionString);
|
||||||
|
free(friendlyNameString);
|
||||||
|
devInfoData.cbSize = sizeof(devInfoData);
|
||||||
|
}
|
||||||
|
SetupDiDestroyDeviceInfoList(devList);
|
||||||
}
|
}
|
||||||
SetupDiDestroyDeviceInfoList(devList);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attempt to locate any FTDI-specified port descriptions
|
// Attempt to locate any FTDI-specified port descriptions
|
||||||
|
@ -248,10 +256,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
||||||
{
|
{
|
||||||
FT_CreateDeviceInfoListFunction FT_CreateDeviceInfoList = (FT_CreateDeviceInfoListFunction)GetProcAddress(ftdiLibInstance, "FT_CreateDeviceInfoList");
|
FT_CreateDeviceInfoListFunction FT_CreateDeviceInfoList = (FT_CreateDeviceInfoListFunction)GetProcAddress(ftdiLibInstance, "FT_CreateDeviceInfoList");
|
||||||
FT_GetDeviceInfoListFunction FT_GetDeviceInfoList = (FT_GetDeviceInfoListFunction)GetProcAddress(ftdiLibInstance, "FT_GetDeviceInfoList");
|
FT_GetDeviceInfoListFunction FT_GetDeviceInfoList = (FT_GetDeviceInfoListFunction)GetProcAddress(ftdiLibInstance, "FT_GetDeviceInfoList");
|
||||||
FT_GetComPortNumberFunction FT_GetComPortNumber = (FT_GetComPortNumberFunction)GetProcAddress(ftdiLibInstance, "FT_GetComPortNumber");
|
if (FT_CreateDeviceInfoList && FT_GetDeviceInfoList)
|
||||||
FT_OpenFunction FT_Open = (FT_OpenFunction)GetProcAddress(ftdiLibInstance, "FT_Open");
|
|
||||||
FT_CloseFunction FT_Close = (FT_CloseFunction)GetProcAddress(ftdiLibInstance, "FT_Close");
|
|
||||||
if (FT_CreateDeviceInfoList && FT_GetDeviceInfoList && FT_GetComPortNumber && FT_Open && FT_Close)
|
|
||||||
{
|
{
|
||||||
DWORD numDevs;
|
DWORD numDevs;
|
||||||
if ((FT_CreateDeviceInfoList(&numDevs) == FT_OK) && (numDevs > 0))
|
if ((FT_CreateDeviceInfoList(&numDevs) == FT_OK) && (numDevs > 0))
|
||||||
|
@ -273,30 +278,24 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the port description if not already open
|
// Update the port description if not already open
|
||||||
if (!isOpen)
|
if (!isOpen && getPortPathFromSerial(comPort, devInfo[i].SerialNumber))
|
||||||
{
|
{
|
||||||
LONG comPortNumber = 0;
|
// Check if actually connected and present in the port list
|
||||||
if ((FT_Open(i, &devInfo[i].ftHandle) == FT_OK) && (FT_GetComPortNumber(devInfo[i].ftHandle, &comPortNumber) == FT_OK))
|
for (int j = 0; j < serialPorts.length; ++j)
|
||||||
{
|
if (wcscmp(serialPorts.ports[j]->portPath, comPort) == 0)
|
||||||
// Close port and check if actually connected and present in the port list
|
{
|
||||||
FT_Close(devInfo[i].ftHandle);
|
// Update the port description
|
||||||
swprintf(comPort, sizeof(comPort) / sizeof(wchar_t), L"COM%ld", comPortNumber);
|
serialPorts.ports[j]->enumerated = 1;
|
||||||
for (int j = 0; j < serialPorts.length; ++j)
|
size_t descLength = 8 + strlen(devInfo[i].Description);
|
||||||
if (wcscmp(serialPorts.ports[j]->portPath, comPort) == 0)
|
wchar_t *newMemory = (wchar_t*)realloc(serialPorts.ports[j]->portDescription, descLength*sizeof(wchar_t));
|
||||||
|
if (newMemory)
|
||||||
{
|
{
|
||||||
// Update the port description
|
serialPorts.ports[j]->portDescription = newMemory;
|
||||||
serialPorts.ports[j]->enumerated = 1;
|
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, devInfo[i].Description, -1, serialPorts.ports[j]->portDescription, descLength);
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
memcpy(serialPorts.ports[j]->serialNumber, devInfo[i].SerialNumber, sizeof(serialPorts.ports[j]->serialNumber));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -444,85 +443,8 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce the port's latency timer to minimum value of 2
|
// Reduce the port's latency to its minimum value
|
||||||
HKEY key, paramKey = 0;
|
reduceLatencyToMinimum(port->portPath + 4);
|
||||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
DWORD index = 0, subkeySize = 255, portNameSize = 16;
|
|
||||||
wchar_t *subkey = (wchar_t*)malloc(subkeySize*sizeof(wchar_t)), *regPortName = (wchar_t*)malloc(portNameSize*sizeof(wchar_t));
|
|
||||||
while (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
DWORD latency = 2, oldLatency = 2, oldLatencySize = sizeof(DWORD);
|
|
||||||
char *subkeyString = (char*)malloc(subkeySize + 2);
|
|
||||||
memset(subkeyString, 0, subkeySize + 2);
|
|
||||||
wcstombs(subkeyString, subkey, subkeySize + 1);
|
|
||||||
subkeySize = 255;
|
|
||||||
portNameSize = 16;
|
|
||||||
memset(regPortName, 0, portNameSize * sizeof(wchar_t));
|
|
||||||
wcscat_s(subkey, subkeySize, L"\\0000\\Device Parameters");
|
|
||||||
if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
if ((RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)regPortName, &portNameSize) == ERROR_SUCCESS) && (wcscmp(port->portPath + 4, regPortName) == 0))
|
|
||||||
RegQueryValueExW(paramKey, L"LatencyTimer", NULL, NULL, (LPBYTE)&oldLatency, &oldLatencySize);
|
|
||||||
RegCloseKey(paramKey);
|
|
||||||
}
|
|
||||||
if (oldLatency > latency)
|
|
||||||
{
|
|
||||||
if (RegOpenKeyExW(key, subkey, 0, KEY_SET_VALUE, ¶mKey) == ERROR_SUCCESS)
|
|
||||||
{
|
|
||||||
RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&latency, sizeof(latency));
|
|
||||||
RegCloseKey(paramKey);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Create registry update file
|
|
||||||
char *workingDirectory = _getcwd(NULL, 0);
|
|
||||||
wchar_t *workingDirectoryWide = _wgetcwd(NULL, 0);
|
|
||||||
int workingDirectoryLength = strlen(workingDirectory) + 1;
|
|
||||||
char *registryFileName = (char*)malloc(workingDirectoryLength + 8);
|
|
||||||
wchar_t *paramsString = (wchar_t*)malloc((workingDirectoryLength + 11) * sizeof(wchar_t));
|
|
||||||
sprintf(registryFileName, "%s\\del.reg", workingDirectory);
|
|
||||||
swprintf(paramsString, workingDirectoryLength + 11, L"/s %s\\del.reg", workingDirectoryWide);
|
|
||||||
FILE *registryFile = fopen(registryFileName, "wb");
|
|
||||||
if (registryFile)
|
|
||||||
{
|
|
||||||
fprintf(registryFile, "Windows Registry Editor Version 5.00\n\n");
|
|
||||||
fprintf(registryFile, "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS\\%s\\0000\\Device Parameters]\n", subkeyString);
|
|
||||||
fprintf(registryFile, "\"LatencyTimer\"=dword:00000002\n\n");
|
|
||||||
fclose(registryFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Launch a new administrative process to update the registry value
|
|
||||||
SHELLEXECUTEINFOW shExInfo = { 0 };
|
|
||||||
shExInfo.cbSize = sizeof(shExInfo);
|
|
||||||
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
|
||||||
shExInfo.hwnd = NULL;
|
|
||||||
shExInfo.lpVerb = L"runas";
|
|
||||||
shExInfo.lpFile = L"C:\\Windows\\regedit.exe";
|
|
||||||
shExInfo.lpParameters = paramsString;
|
|
||||||
shExInfo.lpDirectory = NULL;
|
|
||||||
shExInfo.nShow = SW_SHOW;
|
|
||||||
shExInfo.hInstApp = 0;
|
|
||||||
if (ShellExecuteExW(&shExInfo))
|
|
||||||
{
|
|
||||||
WaitForSingleObject(shExInfo.hProcess, INFINITE);
|
|
||||||
CloseHandle(shExInfo.hProcess);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the registry update file
|
|
||||||
remove(registryFileName);
|
|
||||||
free(workingDirectoryWide);
|
|
||||||
free(workingDirectory);
|
|
||||||
free(registryFileName);
|
|
||||||
free(paramsString);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
free(subkeyString);
|
|
||||||
}
|
|
||||||
RegCloseKey(key);
|
|
||||||
free(regPortName);
|
|
||||||
free(subkey);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to open the serial port with read/write access
|
// 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)
|
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)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* WindowsHelperFunctions.c
|
* WindowsHelperFunctions.c
|
||||||
*
|
*
|
||||||
* Created on: May 05, 2015
|
* Created on: May 05, 2015
|
||||||
* Last Updated on: Jan 06, 2022
|
* Last Updated on: Jan 22, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -24,6 +24,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
#define WINVER _WIN32_WINNT_VISTA
|
||||||
|
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||||
|
#define NTDDI_VERSION NTDDI_VISTA
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
#include <direct.h>
|
||||||
|
#include <shellapi.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "WindowsHelperFunctions.h"
|
#include "WindowsHelperFunctions.h"
|
||||||
|
@ -100,4 +107,124 @@ void removePort(serialPortVector* vector, serialPort* port)
|
||||||
free(port);
|
free(port);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Windows-specific functionality
|
||||||
|
void reduceLatencyToMinimum(const wchar_t* portName)
|
||||||
|
{
|
||||||
|
// Search for this port in all FTDI enumerated ports
|
||||||
|
HKEY key, paramKey = 0;
|
||||||
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DWORD index = 0, subkeySize = 255, portNameSize = 16;
|
||||||
|
wchar_t *subkey = (wchar_t*)malloc(subkeySize*sizeof(wchar_t)), *regPortName = (wchar_t*)malloc(portNameSize*sizeof(wchar_t));
|
||||||
|
while (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DWORD latency = 2, oldLatency = 2, oldLatencySize = sizeof(DWORD);
|
||||||
|
char *subkeyString = (char*)malloc(subkeySize + 2);
|
||||||
|
memset(subkeyString, 0, subkeySize + 2);
|
||||||
|
wcstombs(subkeyString, subkey, subkeySize + 1);
|
||||||
|
subkeySize = 255;
|
||||||
|
portNameSize = 16;
|
||||||
|
memset(regPortName, 0, portNameSize * sizeof(wchar_t));
|
||||||
|
wcscat_s(subkey, subkeySize, L"\\0000\\Device Parameters");
|
||||||
|
if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if ((RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)regPortName, &portNameSize) == ERROR_SUCCESS) && (wcscmp(portName, regPortName) == 0))
|
||||||
|
RegQueryValueExW(paramKey, L"LatencyTimer", NULL, NULL, (LPBYTE)&oldLatency, &oldLatencySize);
|
||||||
|
RegCloseKey(paramKey);
|
||||||
|
}
|
||||||
|
if (oldLatency > latency)
|
||||||
|
{
|
||||||
|
if (RegOpenKeyExW(key, subkey, 0, KEY_SET_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&latency, sizeof(latency));
|
||||||
|
RegCloseKey(paramKey);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Create registry update file
|
||||||
|
char *workingDirectory = _getcwd(NULL, 0);
|
||||||
|
wchar_t *workingDirectoryWide = _wgetcwd(NULL, 0);
|
||||||
|
int workingDirectoryLength = strlen(workingDirectory) + 1;
|
||||||
|
char *registryFileName = (char*)malloc(workingDirectoryLength + 8);
|
||||||
|
wchar_t *paramsString = (wchar_t*)malloc((workingDirectoryLength + 11) * sizeof(wchar_t));
|
||||||
|
sprintf(registryFileName, "%s\\del.reg", workingDirectory);
|
||||||
|
swprintf(paramsString, workingDirectoryLength + 11, L"/s %s\\del.reg", workingDirectoryWide);
|
||||||
|
FILE *registryFile = fopen(registryFileName, "wb");
|
||||||
|
if (registryFile)
|
||||||
|
{
|
||||||
|
fprintf(registryFile, "Windows Registry Editor Version 5.00\n\n");
|
||||||
|
fprintf(registryFile, "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS\\%s\\0000\\Device Parameters]\n", subkeyString);
|
||||||
|
fprintf(registryFile, "\"LatencyTimer\"=dword:00000002\n\n");
|
||||||
|
fclose(registryFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Launch a new administrative process to update the registry value
|
||||||
|
SHELLEXECUTEINFOW shExInfo = { 0 };
|
||||||
|
shExInfo.cbSize = sizeof(shExInfo);
|
||||||
|
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||||
|
shExInfo.hwnd = NULL;
|
||||||
|
shExInfo.lpVerb = L"runas";
|
||||||
|
shExInfo.lpFile = L"C:\\Windows\\regedit.exe";
|
||||||
|
shExInfo.lpParameters = paramsString;
|
||||||
|
shExInfo.lpDirectory = NULL;
|
||||||
|
shExInfo.nShow = SW_SHOW;
|
||||||
|
shExInfo.hInstApp = 0;
|
||||||
|
if (ShellExecuteExW(&shExInfo))
|
||||||
|
{
|
||||||
|
WaitForSingleObject(shExInfo.hProcess, INFINITE);
|
||||||
|
CloseHandle(shExInfo.hProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete the registry update file
|
||||||
|
remove(registryFileName);
|
||||||
|
free(workingDirectoryWide);
|
||||||
|
free(workingDirectory);
|
||||||
|
free(registryFileName);
|
||||||
|
free(paramsString);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(subkeyString);
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
free(regPortName);
|
||||||
|
free(subkey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int getPortPathFromSerial(wchar_t* portPath, const char* serialNumber)
|
||||||
|
{
|
||||||
|
// Search for this port in all FTDI enumerated ports
|
||||||
|
int found = 0;
|
||||||
|
HKEY key, paramKey = 0;
|
||||||
|
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
DWORD index = 0, subkeySize = 255, portNameSize = 16;
|
||||||
|
wchar_t *subkey = (wchar_t*)malloc(subkeySize * sizeof(wchar_t));
|
||||||
|
while (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
// Determine if this device matches the specified serial number
|
||||||
|
char *subkeyString = (char*)malloc(subkeySize + 2);
|
||||||
|
memset(subkeyString, 0, subkeySize + 2);
|
||||||
|
wcstombs(subkeyString, subkey, subkeySize + 1);
|
||||||
|
subkeySize = 255;
|
||||||
|
if (strstr(subkeyString, serialNumber))
|
||||||
|
{
|
||||||
|
portNameSize = 16;
|
||||||
|
memset(portPath, 0, portNameSize * sizeof(wchar_t));
|
||||||
|
wcscat_s(subkey, subkeySize, L"\\0000\\Device Parameters");
|
||||||
|
if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)portPath, &portNameSize) == ERROR_SUCCESS)
|
||||||
|
found = 1;
|
||||||
|
RegCloseKey(paramKey);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(subkeyString);
|
||||||
|
}
|
||||||
|
RegCloseKey(key);
|
||||||
|
free(subkey);
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,10 +2,10 @@
|
||||||
* WindowsHelperFunctions.h
|
* WindowsHelperFunctions.h
|
||||||
*
|
*
|
||||||
* Created on: May 05, 2015
|
* Created on: May 05, 2015
|
||||||
* Last Updated on: Dec 16, 2021
|
* Last Updated on: Jan 21, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of jSerialComm.
|
* This file is part of jSerialComm.
|
||||||
*
|
*
|
||||||
|
@ -50,4 +50,8 @@ serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t
|
||||||
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
|
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
|
||||||
void removePort(serialPortVector* vector, serialPort* port);
|
void removePort(serialPortVector* vector, serialPort* port);
|
||||||
|
|
||||||
|
// Windows-specific functionality
|
||||||
|
void reduceLatencyToMinimum(const wchar_t* portName);
|
||||||
|
int getPortPathFromSerial(wchar_t* portPath, const char* serialNumber);
|
||||||
|
|
||||||
#endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
|
#endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
|
||||||
|
|
|
@ -561,6 +561,11 @@ public final class SerialPort
|
||||||
* <p>
|
* <p>
|
||||||
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
||||||
* <p>
|
* <p>
|
||||||
|
* Note on Windows using an FTDI device: The first time this method is called, you may be prompted to allow elevated privileges
|
||||||
|
* so that the driver latency can be correctly specified. This should only be necessary the first time you use a new FTDI device.
|
||||||
|
* Declining the elevated privileges will not affect the ability of the serial port to be accessed; however, read/write timing
|
||||||
|
* may not be as expected.
|
||||||
|
* <p>
|
||||||
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
||||||
*
|
*
|
||||||
* @param safetySleepTime The number of milliseconds to sleep before opening the port in case of frequent closing/openings.
|
* @param safetySleepTime The number of milliseconds to sleep before opening the port in case of frequent closing/openings.
|
||||||
|
@ -631,6 +636,11 @@ public final class SerialPort
|
||||||
* <p>
|
* <p>
|
||||||
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
||||||
* <p>
|
* <p>
|
||||||
|
* Note on Windows using an FTDI device: The first time this method is called, you may be prompted to allow elevated privileges
|
||||||
|
* so that the driver latency can be correctly specified. This should only be necessary the first time you use a new FTDI device.
|
||||||
|
* Declining the elevated privileges will not affect the ability of the serial port to be accessed; however, read/write timing
|
||||||
|
* may not be as expected.
|
||||||
|
* <p>
|
||||||
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
||||||
*
|
*
|
||||||
* @param safetySleepTime The number of milliseconds to sleep before opening the port in case of frequent closing/openings.
|
* @param safetySleepTime The number of milliseconds to sleep before opening the port in case of frequent closing/openings.
|
||||||
|
@ -645,6 +655,11 @@ public final class SerialPort
|
||||||
* <p>
|
* <p>
|
||||||
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
||||||
* <p>
|
* <p>
|
||||||
|
* Note on Windows using an FTDI device: The first time this method is called, you may be prompted to allow elevated privileges
|
||||||
|
* so that the driver latency can be correctly specified. This should only be necessary the first time you use a new FTDI device.
|
||||||
|
* Declining the elevated privileges will not affect the ability of the serial port to be accessed; however, read/write timing
|
||||||
|
* may not be as expected.
|
||||||
|
* <p>
|
||||||
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
||||||
*
|
*
|
||||||
* @return Whether the port was successfully opened with a valid configuration.
|
* @return Whether the port was successfully opened with a valid configuration.
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue