From 5074a923d1bda84e8b943a1ed1dd069db2c68c21 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Mon, 30 Dec 2019 01:21:49 -0600 Subject: [PATCH] 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+. --- .../HuePlusControllerDetect.cpp | 74 ++--------- .../RGBFusionControllerDetect.cpp | 7 ++ OpenRGB.pro | 3 + serial_port/find_usb_serial_port.h | 10 ++ serial_port/find_usb_serial_port_linux.cpp | 119 ++++++++++++++++++ serial_port/find_usb_serial_port_win.cpp | 118 +++++++++++++++++ 6 files changed, 266 insertions(+), 65 deletions(-) create mode 100644 serial_port/find_usb_serial_port.h create mode 100644 serial_port/find_usb_serial_port_linux.cpp create mode 100644 serial_port/find_usb_serial_port_win.cpp diff --git a/Controllers/HuePlusController/HuePlusControllerDetect.cpp b/Controllers/HuePlusController/HuePlusControllerDetect.cpp index 374b3ad3..1ed29429 100644 --- a/Controllers/HuePlusController/HuePlusControllerDetect.cpp +++ b/Controllers/HuePlusController/HuePlusControllerDetect.cpp @@ -1,20 +1,11 @@ #include "HuePlusController.h" #include "RGBController.h" #include "RGBController_HuePlus.h" +#include "find_usb_serial_port.h" #include -#include -#include -#include -#include -#include -#include -#include - -#ifndef WIN32 -#include -#include -#endif +#define NZXT_HUE_PLUS_VID 0x04D8 +#define NZXT_HUE_PLUS_PID 0x00DF /******************************************************************************************\ * * @@ -29,60 +20,13 @@ void DetectHuePlusControllers(std::vector &rgb_controllers) HuePlusController* new_hueplus; RGBController_HuePlus* new_controller; - //Get file path in executable directory - std::ifstream infile; - char filename[2048]; - char arg1[64]; - -#ifdef WIN32 - GetModuleFileName(NULL, filename, 2048); - strcpy(filename, std::string(filename).substr(0, std::string(filename).find_last_of("\\/")).c_str()); -#else - snprintf(arg1, 64, "/proc/%d/exe", getpid()); - readlink(arg1, filename, 1024); - strcpy(filename, std::string(filename).substr(0, std::string(filename).find_last_of("\\/")).c_str()); -#endif - - strcat(filename, "/settings.txt"); - - //Open settings file - infile.open(filename); - - if (infile.good()) + std::string portname = find_usb_serial_port(NZXT_HUE_PLUS_VID, NZXT_HUE_PLUS_PID); + if( portname != "" ) { - for (std::string line; std::getline(infile, line); ) - { - if (line == "") - { - continue; - } - if ((line[0] != ';') && (line[0] != '#') && (line[0] != '/')) - { - char * argument; - char * value; + new_hueplus = new HuePlusController(); + new_hueplus->Initialize((char *)portname.c_str()); - value = (char *)line.c_str(); - - argument = strtok_s(value, "=", &value); - - //Strip off new line characters if present - argument = strtok(argument, "\r\n"); - value = strtok(value, "\r\n"); - - if(argument) - { - if (strcmp(argument, "hueplus") == 0) - { - new_hueplus = new HuePlusController(); - new_hueplus->Initialize(value); - - new_controller = new RGBController_HuePlus(new_hueplus); - rgb_controllers.push_back(new_controller); - } - } - } - } + new_controller = new RGBController_HuePlus(new_hueplus); + rgb_controllers.push_back(new_controller); } - - } /* DetectHuePlusControllers() */ diff --git a/Controllers/RGBFusionController/RGBFusionControllerDetect.cpp b/Controllers/RGBFusionController/RGBFusionControllerDetect.cpp index 3e07db5c..201e15c1 100644 --- a/Controllers/RGBFusionController/RGBFusionControllerDetect.cpp +++ b/Controllers/RGBFusionController/RGBFusionControllerDetect.cpp @@ -24,6 +24,13 @@ bool TestForRGBFusionController(i2c_smbus_interface* bus, unsigned char address) if (res >= 0) { pass = true; + + res = bus->i2c_smbus_read_byte_data(address, 0xF2); + + if (res != 0xC4) + { + pass = false; + } } return(pass); diff --git a/OpenRGB.pro b/OpenRGB.pro index b012d752..86fb7162 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -85,6 +85,7 @@ HEADERS += \ net_port/net_port.h \ qt/OpenRGBDialog2.h \ qt/OpenRGBSystemInfoPage.h \ + serial_port/find_usb_serial_port.h \ serial_port/serial_port.h \ Controllers/AMDWraithPrismController/AMDWraithPrismController.h \ Controllers/AuraController/AuraController.h \ @@ -133,6 +134,7 @@ win32:SOURCES += \ i2c_smbus/i2c_smbus_i801.cpp \ i2c_smbus/i2c_smbus_nct6775.cpp \ i2c_smbus/i2c_smbus_piix4.cpp \ + serial_port/find_usb_serial_port_win.cpp \ wmi/wmi.cpp \ RGBController/AorusGPUDetect.cpp \ RGBController/RGBController_AorusGPU.cpp \ @@ -176,5 +178,6 @@ unix:LIBS += \ unix:SOURCES += \ i2c_smbus/i2c_smbus_linux.cpp \ + serial_port/find_usb_serial_port_linux.cpp \ RGBController/OpenRazerDetect.cpp \ RGBController/RGBController_OpenRazer.cpp \ diff --git a/serial_port/find_usb_serial_port.h b/serial_port/find_usb_serial_port.h new file mode 100644 index 00000000..7d651ca3 --- /dev/null +++ b/serial_port/find_usb_serial_port.h @@ -0,0 +1,10 @@ +#include +#include + +#include +#include +#include +#include +#include + +std::string find_usb_serial_port(unsigned short vid, unsigned short pid); \ No newline at end of file diff --git a/serial_port/find_usb_serial_port_linux.cpp b/serial_port/find_usb_serial_port_linux.cpp new file mode 100644 index 00000000..1eba333f --- /dev/null +++ b/serial_port/find_usb_serial_port_linux.cpp @@ -0,0 +1,119 @@ +#include "find_usb_serial_port.h" + +#include +#include + +/*---------------------------------------------------------------------*\ +| | +| 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() */ \ No newline at end of file diff --git a/serial_port/find_usb_serial_port_win.cpp b/serial_port/find_usb_serial_port_win.cpp new file mode 100644 index 00000000..75996939 --- /dev/null +++ b/serial_port/find_usb_serial_port_win.cpp @@ -0,0 +1,118 @@ +#include "find_usb_serial_port.h" + +#include +#include +#include + +//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() */ \ No newline at end of file