Add full functionality to retrieve physical port location
This commit is contained in:
parent
2ce74d0e71
commit
35a5818281
|
@ -2,7 +2,7 @@
|
|||
* PosixHelperFunctions.c
|
||||
*
|
||||
* Created on: Mar 10, 2015
|
||||
* Last Updated on: Dec 06, 2021
|
||||
* Last Updated on: Dec 16, 2021
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
|
@ -35,7 +35,7 @@
|
|||
#include "PosixHelperFunctions.h"
|
||||
|
||||
// Common storage functionality
|
||||
serialPort* pushBack(serialPortVector* vector, const char* key, const char* friendlyName, const char* description)
|
||||
serialPort* pushBack(serialPortVector* vector, const char* key, const char* friendlyName, const char* description, const char* location)
|
||||
{
|
||||
// Allocate memory for the new SerialPort storage structure
|
||||
if (vector->capacity == vector->length)
|
||||
|
@ -60,11 +60,13 @@ serialPort* pushBack(serialPortVector* vector, const char* key, const char* frie
|
|||
port->handle = -1;
|
||||
port->enumerated = 1;
|
||||
port->portPath = (char*)malloc(strlen(key) + 1);
|
||||
port->portLocation = (char*)malloc(strlen(location) + 1);
|
||||
port->friendlyName = (char*)malloc(strlen(friendlyName) + 1);
|
||||
port->portDescription = (char*)malloc(strlen(description) + 1);
|
||||
|
||||
// Store port strings
|
||||
strcpy(port->portPath, key);
|
||||
strcpy(port->portLocation, location);
|
||||
strcpy(port->friendlyName, friendlyName);
|
||||
strcpy(port->portDescription, description);
|
||||
|
||||
|
@ -84,6 +86,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)
|
||||
|
@ -181,6 +184,137 @@ void getInterfaceDescription(const char* interfaceFile, char* interfaceDescripti
|
|||
}
|
||||
}
|
||||
|
||||
char getPortLocation(const char* portDirectory, char* portLocation)
|
||||
{
|
||||
// Set location of busnum and devpath files
|
||||
char isUSB = 1;
|
||||
char* busnumFile = (char*)malloc(strlen(portDirectory) + 16);
|
||||
strcpy(busnumFile, portDirectory);
|
||||
strcat(busnumFile, "/busnum");
|
||||
char* devpathFile = (char*)malloc(strlen(portDirectory) + 16);
|
||||
strcpy(devpathFile, portDirectory);
|
||||
strcat(devpathFile, "/devpath");
|
||||
int portLocationLength = 0;
|
||||
portLocation[0] = '\0';
|
||||
|
||||
// Read the bus number
|
||||
FILE *input = fopen(busnumFile, "rb");
|
||||
if (input)
|
||||
{
|
||||
char ch = getc(input);
|
||||
while ((ch != '\n') && (ch != EOF))
|
||||
{
|
||||
portLocation[portLocationLength++] = ch;
|
||||
ch = getc(input);
|
||||
}
|
||||
portLocation[portLocationLength++] = '-';
|
||||
fclose(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
isUSB = 0;
|
||||
portLocation[portLocationLength++] = '0';
|
||||
portLocation[portLocationLength++] = '-';
|
||||
}
|
||||
|
||||
// Read the device path
|
||||
input = fopen(devpathFile, "rb");
|
||||
if (input)
|
||||
{
|
||||
char ch = getc(input);
|
||||
while ((ch != '\n') && (ch != EOF))
|
||||
{
|
||||
portLocation[portLocationLength++] = ch;
|
||||
ch = getc(input);
|
||||
}
|
||||
portLocation[portLocationLength] = '\0';
|
||||
fclose(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
isUSB = 0;
|
||||
portLocation[portLocationLength++] = '0';
|
||||
}
|
||||
|
||||
// Clean up the dynamic memory
|
||||
free(devpathFile);
|
||||
free(busnumFile);
|
||||
return isUSB;
|
||||
}
|
||||
|
||||
char driverGetPortLocation(char topLevel, const char *fullPathToSearch, const char *deviceName, char* portLocation, char searchBackwardIteration)
|
||||
{
|
||||
// Open the linux USB device directory
|
||||
char isUSB = 0;
|
||||
DIR *directoryIterator = opendir(fullPathToSearch);
|
||||
if (!directoryIterator)
|
||||
return isUSB;
|
||||
|
||||
if (!searchBackwardIteration)
|
||||
{
|
||||
// Read all sub-directories in the current directory
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry && !isUSB)
|
||||
{
|
||||
// Check if entry is a sub-directory
|
||||
if ((topLevel || (directoryEntry->d_type == DT_DIR)) && (directoryEntry->d_name[0] != '.'))
|
||||
{
|
||||
// Set up the next directory to search
|
||||
char* nextDirectory = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 5);
|
||||
strcpy(nextDirectory, fullPathToSearch);
|
||||
strcat(nextDirectory, directoryEntry->d_name);
|
||||
|
||||
// Only process directories that match the device name
|
||||
if (strcmp(directoryEntry->d_name, deviceName) == 0)
|
||||
{
|
||||
strcat(nextDirectory, "/..");
|
||||
isUSB = driverGetPortLocation(0, nextDirectory, deviceName, portLocation, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search for more serial ports within the directory
|
||||
strcat(nextDirectory, "/");
|
||||
isUSB = driverGetPortLocation(0, nextDirectory, deviceName, portLocation, 0);
|
||||
}
|
||||
free(nextDirectory);
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read all files in the current directory
|
||||
char hasBusnum = 0, hasDevpath = 0;
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry)
|
||||
{
|
||||
// Check if entry is a regular file with the expected name
|
||||
if (directoryEntry->d_type == DT_REG)
|
||||
{
|
||||
if (strcmp(directoryEntry->d_name, "busnum") == 0)
|
||||
hasBusnum = 1;
|
||||
else if (strcmp(directoryEntry->d_name, "devpath") == 0)
|
||||
hasDevpath = 1;
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
|
||||
// Check if the current directory has the required information files
|
||||
if ((!hasBusnum || !hasDevpath || !(isUSB = getPortLocation(fullPathToSearch, portLocation))) && (searchBackwardIteration < 10))
|
||||
{
|
||||
char* nextDirectory = (char*)malloc(strlen(fullPathToSearch) + 5);
|
||||
strcpy(nextDirectory, fullPathToSearch);
|
||||
strcat(nextDirectory, "/..");
|
||||
isUSB = driverGetPortLocation(0, nextDirectory, deviceName, portLocation, searchBackwardIteration + 1);
|
||||
free(nextDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the directory
|
||||
closedir(directoryIterator);
|
||||
return isUSB;
|
||||
}
|
||||
|
||||
void recursiveSearchForComPorts(serialPortVector* comPorts, const char* fullPathToSearch)
|
||||
{
|
||||
// Open the directory
|
||||
|
@ -215,11 +349,16 @@ void recursiveSearchForComPorts(serialPortVector* comPorts, const char* fullPath
|
|||
else
|
||||
{
|
||||
// See if device has a registered friendly name
|
||||
char* portLocation = (char*)malloc(128);
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
char* productFile = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 30);
|
||||
strcpy(productFile, fullPathToSearch);
|
||||
strcat(productFile, directoryEntry->d_name);
|
||||
strcat(productFile, "/device/../product");
|
||||
strcat(productFile, "/device/..");
|
||||
char isUSB = getPortLocation(productFile, portLocation);
|
||||
if (!isUSB)
|
||||
isUSB = driverGetPortLocation(1, "/sys/bus/usb/devices/", directoryEntry->d_name, portLocation, 0);
|
||||
strcat(productFile, "/product");
|
||||
getFriendlyName(productFile, friendlyName);
|
||||
if (friendlyName[0] == '\0') // Must be a physical (or emulated) port
|
||||
{
|
||||
|
@ -240,14 +379,14 @@ void recursiveSearchForComPorts(serialPortVector* comPorts, const char* fullPath
|
|||
{
|
||||
strcpy(friendlyName, "Bluetooth Port ");
|
||||
strcat(friendlyName, directoryEntry->d_name);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, portLocation);
|
||||
}
|
||||
else if (((strlen(directoryEntry->d_name) >= 6) && (directoryEntry->d_name[3] == 'A') && (directoryEntry->d_name[4] == 'M') && (directoryEntry->d_name[5] == 'A')) ||
|
||||
((ioctl(fd, TIOCGSERIAL, &serialInfo) == 0) && (serialInfo.type != PORT_UNKNOWN)))
|
||||
{
|
||||
strcpy(friendlyName, "Physical Port ");
|
||||
strcat(friendlyName, directoryEntry->d_name+3);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, portLocation);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
@ -270,7 +409,7 @@ void recursiveSearchForComPorts(serialPortVector* comPorts, const char* fullPath
|
|||
}
|
||||
if (interfaceDescription[0] == '\0')
|
||||
strcpy(interfaceDescription, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, interfaceDescription);
|
||||
pushBack(comPorts, systemName, friendlyName, interfaceDescription, portLocation);
|
||||
|
||||
// Clean up memory
|
||||
free(interfaceFile);
|
||||
|
@ -295,7 +434,7 @@ void recursiveSearchForComPorts(serialPortVector* comPorts, const char* fullPath
|
|||
}
|
||||
if (interfaceDescription[0] == '\0')
|
||||
strcpy(interfaceDescription, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, interfaceDescription);
|
||||
pushBack(comPorts, systemName, friendlyName, interfaceDescription, portLocation);
|
||||
|
||||
// Clean up memory
|
||||
free(interfaceFile);
|
||||
|
@ -305,6 +444,7 @@ void recursiveSearchForComPorts(serialPortVector* comPorts, const char* fullPath
|
|||
// Clean up memory
|
||||
free(productFile);
|
||||
free(friendlyName);
|
||||
free(portLocation);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
|
@ -361,7 +501,7 @@ void driverBasedSearchForComPorts(serialPortVector* comPorts, const char* fullPa
|
|||
strcat(friendlyName, serialLine);
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0");
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
|
@ -405,14 +545,17 @@ void lastDitchSearchForComPorts(serialPortVector* comPorts)
|
|||
else
|
||||
{
|
||||
// Set static friendly name
|
||||
char* portLocation = (char*)malloc(128);
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
strcpy(friendlyName, "USB-Based Serial Port");
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
char isUSB = driverGetPortLocation(1, "/sys/bus/usb/devices/", directoryEntry->d_name, portLocation, 0);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, portLocation);
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
free(portLocation);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
|
@ -433,14 +576,17 @@ void lastDitchSearchForComPorts(serialPortVector* comPorts)
|
|||
else
|
||||
{
|
||||
// Set static friendly name
|
||||
char* portLocation = (char*)malloc(128);
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
strcpy(friendlyName, "Advantech Extended Serial Port");
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
char isUSB = driverGetPortLocation(1, "/sys/bus/usb/devices/", directoryEntry->d_name, portLocation, 0);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, portLocation);
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
free(portLocation);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
|
@ -465,7 +611,7 @@ void lastDitchSearchForComPorts(serialPortVector* comPorts)
|
|||
strcpy(friendlyName, "Bluetooth-Based Serial Port");
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0");
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
|
@ -700,7 +846,7 @@ void searchForComPorts(serialPortVector* comPorts)
|
|||
struct stat fileStats;
|
||||
stat(systemName, &fileStats);
|
||||
if (!S_ISDIR(fileStats.st_mode))
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0");
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
|
@ -746,7 +892,7 @@ void searchForComPorts(serialPortVector* comPorts)
|
|||
struct stat fileStats;
|
||||
stat(systemName, &fileStats);
|
||||
if (!S_ISDIR(fileStats.st_mode))
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0");
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
|
@ -890,6 +1036,7 @@ void searchForComPorts(serialPortVector* comPorts)
|
|||
else
|
||||
{
|
||||
// Set static friendly name
|
||||
char *location = (char*)malloc(256);
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
if (directoryEntry->d_name[0] == 'c')
|
||||
strcpy(friendlyName, "Serial Port");
|
||||
|
@ -900,10 +1047,66 @@ void searchForComPorts(serialPortVector* comPorts)
|
|||
struct stat fileStats;
|
||||
stat(systemName, &fileStats);
|
||||
if (!S_ISDIR(fileStats.st_mode))
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName);
|
||||
{
|
||||
size_t bufferSize = 1024;
|
||||
char *stdOutResult = (char*)malloc(bufferSize), *device = NULL;
|
||||
snprintf(stdOutResult, bufferSize, "sysctl -a | grep \"ttyname: %s\"", directoryEntry->d_name + 3);
|
||||
FILE *pipe = popen(stdOutResult, "r");
|
||||
if (pipe)
|
||||
{
|
||||
while (!device && fgets(stdOutResult, bufferSize, pipe))
|
||||
{
|
||||
device = stdOutResult;
|
||||
*(strstr(device, "ttyname:") - 1) = '\0';
|
||||
strcat(device, ".%location");
|
||||
}
|
||||
pclose(pipe);
|
||||
}
|
||||
|
||||
// Add port to the list and clean up memory
|
||||
if (device)
|
||||
{
|
||||
char *location = (char*)malloc(256), *temp = (char*)malloc(64);
|
||||
snprintf(location, bufferSize, "sysctl -a | grep \"%s\"", device);
|
||||
pipe = popen(location, "r");
|
||||
strcpy(location, "0-0");
|
||||
if (pipe)
|
||||
{
|
||||
while (fgets(stdOutResult, bufferSize, pipe))
|
||||
if (strstr(stdOutResult, "bus") && strstr(stdOutResult, "hubaddr") && strstr(stdOutResult, "port"))
|
||||
{
|
||||
char *cursor = strstr(stdOutResult, "bus=") + 4;
|
||||
size_t length = (size_t)(strchr(cursor, ' ') - cursor);
|
||||
memcpy(location, cursor, length);
|
||||
location[length] = '\0';
|
||||
strcat(location, "-");
|
||||
cursor = strstr(stdOutResult, "hubaddr=") + 8;
|
||||
length = (size_t)(strchr(cursor, ' ') - cursor);
|
||||
memcpy(temp, cursor, length);
|
||||
temp[length] = '\0';
|
||||
strcat(location, temp);
|
||||
strcat(location, ".");
|
||||
cursor = strstr(stdOutResult, "port=") + 5;
|
||||
length = (size_t)(strchr(cursor, ' ') - cursor);
|
||||
memcpy(temp, cursor, length);
|
||||
temp[length] = '\0';
|
||||
strcat(location, temp);
|
||||
break;
|
||||
}
|
||||
pclose(pipe);
|
||||
}
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, location);
|
||||
free(location);
|
||||
free(temp);
|
||||
}
|
||||
else
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0");
|
||||
free(stdOutResult);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
free(location);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
|
@ -942,31 +1145,25 @@ int setBaudRateCustom(int portFD, baud_rate baudRate)
|
|||
void searchForComPorts(serialPortVector* comPorts)
|
||||
{
|
||||
serialPort *port;
|
||||
int numValues = 0;
|
||||
io_object_t serialPort;
|
||||
io_iterator_t serialPortIterator;
|
||||
char friendlyName[1024], comPortCu[1024], comPortTty[1024], portDescription[1024];
|
||||
char friendlyName[1024], comPortCu[1024], comPortTty[1024];
|
||||
char portLocation[1024], portDescription[1024];
|
||||
|
||||
// Enumerate serial ports on machine
|
||||
IOServiceGetMatchingServices(kIOMasterPortDefault, IOServiceMatching(kIOSerialBSDServiceValue), &serialPortIterator);
|
||||
while ((serialPort = IOIteratorNext(serialPortIterator)))
|
||||
{
|
||||
++numValues;
|
||||
IOObjectRelease(serialPort);
|
||||
}
|
||||
IOIteratorReset(serialPortIterator);
|
||||
for (int i = 0; i < numValues; ++i)
|
||||
{
|
||||
// Get serial port information
|
||||
char isUSB = 0;
|
||||
friendlyName[0] = '\0';
|
||||
serialPort = IOIteratorNext(serialPortIterator);
|
||||
io_registry_entry_t parent = 0;
|
||||
io_registry_entry_t service = serialPort;
|
||||
io_registry_entry_t parent = 0, service = serialPort;
|
||||
while (service)
|
||||
{
|
||||
if (IOObjectConformsTo(service, "IOUSBDevice"))
|
||||
{
|
||||
IORegistryEntryGetName(service, friendlyName);
|
||||
isUSB = 1;
|
||||
break;
|
||||
}
|
||||
if (IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent) != KERN_SUCCESS)
|
||||
|
@ -992,12 +1189,38 @@ void searchForComPorts(serialPortVector* comPorts)
|
|||
CFStringGetCString(comPortRef, comPortTty, sizeof(comPortTty), kCFStringEncodingUTF8);
|
||||
CFRelease(comPortRef);
|
||||
|
||||
// Get VID, PID, Serial Number, Bus Number, and Port Address
|
||||
if (isUSB)
|
||||
{
|
||||
CFTypeRef propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR("locationID"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
if (propertyRef)
|
||||
{
|
||||
int locationID = 0;
|
||||
char multiHub = 0, tempLocation[64];
|
||||
CFNumberGetValue(propertyRef, kCFNumberIntType, &locationID);
|
||||
CFRelease(propertyRef);
|
||||
snprintf(portLocation, sizeof(portLocation), "%d", (locationID >> 24) & 0x000000FF);
|
||||
strcat(portLocation, "-");
|
||||
while (locationID & 0x00F00000)
|
||||
{
|
||||
if (multiHub)
|
||||
strcat(portLocation, ".");
|
||||
snprintf(tempLocation, sizeof(tempLocation), "%d", (locationID >> 20) & 0x0000000F);
|
||||
strcat(portLocation, tempLocation);
|
||||
locationID <<= 4;
|
||||
multiHub = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
strcpy(portLocation, "0-0");
|
||||
|
||||
// Check if callout port is already enumerated
|
||||
port = fetchPort(comPorts, comPortCu);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
pushBack(comPorts, comPortCu, friendlyName, friendlyName);
|
||||
pushBack(comPorts, comPortCu, friendlyName, friendlyName, portLocation);
|
||||
|
||||
// Check if dialin port is already enumerated
|
||||
port = fetchPort(comPorts, comPortTty);
|
||||
|
@ -1005,7 +1228,7 @@ void searchForComPorts(serialPortVector* comPorts)
|
|||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
pushBack(comPorts, comPortTty, friendlyName, friendlyName);
|
||||
pushBack(comPorts, comPortTty, friendlyName, friendlyName, portLocation);
|
||||
IOObjectRelease(serialPort);
|
||||
}
|
||||
IOObjectRelease(serialPortIterator);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* PosixHelperFunctions.h
|
||||
*
|
||||
* Created on: Mar 10, 2015
|
||||
* Last Updated on: Nov 30, 2021
|
||||
* Last Updated on: Dec 16, 2021
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
|
@ -32,7 +32,7 @@
|
|||
// Serial port data structure
|
||||
typedef struct serialPort
|
||||
{
|
||||
char *portPath, *friendlyName, *portDescription, *readBuffer;
|
||||
char *portPath, *friendlyName, *portDescription, *portLocation, *readBuffer;
|
||||
int errorLineNumber, errorNumber, handle, readBufferLength;
|
||||
volatile char enumerated, eventListenerRunning;
|
||||
short eventsMask;
|
||||
|
@ -44,7 +44,7 @@ typedef struct serialPortVector
|
|||
serialPort **ports;
|
||||
int length, capacity;
|
||||
} serialPortVector;
|
||||
serialPort* pushBack(serialPortVector* vector, const char* key, const char* friendlyName, const char* description);
|
||||
serialPort* pushBack(serialPortVector* vector, const char* key, const char* friendlyName, const char* description, const char* location);
|
||||
serialPort* fetchPort(serialPortVector* vector, const char* key);
|
||||
void removePort(serialPortVector* vector, serialPort* port);
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* SerialPort_Posix.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.
|
||||
|
@ -54,6 +54,7 @@ jfieldID disableConfigField;
|
|||
jfieldID isDtrEnabledField;
|
||||
jfieldID isRtsEnabledField;
|
||||
jfieldID autoFlushIOBuffersField;
|
||||
jfieldID portLocationField;
|
||||
jfieldID baudRateField;
|
||||
jfieldID dataBitsField;
|
||||
jfieldID stopBitsField;
|
||||
|
@ -76,7 +77,7 @@ jfieldID writeTimeoutField;
|
|||
jfieldID eventFlagsField;
|
||||
|
||||
// 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)
|
||||
{
|
||||
|
@ -115,6 +116,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
(*env)->SetObjectField(env, serialCommObject, portDescriptionField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portDescription));
|
||||
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewStringUTF(env, serialPorts.ports[i]->friendlyName));
|
||||
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portPath));
|
||||
(*env)->SetObjectField(env, serialCommObject, portLocationField, (*env)->NewStringUTF(env, serialPorts.ports[i]->portLocation));
|
||||
|
||||
// Add new SerialComm object to array
|
||||
(*env)->SetObjectArrayElement(env, arrayObject, i, serialCommObject);
|
||||
|
@ -133,6 +135,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");
|
||||
|
@ -195,7 +198,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, "User-Specified Port", "User-Specified Port");
|
||||
port = pushBack(&serialPorts, portName, "User-Specified Port", "User-Specified Port", "0-0");
|
||||
}
|
||||
if (!port || (port->handle > 0))
|
||||
{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* SerialPort.java
|
||||
*
|
||||
* Created on: Feb 25, 2012
|
||||
* Last Updated on: Dec 09, 2021
|
||||
* Last Updated on: Dec 15, 2021
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
|
@ -492,7 +492,7 @@ public final class SerialPort
|
|||
private volatile byte xonStartChar = 17, xoffStopChar = 19;
|
||||
private volatile SerialPortDataListener userDataListener = null;
|
||||
private volatile SerialPortEventListener serialEventListener = null;
|
||||
private volatile String comPort, friendlyName, portDescription;
|
||||
private volatile String comPort, friendlyName, portDescription, portLocation;
|
||||
private volatile boolean eventListenerRunning = false, disableConfig = false, disableExclusiveLock = false;
|
||||
private volatile boolean rs485Mode = false, rs485ActiveHigh = true, rs485RxDuringTx = false, rs485EnableTermination = false;
|
||||
private volatile boolean isRtsEnabled = true, isDtrEnabled = true, autoFlushIOBuffers = false;
|
||||
|
@ -1473,10 +1473,32 @@ public final class SerialPort
|
|||
* <p>
|
||||
* This will only be available for USB-connected devices that report a product description.
|
||||
* Otherwise, it will return the same value as {@link #getDescriptivePortName()}.
|
||||
*
|
||||
*
|
||||
* @return The port description as reported by the device itself.
|
||||
*/
|
||||
public final String getPortDescription() { return portDescription.trim(); }
|
||||
|
||||
/**
|
||||
* Gets the physical location of the port as a String in the form "BUS-[HUB1.HUB2.etc]PORT_NUMBER".
|
||||
* <p>
|
||||
* "[HUB1.HUB2...]" is an optional field that refers to the hierarchy of USB hub numbers that a device
|
||||
* might be plugged into. For example, a USB-to-Serial Converter plugged into the third port of a USB hub
|
||||
* which is plugged into another USB hub which is plugged into a USB bus on a PC might have the port
|
||||
* location "1-1.1.3". A device plugged directly into a PC-based serial or USB port might have a port
|
||||
* location of "1-2". A virtual (non-physical) serial port might return a value of "0-0" since this
|
||||
* port has no physical location.
|
||||
* <p>
|
||||
* This method may be used to uniquely identify a device in the case where multiples of the same type
|
||||
* of device are present on the same system. In this case, the operating system might assign each device
|
||||
* to a different port number upon reboot; however, the port locations will remain the same as long
|
||||
* as each device remains physically plugged into the same port.
|
||||
* <p>
|
||||
* Note, if you manually specified the port location using {@link #getCommPort}, this method will
|
||||
* always return "0-0".
|
||||
*
|
||||
* @return The physical port location in the form "BUS-[HUB1.HUB2.etc]PORT_NUMBER".
|
||||
*/
|
||||
public final String getPortLocation() { return portLocation; }
|
||||
|
||||
/**
|
||||
* Gets the current baud rate of the serial port.
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,11 +1,15 @@
|
|||
# Compiler tools, commands, and flags
|
||||
COMPILE := gcc
|
||||
COMPILE_WIN := x86_64-w64-mingw32-gcc
|
||||
BUILD_DIR := build
|
||||
JDK_HOME := $(shell if [ "`uname`" = "Darwin" ]; then echo "`/usr/libexec/java_home`"; else echo "$$JDK_HOME"; fi)
|
||||
INCLUDES := -I"../../main/c/Posix" -I"$(JDK_HOME)/include" -I"$(JDK_HOME)/include/linux" -I"$(JDK_HOME)/include/darwin" -I"$(JDK_HOME)/include/solaris"
|
||||
INCLUDES := -I"../../main/c/Posix" -I"../../main/c/Windows" -I"$(JDK_HOME)/include" -I"$(JDK_HOME)/include/linux" -I"$(JDK_HOME)/include/darwin" -I"$(JDK_HOME)/include/solaris"
|
||||
CFLAGS := -fPIC -Os -flto -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 $(shell if [ "`uname`" != "Darwin" ]; then echo "-static-libgcc -fuse-linker-plugin"; fi)
|
||||
CFLAGS_WIN := -Os -flto -static-libgcc -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0
|
||||
LDFLAGS := -Os -flto -fuse-linker-plugin $(shell if [ "`uname`" != "Darwin" ]; then echo "-static-libgcc -s"; fi)
|
||||
LDFLAGS_WIN := -Os -flto -static-libgcc -fuse-linker-plugin -s
|
||||
LIBRARIES := $(shell if [ "`uname`" = "Darwin" ]; then echo "-framework Cocoa -framework IOKit"; else echo "-pthread"; fi)
|
||||
LIBRARIES_WIN := -ladvapi32 -lsetupapi
|
||||
DELETE := @rm
|
||||
MKDIR := @mkdir -p
|
||||
COPY := @cp
|
||||
|
@ -16,7 +20,7 @@ PRINT := @echo
|
|||
.PHONY: all clean
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .cpp .c .o .h
|
||||
vpath %.c ../../main/c/Posix
|
||||
vpath %.c ../../main/c/Posix ../../main/c/Windows
|
||||
|
||||
# Default build target does nothing
|
||||
all :
|
||||
|
@ -31,8 +35,18 @@ $(BUILD_DIR) :
|
|||
# Build rules for all tests
|
||||
testOpenClose : $(BUILD_DIR)/testOpenClose.o $(BUILD_DIR)/PosixHelperFunctions.o
|
||||
$(COMPILE) $(LDFLAGS) $(LIBRARIES) -o $@ $^
|
||||
testEnumeratePosix : $(BUILD_DIR)/testEnumeratePosix.o $(BUILD_DIR)/PosixHelperFunctions.o
|
||||
$(COMPILE) $(LDFLAGS) $(LIBRARIES) -o $@ $^
|
||||
testEnumerateWindows : $(BUILD_DIR)/testEnumerateWindows.o $(BUILD_DIR)/WindowsHelperFunctions.o
|
||||
$(COMPILE_WIN) $(LDFLAGS_WIN) $(LIBRARIES_WIN) -o $@ $^
|
||||
|
||||
# Suffix rules to get from *.c -> *.o
|
||||
$(BUILD_DIR)/testEnumerateWindows.o : testEnumerateWindows.c
|
||||
$(MKDIR) $(BUILD_DIR)
|
||||
$(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -o $@
|
||||
$(BUILD_DIR)/WindowsHelperFunctions.o : WindowsHelperFunctions.c
|
||||
$(MKDIR) $(BUILD_DIR)
|
||||
$(COMPILE_WIN) $(INCLUDES) $(CFLAGS_WIN) -c $< -o $@
|
||||
$(BUILD_DIR)/%.o : %.c
|
||||
$(MKDIR) $(BUILD_DIR)
|
||||
$(COMPILE) $(INCLUDES) $(CFLAGS) -c $< -o $@
|
||||
|
|
|
@ -0,0 +1,784 @@
|
|||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "PosixHelperFunctions.h"
|
||||
|
||||
static serialPortVector comPorts = { NULL, 0, 0 };
|
||||
|
||||
#if defined(__linux__)
|
||||
|
||||
#include <linux/serial.h>
|
||||
#include <asm/termios.h>
|
||||
#include <asm/ioctls.h>
|
||||
|
||||
void getDriverNameTest(const char* directoryToSearch, char* friendlyName)
|
||||
{
|
||||
friendlyName[0] = '\0';
|
||||
|
||||
// Open the directory
|
||||
DIR *directoryIterator = opendir(directoryToSearch);
|
||||
if (!directoryIterator)
|
||||
return;
|
||||
|
||||
// Read all sub-directories in the current directory
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry)
|
||||
{
|
||||
// Check if entry is a valid sub-directory
|
||||
if (directoryEntry->d_name[0] != '.')
|
||||
{
|
||||
// Get the readable part of the driver name
|
||||
strcpy(friendlyName, "USB-to-Serial Port (");
|
||||
char *startingPoint = strchr(directoryEntry->d_name, ':');
|
||||
if (startingPoint != NULL)
|
||||
strcat(friendlyName, startingPoint+1);
|
||||
else
|
||||
strcat(friendlyName, directoryEntry->d_name);
|
||||
strcat(friendlyName, ")");
|
||||
break;
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
|
||||
// Close the directory
|
||||
closedir(directoryIterator);
|
||||
}
|
||||
|
||||
void getFriendlyNameTest(const char* productFile, char* friendlyName)
|
||||
{
|
||||
int friendlyNameLength = 0;
|
||||
friendlyName[0] = '\0';
|
||||
|
||||
FILE *input = fopen(productFile, "rb");
|
||||
if (input)
|
||||
{
|
||||
char ch = getc(input);
|
||||
while ((ch != '\n') && (ch != EOF))
|
||||
{
|
||||
friendlyName[friendlyNameLength++] = ch;
|
||||
ch = getc(input);
|
||||
}
|
||||
friendlyName[friendlyNameLength] = '\0';
|
||||
fclose(input);
|
||||
}
|
||||
}
|
||||
|
||||
void getInterfaceDescriptionTest(const char* interfaceFile, char* interfaceDescription)
|
||||
{
|
||||
int interfaceDescriptionLength = 0;
|
||||
interfaceDescription[0] = '\0';
|
||||
|
||||
FILE *input = fopen(interfaceFile, "rb");
|
||||
if (input)
|
||||
{
|
||||
char ch = getc(input);
|
||||
while ((ch != '\n') && (ch != EOF))
|
||||
{
|
||||
interfaceDescription[interfaceDescriptionLength++] = ch;
|
||||
ch = getc(input);
|
||||
}
|
||||
interfaceDescription[interfaceDescriptionLength] = '\0';
|
||||
fclose(input);
|
||||
}
|
||||
}
|
||||
|
||||
char getPortLocationTest(const char* portDirectory, char* portLocation)
|
||||
{
|
||||
// Set location of busnum and devpath files
|
||||
char isUSB = 1;
|
||||
char* busnumFile = (char*)malloc(strlen(portDirectory) + 16);
|
||||
strcpy(busnumFile, portDirectory);
|
||||
strcat(busnumFile, "/busnum");
|
||||
char* devpathFile = (char*)malloc(strlen(portDirectory) + 16);
|
||||
strcpy(devpathFile, portDirectory);
|
||||
strcat(devpathFile, "/devpath");
|
||||
int portLocationLength = 0;
|
||||
portLocation[0] = '\0';
|
||||
|
||||
// Read the bus number
|
||||
FILE *input = fopen(busnumFile, "rb");
|
||||
if (input)
|
||||
{
|
||||
char ch = getc(input);
|
||||
while ((ch != '\n') && (ch != EOF))
|
||||
{
|
||||
portLocation[portLocationLength++] = ch;
|
||||
ch = getc(input);
|
||||
}
|
||||
portLocation[portLocationLength++] = '-';
|
||||
fclose(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
isUSB = 0;
|
||||
portLocation[portLocationLength++] = '0';
|
||||
portLocation[portLocationLength++] = '-';
|
||||
}
|
||||
|
||||
// Read the device path
|
||||
input = fopen(devpathFile, "rb");
|
||||
if (input)
|
||||
{
|
||||
char ch = getc(input);
|
||||
while ((ch != '\n') && (ch != EOF))
|
||||
{
|
||||
portLocation[portLocationLength++] = ch;
|
||||
ch = getc(input);
|
||||
}
|
||||
portLocation[portLocationLength] = '\0';
|
||||
fclose(input);
|
||||
}
|
||||
else
|
||||
{
|
||||
isUSB = 0;
|
||||
portLocation[portLocationLength++] = '0';
|
||||
}
|
||||
|
||||
// Clean up the dynamic memory
|
||||
free(devpathFile);
|
||||
free(busnumFile);
|
||||
return isUSB;
|
||||
}
|
||||
|
||||
char driverGetPortLocationTest(char topLevel, const char *fullPathToSearch, const char *deviceName, char* portLocation, char searchBackwardIteration)
|
||||
{
|
||||
// Open the linux USB device directory
|
||||
char isUSB = 0;
|
||||
DIR *directoryIterator = opendir(fullPathToSearch);
|
||||
if (!directoryIterator)
|
||||
return isUSB;
|
||||
|
||||
if (!searchBackwardIteration)
|
||||
{
|
||||
// Read all sub-directories in the current directory
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry && !isUSB)
|
||||
{
|
||||
// Check if entry is a sub-directory
|
||||
if ((topLevel || (directoryEntry->d_type == DT_DIR)) && (directoryEntry->d_name[0] != '.'))
|
||||
{
|
||||
// Set up the next directory to search
|
||||
char* nextDirectory = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 5);
|
||||
strcpy(nextDirectory, fullPathToSearch);
|
||||
strcat(nextDirectory, directoryEntry->d_name);
|
||||
|
||||
// Only process directories that match the device name
|
||||
if (strcmp(directoryEntry->d_name, deviceName) == 0)
|
||||
{
|
||||
strcat(nextDirectory, "/..");
|
||||
isUSB = driverGetPortLocationTest(0, nextDirectory, deviceName, portLocation, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search for more serial ports within the directory
|
||||
strcat(nextDirectory, "/");
|
||||
isUSB = driverGetPortLocationTest(0, nextDirectory, deviceName, portLocation, 0);
|
||||
}
|
||||
free(nextDirectory);
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Read all files in the current directory
|
||||
char hasBusnum = 0, hasDevpath = 0;
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry)
|
||||
{
|
||||
// Check if entry is a regular file with the expected name
|
||||
if (directoryEntry->d_type == DT_REG)
|
||||
{
|
||||
if (strcmp(directoryEntry->d_name, "busnum") == 0)
|
||||
hasBusnum = 1;
|
||||
else if (strcmp(directoryEntry->d_name, "devpath") == 0)
|
||||
hasDevpath = 1;
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
|
||||
// Check if the current directory has the required information files
|
||||
if ((!hasBusnum || !hasDevpath || !(isUSB = getPortLocationTest(fullPathToSearch, portLocation))) && (searchBackwardIteration < 10))
|
||||
{
|
||||
char* nextDirectory = (char*)malloc(strlen(fullPathToSearch) + 5);
|
||||
strcpy(nextDirectory, fullPathToSearch);
|
||||
strcat(nextDirectory, "/..");
|
||||
isUSB = driverGetPortLocationTest(0, nextDirectory, deviceName, portLocation, searchBackwardIteration + 1);
|
||||
free(nextDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
// Close the directory
|
||||
closedir(directoryIterator);
|
||||
return isUSB;
|
||||
}
|
||||
|
||||
void recursiveSearchForComPortsTest(serialPortVector* comPorts, const char* fullPathToSearch)
|
||||
{
|
||||
// Open the directory
|
||||
DIR *directoryIterator = opendir(fullPathToSearch);
|
||||
if (!directoryIterator)
|
||||
return;
|
||||
|
||||
// Read all sub-directories in the current directory
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry)
|
||||
{
|
||||
// Check if entry is a sub-directory
|
||||
if (directoryEntry->d_type == DT_DIR)
|
||||
{
|
||||
// Only process non-dot, non-virtual directories
|
||||
if ((directoryEntry->d_name[0] != '.') && (strcmp(directoryEntry->d_name, "virtual") != 0))
|
||||
{
|
||||
// See if the directory names a potential serial port
|
||||
if ((strlen(directoryEntry->d_name) > 3) &&
|
||||
(((directoryEntry->d_name[0] == 't') && (directoryEntry->d_name[1] == 't') && (directoryEntry->d_name[2] == 'y')) ||
|
||||
((directoryEntry->d_name[0] == 'r') && (directoryEntry->d_name[1] == 'f') && (directoryEntry->d_name[2] == 'c'))))
|
||||
{
|
||||
// Determine system name of port
|
||||
char* systemName = (char*)malloc(256);
|
||||
strcpy(systemName, "/dev/");
|
||||
strcat(systemName, directoryEntry->d_name);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(comPorts, systemName);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
{
|
||||
// See if device has a registered friendly name
|
||||
char* portLocation = (char*)malloc(128);
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
char* productFile = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 30);
|
||||
strcpy(productFile, fullPathToSearch);
|
||||
strcat(productFile, directoryEntry->d_name);
|
||||
strcat(productFile, "/device/..");
|
||||
char isUSB = getPortLocationTest(productFile, portLocation);
|
||||
if (!isUSB)
|
||||
isUSB = driverGetPortLocationTest(1, "/sys/bus/usb/devices/", directoryEntry->d_name, portLocation, 0);
|
||||
strcat(productFile, "/product");
|
||||
getFriendlyNameTest(productFile, friendlyName);
|
||||
if (friendlyName[0] == '\0') // Must be a physical (or emulated) port
|
||||
{
|
||||
// See if this is a USB-to-Serial converter based on the driver loaded
|
||||
strcpy(productFile, fullPathToSearch);
|
||||
strcat(productFile, directoryEntry->d_name);
|
||||
strcat(productFile, "/driver/module/drivers");
|
||||
getDriverNameTest(productFile, friendlyName);
|
||||
if (friendlyName[0] == '\0') // Must be a physical port
|
||||
{
|
||||
// Ensure that the platform port is actually open
|
||||
struct serial_struct serialInfo = { 0 };
|
||||
int fd = open(systemName, O_RDWR | O_NONBLOCK | O_NOCTTY);
|
||||
if (fd >= 0)
|
||||
{
|
||||
if ((strlen(directoryEntry->d_name) >= 6) && (directoryEntry->d_name[0] == 'r') && (directoryEntry->d_name[1] == 'f') && (directoryEntry->d_name[2] == 'c') &&
|
||||
(directoryEntry->d_name[3] == 'o') && (directoryEntry->d_name[4] == 'm') && (directoryEntry->d_name[5] == 'm'))
|
||||
{
|
||||
strcpy(friendlyName, "Bluetooth Port ");
|
||||
strcat(friendlyName, directoryEntry->d_name);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, portLocation);
|
||||
}
|
||||
else if (((strlen(directoryEntry->d_name) >= 6) && (directoryEntry->d_name[3] == 'A') && (directoryEntry->d_name[4] == 'M') && (directoryEntry->d_name[5] == 'A')) ||
|
||||
((ioctl(fd, TIOCGSERIAL, &serialInfo) == 0) && (serialInfo.type != PORT_UNKNOWN)))
|
||||
{
|
||||
strcpy(friendlyName, "Physical Port ");
|
||||
strcat(friendlyName, directoryEntry->d_name+3);
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, portLocation);
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to read from the device interface file
|
||||
char* interfaceDescription = (char*)malloc(256);
|
||||
char* interfaceFile = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 30);
|
||||
strcpy(interfaceFile, fullPathToSearch);
|
||||
strcat(interfaceFile, directoryEntry->d_name);
|
||||
strcat(interfaceFile, "/../interface");
|
||||
getInterfaceDescriptionTest(interfaceFile, interfaceDescription);
|
||||
if (interfaceDescription[0] == '\0')
|
||||
{
|
||||
strcpy(interfaceFile, fullPathToSearch);
|
||||
strcat(interfaceFile, directoryEntry->d_name);
|
||||
strcat(interfaceFile, "/device/../interface");
|
||||
getInterfaceDescriptionTest(interfaceFile, interfaceDescription);
|
||||
}
|
||||
if (interfaceDescription[0] == '\0')
|
||||
strcpy(interfaceDescription, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, interfaceDescription, portLocation);
|
||||
|
||||
// Clean up memory
|
||||
free(interfaceFile);
|
||||
free(interfaceDescription);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Attempt to read from the device interface file
|
||||
char* interfaceDescription = (char*)malloc(256);
|
||||
char* interfaceFile = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 30);
|
||||
strcpy(interfaceFile, fullPathToSearch);
|
||||
strcat(interfaceFile, directoryEntry->d_name);
|
||||
strcat(interfaceFile, "/../interface");
|
||||
getInterfaceDescriptionTest(interfaceFile, interfaceDescription);
|
||||
if (interfaceDescription[0] == '\0')
|
||||
{
|
||||
strcpy(interfaceFile, fullPathToSearch);
|
||||
strcat(interfaceFile, directoryEntry->d_name);
|
||||
strcat(interfaceFile, "/device/../interface");
|
||||
getInterfaceDescriptionTest(interfaceFile, interfaceDescription);
|
||||
}
|
||||
if (interfaceDescription[0] == '\0')
|
||||
strcpy(interfaceDescription, friendlyName);
|
||||
pushBack(comPorts, systemName, friendlyName, interfaceDescription, portLocation);
|
||||
|
||||
// Clean up memory
|
||||
free(interfaceFile);
|
||||
free(interfaceDescription);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(productFile);
|
||||
free(friendlyName);
|
||||
free(portLocation);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(systemName);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Search for more serial ports within the directory
|
||||
char* nextDirectory = (char*)malloc(strlen(fullPathToSearch) + strlen(directoryEntry->d_name) + 5);
|
||||
strcpy(nextDirectory, fullPathToSearch);
|
||||
strcat(nextDirectory, directoryEntry->d_name);
|
||||
strcat(nextDirectory, "/");
|
||||
recursiveSearchForComPortsTest(comPorts, nextDirectory);
|
||||
free(nextDirectory);
|
||||
}
|
||||
}
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
|
||||
// Close the directory
|
||||
closedir(directoryIterator);
|
||||
}
|
||||
|
||||
void driverBasedSearchForComPortsTest(serialPortVector* comPorts, const char* fullPathToDriver, const char* fullBasePathToPort)
|
||||
{
|
||||
// Search for unidentified physical serial ports
|
||||
FILE *serialDriverFile = fopen(fullPathToDriver, "rb");
|
||||
if (serialDriverFile)
|
||||
{
|
||||
char* serialLine = (char*)malloc(128);
|
||||
while (fgets(serialLine, 128, serialDriverFile))
|
||||
if (strstr(serialLine, "uart:") && (strstr(serialLine, "uart:unknown") == NULL))
|
||||
{
|
||||
// Determine system name of port
|
||||
*strchr(serialLine, ':') = '\0';
|
||||
char* systemName = (char*)malloc(256);
|
||||
strcpy(systemName, fullBasePathToPort);
|
||||
strcat(systemName, serialLine);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(comPorts, systemName);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
{
|
||||
// Ensure that the port is valid and not a symlink
|
||||
struct stat fileStats;
|
||||
if ((access(systemName, F_OK) == 0) && (lstat(systemName, &fileStats) == 0) && !S_ISLNK(fileStats.st_mode))
|
||||
{
|
||||
// Set static friendly name
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
strcpy(friendlyName, "Physical Port ");
|
||||
strcat(friendlyName, serialLine);
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0", 0);
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(systemName);
|
||||
}
|
||||
free(serialLine);
|
||||
fclose(serialDriverFile);
|
||||
}
|
||||
}
|
||||
|
||||
void lastDitchSearchForComPortsTest(serialPortVector* comPorts)
|
||||
{
|
||||
// Open the linux dev directory
|
||||
DIR *directoryIterator = opendir("/dev/");
|
||||
if (!directoryIterator)
|
||||
return;
|
||||
|
||||
// Read all files in the current directory
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry)
|
||||
{
|
||||
// See if the file names a potential serial port
|
||||
if ((strlen(directoryEntry->d_name) >= 6) && (directoryEntry->d_name[0] == 't') && (directoryEntry->d_name[1] == 't') && (directoryEntry->d_name[2] == 'y') &&
|
||||
(((directoryEntry->d_name[3] == 'A') && (directoryEntry->d_name[4] == 'M') && (directoryEntry->d_name[5] == 'A')) ||
|
||||
((directoryEntry->d_name[3] == 'A') && (directoryEntry->d_name[4] == 'C') && (directoryEntry->d_name[5] == 'M')) ||
|
||||
((directoryEntry->d_name[3] == 'U') && (directoryEntry->d_name[4] == 'S') && (directoryEntry->d_name[5] == 'B'))))
|
||||
{
|
||||
// Determine system name of port
|
||||
char* systemName = (char*)malloc(256);
|
||||
strcpy(systemName, "/dev/");
|
||||
strcat(systemName, directoryEntry->d_name);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(comPorts, systemName);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
{
|
||||
// Set static friendly name
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
strcpy(friendlyName, "USB-Based Serial Port");
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0", 1);
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(systemName);
|
||||
}
|
||||
else if ((strlen(directoryEntry->d_name) >= 6) && (directoryEntry->d_name[0] == 't') && (directoryEntry->d_name[1] == 't') && (directoryEntry->d_name[2] == 'y') &&
|
||||
(directoryEntry->d_name[3] == 'A') && (directoryEntry->d_name[4] == 'P'))
|
||||
{
|
||||
// Determine system name of port
|
||||
char* systemName = (char*)malloc(256);
|
||||
strcpy(systemName, "/dev/");
|
||||
strcat(systemName, directoryEntry->d_name);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(comPorts, systemName);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
{
|
||||
// Set static friendly name
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
strcpy(friendlyName, "Advantech Extended Serial Port");
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0", 0);
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(systemName);
|
||||
}
|
||||
else if ((strlen(directoryEntry->d_name) >= 6) && (directoryEntry->d_name[0] == 'r') && (directoryEntry->d_name[1] == 'f') && (directoryEntry->d_name[2] == 'c') &&
|
||||
(directoryEntry->d_name[3] == 'o') && (directoryEntry->d_name[4] == 'm') && (directoryEntry->d_name[5] == 'm'))
|
||||
{
|
||||
// Determine system name of port
|
||||
char* systemName = (char*)malloc(256);
|
||||
strcpy(systemName, "/dev/");
|
||||
strcat(systemName, directoryEntry->d_name);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(comPorts, systemName);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
{
|
||||
// Set static friendly name
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
strcpy(friendlyName, "Bluetooth-Based Serial Port");
|
||||
|
||||
// Add the port to the list
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0", 0);
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(systemName);
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
|
||||
// Close the directory
|
||||
closedir(directoryIterator);
|
||||
}
|
||||
|
||||
#elif defined(__FreeBSD__)
|
||||
|
||||
void searchForComPorts(serialPortVector* comPorts)
|
||||
{
|
||||
// Open the FreeBSD dev directory
|
||||
DIR *directoryIterator = opendir("/dev/");
|
||||
if (directoryIterator)
|
||||
{
|
||||
// Read all files in the current directory
|
||||
struct dirent *directoryEntry = readdir(directoryIterator);
|
||||
while (directoryEntry)
|
||||
{
|
||||
// See if the file names a potential serial port
|
||||
if ((strlen(directoryEntry->d_name) >= 4) && (directoryEntry->d_name[0] != '.') &&
|
||||
(((directoryEntry->d_name[0] == 't') && (directoryEntry->d_name[1] == 't') && (directoryEntry->d_name[2] == 'y') && (directoryEntry->d_name[3] != 'v')) ||
|
||||
((directoryEntry->d_name[0] == 'c') && (directoryEntry->d_name[1] == 'u') && (directoryEntry->d_name[2] == 'a'))))
|
||||
{
|
||||
// Ensure that the file is not an init or a lock file
|
||||
if ((strlen(directoryEntry->d_name) < 5) ||
|
||||
(memcmp(".init", directoryEntry->d_name + strlen(directoryEntry->d_name) - 5, 5) &&
|
||||
memcmp(".lock", directoryEntry->d_name + strlen(directoryEntry->d_name) - 5, 5)))
|
||||
{
|
||||
// Determine system name of port
|
||||
char* systemName = (char*)malloc(256);
|
||||
strcpy(systemName, "/dev/");
|
||||
strcat(systemName, directoryEntry->d_name);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(comPorts, systemName);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
{
|
||||
// Set static friendly name
|
||||
char *location = (char*)malloc(256);
|
||||
char* friendlyName = (char*)malloc(256);
|
||||
if (directoryEntry->d_name[0] == 'c')
|
||||
strcpy(friendlyName, "Serial Port");
|
||||
else
|
||||
strcpy(friendlyName, "Serial Port (Dial-In)");
|
||||
|
||||
// Add the port to the list if it is not a directory
|
||||
struct stat fileStats;
|
||||
stat(systemName, &fileStats);
|
||||
if (!S_ISDIR(fileStats.st_mode))
|
||||
{
|
||||
size_t bufferSize = 1024;
|
||||
char *stdOutResult = (char*)malloc(bufferSize), *device = NULL;
|
||||
snprintf(stdOutResult, bufferSize, "sysctl -a | grep \"ttyname: %s\"", directoryEntry->d_name + 3);
|
||||
FILE *pipe = popen(stdOutResult, "r");
|
||||
if (pipe)
|
||||
{
|
||||
while (!device && fgets(stdOutResult, bufferSize, pipe))
|
||||
{
|
||||
device = stdOutResult;
|
||||
*(strstr(device, "ttyname:") - 1) = '\0';
|
||||
strcat(device, ".%location");
|
||||
}
|
||||
pclose(pipe);
|
||||
}
|
||||
|
||||
// Add port to the list and clean up memory
|
||||
if (device)
|
||||
{
|
||||
char *location = (char*)malloc(256), *temp = (char*)malloc(64);
|
||||
snprintf(location, bufferSize, "sysctl -a | grep \"%s\"", device);
|
||||
pipe = popen(location, "r");
|
||||
strcpy(location, "0-0");
|
||||
if (pipe)
|
||||
{
|
||||
while (fgets(stdOutResult, bufferSize, pipe))
|
||||
if (strstr(stdOutResult, "bus") && strstr(stdOutResult, "hubaddr") && strstr(stdOutResult, "port"))
|
||||
{
|
||||
char *cursor = strstr(stdOutResult, "bus=") + 4;
|
||||
size_t length = (size_t)(strchr(cursor, ' ') - cursor);
|
||||
memcpy(location, cursor, length);
|
||||
location[length] = '\0';
|
||||
strcat(location, "-");
|
||||
cursor = strstr(stdOutResult, "hubaddr=") + 8;
|
||||
length = (size_t)(strchr(cursor, ' ') - cursor);
|
||||
memcpy(temp, cursor, length);
|
||||
temp[length] = '\0';
|
||||
strcat(location, temp);
|
||||
strcat(location, ".");
|
||||
cursor = strstr(stdOutResult, "port=") + 5;
|
||||
length = (size_t)(strchr(cursor, ' ') - cursor);
|
||||
memcpy(temp, cursor, length);
|
||||
temp[length] = '\0';
|
||||
strcat(location, temp);
|
||||
break;
|
||||
}
|
||||
pclose(pipe);
|
||||
}
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, location);
|
||||
free(location);
|
||||
free(temp);
|
||||
}
|
||||
else
|
||||
pushBack(comPorts, systemName, friendlyName, friendlyName, "0-0");
|
||||
free(stdOutResult);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(friendlyName);
|
||||
free(location);
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(systemName);
|
||||
}
|
||||
}
|
||||
directoryEntry = readdir(directoryIterator);
|
||||
}
|
||||
|
||||
// Close the directory
|
||||
closedir(directoryIterator);
|
||||
}
|
||||
}
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
|
||||
#include <AvailabilityMacros.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/serial/IOSerialKeys.h>
|
||||
#include <IOKit/serial/ioss.h>
|
||||
#include <IOKit/usb/USBSpec.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#if (MAC_OS_X_VERSION_MAX_ALLOWED < 120000)
|
||||
#define kIOMainPortDefault kIOMasterPortDefault
|
||||
#endif
|
||||
|
||||
void enumeratePortsMac(serialPortVector *comPorts)
|
||||
{
|
||||
serialPort *port;
|
||||
io_object_t serialPort;
|
||||
io_iterator_t serialPortIterator;
|
||||
int vendor_id = 0, product_id = 0;
|
||||
char friendlyName[1024], comPortCu[1024], comPortTty[1024];
|
||||
char portLocation[1024], portDescription[1024], serialNumber[1024] = "Unknown";
|
||||
|
||||
// Enumerate serial ports on machine
|
||||
IOServiceGetMatchingServices(kIOMainPortDefault, IOServiceMatching(kIOSerialBSDServiceValue), &serialPortIterator);
|
||||
while ((serialPort = IOIteratorNext(serialPortIterator)))
|
||||
{
|
||||
// Get serial port information
|
||||
char isUSB = 0;
|
||||
friendlyName[0] = '\0';
|
||||
io_registry_entry_t parent = 0, service = serialPort;
|
||||
while (service)
|
||||
{
|
||||
if (IOObjectConformsTo(service, "IOUSBDevice"))
|
||||
{
|
||||
IORegistryEntryGetName(service, friendlyName);
|
||||
isUSB = 1;
|
||||
break;
|
||||
}
|
||||
if (IORegistryEntryGetParentEntry(service, kIOServicePlane, &parent) != KERN_SUCCESS)
|
||||
break;
|
||||
if (service != serialPort)
|
||||
IOObjectRelease(service);
|
||||
service = parent;
|
||||
}
|
||||
if (service != serialPort)
|
||||
IOObjectRelease(service);
|
||||
|
||||
// Get serial port name and COM value
|
||||
if (friendlyName[0] == '\0')
|
||||
{
|
||||
CFStringRef friendlyNameRef = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIOTTYDeviceKey), kCFAllocatorDefault, 0);
|
||||
CFStringGetCString(friendlyNameRef, friendlyName, sizeof(friendlyName), kCFStringEncodingUTF8);
|
||||
CFRelease(friendlyNameRef);
|
||||
}
|
||||
CFStringRef comPortRef = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIOCalloutDeviceKey), kCFAllocatorDefault, 0);
|
||||
CFStringGetCString(comPortRef, comPortCu, sizeof(comPortCu), kCFStringEncodingUTF8);
|
||||
CFRelease(comPortRef);
|
||||
comPortRef = (CFStringRef)IORegistryEntryCreateCFProperty(serialPort, CFSTR(kIODialinDeviceKey), kCFAllocatorDefault, 0);
|
||||
CFStringGetCString(comPortRef, comPortTty, sizeof(comPortTty), kCFStringEncodingUTF8);
|
||||
CFRelease(comPortRef);
|
||||
|
||||
// Get VID, PID, Serial Number, Bus Number, and Port Address
|
||||
if (isUSB)
|
||||
{
|
||||
CFTypeRef propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR("locationID"), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
if (propertyRef)
|
||||
{
|
||||
int locationID = 0;
|
||||
char multiHub = 0, tempLocation[64];
|
||||
CFNumberGetValue(propertyRef, kCFNumberIntType, &locationID);
|
||||
CFRelease(propertyRef);
|
||||
snprintf(portLocation, sizeof(portLocation), "%d", (locationID >> 24) & 0x000000FF);
|
||||
strcat(portLocation, "-");
|
||||
while (locationID & 0x00F00000)
|
||||
{
|
||||
if (multiHub)
|
||||
strcat(portLocation, ".");
|
||||
snprintf(tempLocation, sizeof(tempLocation), "%d", (locationID >> 20) & 0x0000000F);
|
||||
strcat(portLocation, tempLocation);
|
||||
locationID <<= 4;
|
||||
multiHub = 1;
|
||||
}
|
||||
}
|
||||
propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR(kUSBSerialNumberString), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
if (propertyRef)
|
||||
{
|
||||
CFStringGetCString(propertyRef, serialNumber, sizeof(serialNumber), kCFStringEncodingASCII);
|
||||
CFRelease(propertyRef);
|
||||
}
|
||||
propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR(kUSBVendorID), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
if (propertyRef)
|
||||
{
|
||||
CFNumberGetValue(propertyRef, kCFNumberIntType, &vendor_id);
|
||||
CFRelease(propertyRef);
|
||||
}
|
||||
propertyRef = IORegistryEntrySearchCFProperty(serialPort, kIOServicePlane, CFSTR(kUSBProductID), kCFAllocatorDefault, kIORegistryIterateRecursively | kIORegistryIterateParents);
|
||||
if (propertyRef)
|
||||
{
|
||||
CFNumberGetValue(propertyRef, kCFNumberIntType, &product_id);
|
||||
CFRelease(propertyRef);
|
||||
}
|
||||
}
|
||||
else
|
||||
strcpy(portLocation, "0-0");
|
||||
|
||||
// Add ports to enumerated list
|
||||
pushBack(comPorts, comPortCu, friendlyName, friendlyName, portLocation);
|
||||
strcat(friendlyName, " (Dial-In)");
|
||||
pushBack(comPorts, comPortTty, friendlyName, friendlyName, portLocation);
|
||||
IOObjectRelease(serialPort);
|
||||
}
|
||||
IOObjectRelease(serialPortIterator);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Enumerate all serial ports
|
||||
#if defined(__linux__)
|
||||
recursiveSearchForComPortsTest(&comPorts, "/sys/devices/");
|
||||
driverBasedSearchForComPortsTest(&comPorts, "/proc/tty/driver/serial", "/dev/ttyS");
|
||||
driverBasedSearchForComPortsTest(&comPorts, "/proc/tty/driver/mvebu_serial", "/dev/ttyMV");
|
||||
lastDitchSearchForComPortsTest(&comPorts);
|
||||
#elif defined(__APPLE__)
|
||||
enumeratePortsMac(&comPorts);
|
||||
#endif
|
||||
|
||||
// Output all enumerated ports
|
||||
for (int i = 0; i < comPorts.length; ++i)
|
||||
{
|
||||
serialPort *port = comPorts.ports[i];
|
||||
printf("%s: Description = %s, Location = %s\n", port->portPath, port->friendlyName, port->portLocation);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
#define WINVER _WIN32_WINNT_VISTA
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#define NTDDI_VERSION NTDDI_VISTA
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <initguid.h>
|
||||
#include <windows.h>
|
||||
#include <delayimp.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setupapi.h>
|
||||
#include <devpkey.h>
|
||||
#include "WindowsHelperFunctions.h"
|
||||
|
||||
static serialPortVector serialPorts = { NULL, 0, 0 };
|
||||
|
||||
void getPortsWindows(void)
|
||||
{
|
||||
HKEY keyHandle1, keyHandle2, keyHandle3, keyHandle4, keyHandle5;
|
||||
DWORD numSubKeys1, numSubKeys2, numSubKeys3, numValues;
|
||||
DWORD maxSubKeyLength1, maxSubKeyLength2, maxSubKeyLength3;
|
||||
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))
|
||||
{
|
||||
// Allocate memory
|
||||
++maxValueLength;
|
||||
++maxComPortLength;
|
||||
WCHAR *valueName = (WCHAR*)malloc(maxValueLength*sizeof(WCHAR));
|
||||
WCHAR *comPort = (WCHAR*)malloc(maxComPortLength*sizeof(WCHAR));
|
||||
|
||||
// Iterate through all COM ports
|
||||
for (DWORD i = 0; i < numValues; ++i)
|
||||
{
|
||||
// Get serial port name and COM value
|
||||
valueLength = maxValueLength;
|
||||
comPortLength = maxComPortLength;
|
||||
memset(valueName, 0, valueLength*sizeof(WCHAR));
|
||||
memset(comPort, 0, comPortLength*sizeof(WCHAR));
|
||||
if ((RegEnumValueW(keyHandle1, i, valueName, &valueLength, NULL, &keyType, (BYTE*)comPort, &comPortLength) == ERROR_SUCCESS) && (keyType == REG_SZ))
|
||||
{
|
||||
// Set port name and description
|
||||
wchar_t* comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
|
||||
wchar_t* descriptionString = wcsrchr(valueName, L'\\') ? (wcsrchr(valueName, L'\\') + 1) : valueName;
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(&serialPorts, comPortString);
|
||||
if (port)
|
||||
port->enumerated = 1;
|
||||
else
|
||||
pushBack(&serialPorts, comPortString, descriptionString, descriptionString, L"0-0");
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(valueName);
|
||||
free(comPort);
|
||||
}
|
||||
RegCloseKey(keyHandle1);
|
||||
|
||||
// Enumerate all devices on machine
|
||||
if ((RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum", 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &keyHandle1) == ERROR_SUCCESS) &&
|
||||
(RegQueryInfoKeyW(keyHandle1, NULL, NULL, NULL, &numSubKeys1, &maxSubKeyLength1, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS))
|
||||
{
|
||||
// Allocate memory
|
||||
++maxSubKeyLength1;
|
||||
WCHAR *subKeyName1 = (WCHAR*)malloc(maxSubKeyLength1*sizeof(WCHAR));
|
||||
|
||||
// Enumerate sub-keys
|
||||
for (DWORD i1 = 0; i1 < numSubKeys1; ++i1)
|
||||
{
|
||||
subKeyLength1 = maxSubKeyLength1;
|
||||
if ((RegEnumKeyExW(keyHandle1, i1, subKeyName1, &subKeyLength1, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
|
||||
(RegOpenKeyExW(keyHandle1, subKeyName1, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &keyHandle2) == ERROR_SUCCESS) &&
|
||||
(RegQueryInfoKeyW(keyHandle2, NULL, NULL, NULL, &numSubKeys2, &maxSubKeyLength2, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS))
|
||||
{
|
||||
// Allocate memory
|
||||
++maxSubKeyLength2;
|
||||
WCHAR *subKeyName2 = (WCHAR*)malloc(maxSubKeyLength2*sizeof(WCHAR));
|
||||
|
||||
// Enumerate sub-keys
|
||||
for (DWORD i2 = 0; i2 < numSubKeys2; ++i2)
|
||||
{
|
||||
subKeyLength2 = maxSubKeyLength2;
|
||||
if ((RegEnumKeyExW(keyHandle2, i2, subKeyName2, &subKeyLength2, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
|
||||
(RegOpenKeyExW(keyHandle2, subKeyName2, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &keyHandle3) == ERROR_SUCCESS) &&
|
||||
(RegQueryInfoKeyW(keyHandle3, NULL, NULL, NULL, &numSubKeys3, &maxSubKeyLength3, NULL, NULL, NULL, NULL, NULL, NULL) == ERROR_SUCCESS))
|
||||
{
|
||||
// Allocate memory
|
||||
++maxSubKeyLength3;
|
||||
WCHAR *subKeyName3 = (WCHAR*)malloc(maxSubKeyLength3*sizeof(WCHAR));
|
||||
|
||||
// Enumerate sub-keys
|
||||
for (DWORD i3 = 0; i3 < numSubKeys3; ++i3)
|
||||
{
|
||||
subKeyLength3 = maxSubKeyLength3;
|
||||
if ((RegEnumKeyExW(keyHandle3, i3, subKeyName3, &subKeyLength3, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) &&
|
||||
(RegOpenKeyExW(keyHandle3, subKeyName3, 0, KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE, &keyHandle4) == ERROR_SUCCESS) &&
|
||||
(RegQueryInfoKeyW(keyHandle4, NULL, NULL, NULL, NULL, NULL, NULL, &numValues, NULL, &valueLength, NULL, NULL) == ERROR_SUCCESS))
|
||||
{
|
||||
// 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))
|
||||
{
|
||||
// Allocate memory
|
||||
comPortLength = valueLength + 1;
|
||||
WCHAR *comPort = (WCHAR*)malloc(comPortLength*sizeof(WCHAR));
|
||||
|
||||
// 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"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, comPortLength, 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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
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
|
||||
free(comPort);
|
||||
}
|
||||
|
||||
// Clean up memory and close registry key
|
||||
RegCloseKey(keyHandle5);
|
||||
free(locationInfo);
|
||||
free(friendlyName);
|
||||
}
|
||||
|
||||
// Close registry key
|
||||
RegCloseKey(keyHandle4);
|
||||
}
|
||||
|
||||
// Clean up memory and close registry key
|
||||
RegCloseKey(keyHandle3);
|
||||
free(subKeyName3);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up memory and close registry key
|
||||
RegCloseKey(keyHandle2);
|
||||
free(subKeyName2);
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up memory and close registry key
|
||||
RegCloseKey(keyHandle1);
|
||||
free(subKeyName1);
|
||||
}
|
||||
|
||||
// Attempt to locate any device-specified port descriptions
|
||||
HDEVINFO devList = SetupDiGetClassDevsW(NULL, L"USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
|
||||
if (devList != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Iterate through all USB-connected devices
|
||||
DWORD devInterfaceIndex = 0;
|
||||
DEVPROPTYPE devInfoPropType;
|
||||
SP_DEVINFO_DATA devInfoData;
|
||||
devInfoData.cbSize = sizeof(devInfoData);
|
||||
WCHAR comPort[128];
|
||||
while (SetupDiEnumDeviceInfo(devList, devInterfaceIndex++, &devInfoData))
|
||||
{
|
||||
// Fetch the corresponding COM port for this device
|
||||
wchar_t* comPortString = NULL;
|
||||
comPortLength = sizeof(comPort) / sizeof(WCHAR);
|
||||
keyHandle5 = SetupDiOpenDevRegKey(devList, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
||||
if ((keyHandle5 != INVALID_HANDLE_VALUE) && (RegQueryValueExW(keyHandle5, L"PortName", NULL, &keyType, (BYTE*)comPort, &comPortLength) == ERROR_SUCCESS) && (keyType == REG_SZ))
|
||||
comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
|
||||
if (keyHandle5 != INVALID_HANDLE_VALUE)
|
||||
RegCloseKey(keyHandle5);
|
||||
|
||||
// Fetch the length of the "Bus-Reported Device Description"
|
||||
if (comPortString && !SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, NULL, 0, &valueLength, 0) && (GetLastError() == ERROR_INSUFFICIENT_BUFFER))
|
||||
{
|
||||
// Allocate memory
|
||||
++valueLength;
|
||||
WCHAR *portDescription = (WCHAR*)malloc(valueLength);
|
||||
|
||||
// Retrieve the "Bus-Reported Device Description"
|
||||
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
|
||||
for (int i = 0; i < serialPorts.length; ++i)
|
||||
if (wcscmp(serialPorts.ports[i]->portPath, comPortString) == 0)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up memory
|
||||
free(portDescription);
|
||||
}
|
||||
devInfoData.cbSize = sizeof(devInfoData);
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(devList);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
// Enumerate all serial ports
|
||||
getPortsWindows();
|
||||
|
||||
// Output all enumerated ports
|
||||
for (int i = 0; i < serialPorts.length; ++i)
|
||||
{
|
||||
serialPort *port = serialPorts.ports[i];
|
||||
printf("%ls: Description = %ls, Location = %ls\n", port->portPath, port->friendlyName, port->portLocation);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -85,13 +85,15 @@ public class SerialPortTest
|
|||
{
|
||||
System.out.println("\nUsing Library Version v" + SerialPort.getVersion());
|
||||
SerialPort[] ports = SerialPort.getCommPorts();
|
||||
System.out.println("\nAvailable Ports (First Try):\n");
|
||||
System.out.println("\nAvailable Ports:\n");
|
||||
for (int i = 0; i < ports.length; ++i)
|
||||
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription());
|
||||
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation());
|
||||
System.out.println("Re-enumerating ports again in 5 seconds...\n");
|
||||
try { Thread.sleep(5000); } catch (Exception e) {}
|
||||
ports = SerialPort.getCommPorts();
|
||||
System.out.println("\nAvailable Ports (Second Try):\n");
|
||||
System.out.println("Available Ports:\n");
|
||||
for (int i = 0; i < ports.length; ++i)
|
||||
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription());
|
||||
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation());
|
||||
SerialPort ubxPort;
|
||||
System.out.print("\nChoose your desired serial port or enter -1 to specify a port directly: ");
|
||||
int serialPortChoice = 0;
|
||||
|
@ -147,6 +149,10 @@ public class SerialPortTest
|
|||
} catch (Exception e) { e.printStackTrace(); }
|
||||
System.out.println("\nSetting read timeout mode to semi-blocking with no timeout");
|
||||
ubxPort.setComPortTimeouts(SerialPort.TIMEOUT_READ_SEMI_BLOCKING, 0, 0);
|
||||
System.out.println("\nWaiting for available bytes to read...");
|
||||
while (ubxPort.bytesAvailable() == 0);
|
||||
System.out.println("Available: " + ubxPort.bytesAvailable());
|
||||
System.out.println("Flushing read buffers: " + ubxPort.flushIOBuffers());
|
||||
try
|
||||
{
|
||||
for (int i = 0; i < 3; ++i)
|
||||
|
|
Loading…
Reference in New Issue