Add functions to get serial port path from USB VID/PID for both Windows and Linux. Use this function to automatically detect the presence of an NZXT Hue+.

This commit is contained in:
Adam Honse 2019-12-30 01:21:49 -06:00
parent bfd8030438
commit 5074a923d1
6 changed files with 266 additions and 65 deletions

View file

@ -0,0 +1,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <fstream>
#include <iostream>
#include <string>
std::string find_usb_serial_port(unsigned short vid, unsigned short pid);

View file

@ -0,0 +1,119 @@
#include "find_usb_serial_port.h"
#include <unistd.h>
#include <dirent.h>
/*---------------------------------------------------------------------*\
| |
| find_usb_serial_port |
| |
| This function returns the name of the first USB serial port matching|
| the given USB product and vendor ID. |
| |
| vid: Vendor ID code |
| pid: Product ID code |
| |
| returns: std::string containing port name "COMx" or "/dev/ttyX" |
| |
\*---------------------------------------------------------------------*/
std::string find_usb_serial_port(unsigned short vid, unsigned short pid)
{
std::string ret_string = "";
DIR* dir;
char symlink_path[1024] = {0};
struct dirent* ent;
char vid_pid[10] = {0}; //Store VID/PID
/*-----------------------------------------------------------------*\
| Open /sys/class/tty |
\*-----------------------------------------------------------------*/
dir = opendir("/sys/class/tty");
if(dir == NULL)
{
closedir(dir);
return ret_string;
}
/*-----------------------------------------------------------------*\
| Loop through all symlinks in /sys/class/tty directory to find |
| paths with "usb" in them. These links should have the USB device |
| index which can be used to find the VID/PID |
\*-----------------------------------------------------------------*/
ent = readdir(dir);
while(ent != NULL)
{
if(ent->d_type == DT_LNK)
{
char tty_path[1024];
strcpy(tty_path, "/sys/class/tty/");
strcat(tty_path, ent->d_name);
readlink(tty_path, symlink_path, 1024);
char * usb_string = strstr(symlink_path, "usb");
if(usb_string != NULL)
{
char * usb_dev = strstr(usb_string, "/");
usb_dev++;
usb_dev = strtok(usb_dev, "/");
char usb_path[1024];
strcpy(usb_path, "/sys/bus/usb/devices/");
strcat(usb_path, usb_dev);
char vendor_path[1024];
char product_path[1024];
strcpy(vendor_path, usb_path);
strcat(vendor_path, "/idVendor");
strcpy(product_path, usb_path);
strcat(product_path, "/idProduct");
std::ifstream vendor_file;
std::ifstream product_file;
std::string vendor_string;
std::string product_string;
vendor_file.open(vendor_path);
product_file.open(product_path);
std::getline(vendor_file, vendor_string);
std::getline(product_file, product_string);
snprintf(vid_pid, 10, "%04x", vid);
if(strcmp(vid_pid, vendor_string.c_str()) == 0)
{
snprintf(vid_pid, 10, "%04x", pid);
if(strcmp(vid_pid, product_string.c_str()) == 0)
{
char* port_string = NULL;
for(int i = strlen(tty_path); i > 0; i--)
{
if(tty_path[i] == '/')
{
port_string = &tty_path[i + 1];
break;
}
}
ret_string.append("/dev/");
ret_string.append(port_string);
return ret_string;
}
}
}
}
ent = readdir(dir);
}
return ret_string;
} /* find_usb_serial_port() */

View file

@ -0,0 +1,118 @@
#include "find_usb_serial_port.h"
#include <initguid.h>
#include <windows.h>
#include <Setupapi.h>
//Buffer length
#define BUFF_LEN 20
#pragma comment (lib, "Setupapi.lib")
#pragma comment(lib, "advapi32")
/*---------------------------------------------------------------------*\
| |
| find_usb_serial_port |
| |
| This function returns the name of the first USB serial port matching|
| the given USB product and vendor ID. |
| |
| vid: Vendor ID code |
| pid: Product ID code |
| |
| returns: std::string containing port name "COMx" or "/dev/ttyX" |
| |
\*---------------------------------------------------------------------*/
std::string find_usb_serial_port(unsigned short vid, unsigned short pid)
{
std::string ret_str = "";
HDEVINFO DeviceInfoSet;
DWORD DeviceIndex = 0;
SP_DEVINFO_DATA DeviceInfoData;
const char * DevEnum = "USB";
char ExpectedDeviceId[80] = {0}; //Store hardware id
char vid_pid[10] = {0}; //Store VID/PID
BYTE szBuffer[1024] = {0};
DEVPROPTYPE ulPropertyType;
DWORD dwSize = 0;
/*-----------------------------------------------------------------*\
| Create device hardware id |
| "vid_ABCD&pid_CDEF" |
\*-----------------------------------------------------------------*/
strcpy(ExpectedDeviceId, "vid_");
snprintf(vid_pid, 10, "%04X", vid);
strcat(ExpectedDeviceId, vid_pid);
strcat(ExpectedDeviceId, "&pid_");
snprintf(vid_pid, 10, "%04X", pid);
strcat(ExpectedDeviceId, vid_pid);
/*-----------------------------------------------------------------*\
| SetupDiGetClassDevs returns a handle to a device information set |
\*-----------------------------------------------------------------*/
DeviceInfoSet = SetupDiGetClassDevs( NULL, DevEnum, NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
if (DeviceInfoSet == INVALID_HANDLE_VALUE)
{
return false;
}
/*-----------------------------------------------------------------*\
| Set up Device Info Data |
\*-----------------------------------------------------------------*/
memset(&DeviceInfoData, 0, sizeof(SP_DEVINFO_DATA));
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
/*-----------------------------------------------------------------*\
| Receive information about an enumerated device |
\*-----------------------------------------------------------------*/
while (SetupDiEnumDeviceInfo( DeviceInfoSet, DeviceIndex, &DeviceInfoData))
{
DeviceIndex++;
/*-------------------------------------------------------------*\
| Retrieves a specified Plug and Play device property |
\*-------------------------------------------------------------*/
if (SetupDiGetDeviceRegistryProperty (DeviceInfoSet, &DeviceInfoData, SPDRP_HARDWAREID, &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize))
{
HKEY hDeviceRegistryKey;
hDeviceRegistryKey = SetupDiOpenDevRegKey(DeviceInfoSet, &DeviceInfoData,DICS_FLAG_GLOBAL, 0,DIREG_DEV, KEY_READ);
if (hDeviceRegistryKey == INVALID_HANDLE_VALUE)
{
break;
}
else
{
char pszPortName[BUFF_LEN];
DWORD dwSize = sizeof(pszPortName);
DWORD dwType = 0;
/*-----------------------------------------------------*\
| Read in the name of the port |
\*-----------------------------------------------------*/
if( (RegQueryValueEx(hDeviceRegistryKey,"PortName", NULL, &dwType, (LPBYTE) pszPortName, &dwSize) == ERROR_SUCCESS) && (dwType == REG_SZ))
{
if(strncmp(pszPortName, "COM", 3) == 0)
{
ret_str.append(pszPortName);
return ret_str;
}
}
// Close the key now that we are finished with it
RegCloseKey(hDeviceRegistryKey);
}
}
}
if (DeviceInfoSet)
{
SetupDiDestroyDeviceInfoList(DeviceInfoSet);
}
return ret_str;
} /* find_usb_serial_port() */