From 2058f5b69e574c92719ff09a54ed1eba10138220 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 25 Jan 2023 19:42:23 -0600 Subject: [PATCH] hidapi wrapper devel test --- .../HyperXQuadcastSController.cpp | 23 +- .../HyperXQuadcastSController.h | 32 +-- .../HyperXQuadcastSControllerDetect.cpp | 152 +---------- Detector.h | 43 ++-- DeviceDetector.h | 9 + OpenRGB.pro | 3 + ResourceManager.cpp | 72 ++++++ ResourceManager.h | 34 ++- hidapi_wrapper/hidapi_wrapper.cpp | 240 ++++++++++++++++++ hidapi_wrapper/hidapi_wrapper.h | 51 ++++ 10 files changed, 447 insertions(+), 212 deletions(-) create mode 100644 hidapi_wrapper/hidapi_wrapper.cpp create mode 100644 hidapi_wrapper/hidapi_wrapper.h diff --git a/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp b/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp index 14ec6e5d3..ed357581f 100644 --- a/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp +++ b/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp @@ -8,14 +8,14 @@ \*-----------------------------------------*/ #include "HyperXQuadcastSController.h" -HyperXQuadcastSController::HyperXQuadcastSController(hid_device* dev_handle, HXQS_HIDAPI_WRAPPER wrapper, std::string path) +HyperXQuadcastSController::HyperXQuadcastSController(hidapi_wrapper hid_wrapper, hid_device* dev_handle, std::string path) { - hidapi_wrapper = wrapper; - dev = dev_handle; - location = path; + wrapper = hid_wrapper; + dev = dev_handle; + location = path; wchar_t serial_string[128]; - int ret = wrapper.get_serial_num_string(dev, serial_string, 128); + int ret = wrapper.hid_get_serial_num_string(dev, serial_string, 128); if(ret != 0) { @@ -30,10 +30,9 @@ HyperXQuadcastSController::HyperXQuadcastSController(hid_device* dev_handle, HXQ HyperXQuadcastSController::~HyperXQuadcastSController() { - if(dev) { - hidapi_wrapper.close(dev); + wrapper.hid_close(dev); } } @@ -97,7 +96,7 @@ void HyperXQuadcastSController::SaveColors(std::vector colors, unsigne } std::this_thread::sleep_for(15ms); - res = hidapi_wrapper.send_feature_report(dev,color,HXQS_PACKET_SIZE); + res = wrapper.hid_send_feature_report(dev,color,HXQS_PACKET_SIZE); } /*---------------------------------------------------------*\ @@ -156,7 +155,7 @@ void HyperXQuadcastSController::SendDirect(std::vector colors) lock.lock(); - res = hidapi_wrapper.send_feature_report(dev, buffer, HXQS_PACKET_SIZE); + res = wrapper.hid_send_feature_report(dev, buffer, HXQS_PACKET_SIZE); std::this_thread::sleep_for(15ms); SendToRegister(0xF2, 0, 1); @@ -179,7 +178,7 @@ void HyperXQuadcastSController::SendEOT(uint8_t frame_count) buffer[0x3F] = 0xAA; buffer[0x40] = 0x55; - int result = hidapi_wrapper.send_feature_report(dev,buffer,HXQS_PACKET_SIZE); + int result = wrapper.hid_send_feature_report(dev,buffer,HXQS_PACKET_SIZE); LOG_DEBUG("[HyperX Quadcast S] SendEOT with frame count %02X wrote %d bytes", frame_count, result); std::this_thread::sleep_for(15ms); } @@ -197,10 +196,10 @@ void HyperXQuadcastSController::SendToRegister(uint8_t reg, uint8_t param1, uint buffer[0x08] = param1; buffer[0x09] = param2; - int result = hidapi_wrapper.send_feature_report(dev, buffer, HXQS_PACKET_SIZE); + int result = wrapper.hid_send_feature_report(dev, buffer, HXQS_PACKET_SIZE); if(result < 0) { - LOG_ERROR("[HyperX Quadcast S] SendToRegister failed: %ls", hidapi_wrapper.error(dev)); + LOG_ERROR("[HyperX Quadcast S] SendToRegister failed: %ls", wrapper.hid_error(dev)); } else { diff --git a/Controllers/HyperXQuadcastController/HyperXQuadcastSController.h b/Controllers/HyperXQuadcastController/HyperXQuadcastSController.h index b8cc0977c..3cf326646 100644 --- a/Controllers/HyperXQuadcastController/HyperXQuadcastSController.h +++ b/Controllers/HyperXQuadcastController/HyperXQuadcastSController.h @@ -9,43 +9,17 @@ #pragma once #include -#include +#include "hidapi_wrapper.h" #include "LogManager.h" #include "RGBController.h" #define HXQS_PACKET_SIZE 64 + 1 #define HXQS_FRAME_SIZE 8 -// wrapper typedefs -typedef int (*HXQS_Report_Send_t)(hid_device*, const unsigned char*, size_t); -typedef int (*HXQS_Report_Get_t)(hid_device*, unsigned char*, size_t); -typedef int (*HXQS_Get_Serial_t)(hid_device*, wchar_t*, size_t); -typedef hid_device* (*HXQS_hid_open_path_t)(const char*); -typedef hid_device_info* (*HXQS_hid_enumerate_t) (unsigned short, unsigned short); -typedef void (*HXQS_hid_free_enumeration_t)(hid_device_info*); -typedef void (*HXQS_hid_close_t)(hid_device*); -typedef const wchar_t* (*HXQS_hid_error_t) (hid_device*); - -/*----------------------------------------------------*\ -| See comment at top of HyperXQuadcastSDetect.cpp for | -| details about the hidapi wrapper for this device | -\*----------------------------------------------------*/ -struct HXQS_HIDAPI_WRAPPER { - void* dyn_handle; - HXQS_Report_Send_t send_feature_report; - HXQS_Report_Get_t get_feature_report; - HXQS_Get_Serial_t get_serial_num_string; - HXQS_hid_open_path_t open_path; - HXQS_hid_enumerate_t enumerate; - HXQS_hid_free_enumeration_t free_enumeration; - HXQS_hid_close_t close; - HXQS_hid_error_t error; -}; - class HyperXQuadcastSController { public: - HyperXQuadcastSController(hid_device* dev, HXQS_HIDAPI_WRAPPER wrapper, std::string path); + HyperXQuadcastSController(hidapi_wrapper hid_wrapper, hid_device* dev, std::string path); ~HyperXQuadcastSController(); std::string GetDeviceLocation(); @@ -55,11 +29,11 @@ public: void SaveColors(std::vector colors, unsigned int num_frames); private: + hidapi_wrapper wrapper; hid_device* dev; std::string location; std::string serial_number; std::mutex lock; - HXQS_HIDAPI_WRAPPER hidapi_wrapper; void SendEOT(uint8_t frame_count); void SendToRegister(uint8_t reg, uint8_t param1, uint8_t param2); diff --git a/Controllers/HyperXQuadcastController/HyperXQuadcastSControllerDetect.cpp b/Controllers/HyperXQuadcastController/HyperXQuadcastSControllerDetect.cpp index 30c79ad0f..80ebb9905 100644 --- a/Controllers/HyperXQuadcastController/HyperXQuadcastSControllerDetect.cpp +++ b/Controllers/HyperXQuadcastController/HyperXQuadcastSControllerDetect.cpp @@ -14,11 +14,7 @@ #include #include -#ifdef __linux__ -#include -#endif - -#include +#include "hidapi_wrapper.h" /*-----------------------------------------------------*\ | HyperX microphone vendor and product IDs | @@ -33,147 +29,17 @@ const char* name = "HyperX Quadcast S"; -#ifdef __linux__ -void FindAndAddHyperXQuadcastSDevice(unsigned int vid, unsigned int pid, - HXQS_HIDAPI_WRAPPER wrapper, - std::vector& rgb_controllers) +void DetectHyperXQuadcastSControllers(hidapi_wrapper wrapper, hid_device_info* info, const std::string& name) { - std::string path; + hid_device* dev = wrapper.hid_open_path(info->path); - hid_device_info* devs = NULL; - hid_device *dev = NULL; - - HyperXQuadcastSController* controller; - RGBController_HyperXQuadcastS* rgb_controller; - - /*-----------------------------------------*\ - | Iterate over devices with corresponding | - | VID and PID and check if there is one | - | with interface 0 as that is what we use | - \*-----------------------------------------*/ - if(!(devs = wrapper.enumerate(vid, pid))) - { - LOG_DEBUG("[%s] Dynamic call to hid_enumerate failed or couldn't find a device (Linux only)", name); - return; - } - - hid_device_info *curr = devs; - while(curr) - { - if(curr->interface_number == 0) - { - path = curr->path; - LOG_DEBUG("[%s] Found device with correct 0 interface (Linux only): %s", name, path.c_str()); - break; - } - curr = curr->next; - } - - wrapper.free_enumeration(devs); - - if(!curr) - { - LOG_ERROR("[%s] Unable to find device with 0 interface (Linux only)", name); - return; - } - - - if(!(dev = wrapper.open_path(path.c_str()))) - { - LOG_ERROR("[%s] Dynamic call to hid_open_path failed (Linux only)", name); - return; - } - - LOG_DEBUG("[%s] Sucessfully opened device as a hidapi_device (Linux only)", name); - - - controller = new HyperXQuadcastSController(dev, wrapper, path); - rgb_controller = new RGBController_HyperXQuadcastS(controller); - - rgb_controller->name = name; - rgb_controllers.push_back(rgb_controller); -} - -void DetectHyperXQuadcastSControllers(std::vector& rgb_controllers) -{ - /*-----------------------------------------*\ - | Dynamically load hidapi-libusb and setup | - | wrapper for Linux platforms | - \*-----------------------------------------*/ - void* dyn_handle = NULL; - HXQS_HIDAPI_WRAPPER wrapper; - - if(!(dyn_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND))) - { - LOG_ERROR("[%s] Couldn't dynamically load hidapi-libusb (Linux only): %s", name, dlerror()); - return; - } - - wrapper = - { - .dyn_handle = dyn_handle, - .send_feature_report = (HXQS_Report_Send_t) dlsym(dyn_handle,"hid_send_feature_report"), - .get_feature_report = (HXQS_Report_Get_t) dlsym(dyn_handle,"hid_get_feature_report"), - .get_serial_num_string = (HXQS_Get_Serial_t) dlsym(dyn_handle,"hid_get_serial_number_string"), - .open_path = (HXQS_hid_open_path_t) dlsym(dyn_handle,"hid_open_path"), - .enumerate = (HXQS_hid_enumerate_t) dlsym(dyn_handle,"hid_enumerate"), - .free_enumeration = (HXQS_hid_free_enumeration_t) dlsym(dyn_handle,"hid_free_enumeration"), - .close = (HXQS_hid_close_t) dlsym(dyn_handle,"hid_close"), - .error = (HXQS_hid_error_t) dlsym(dyn_handle,"hid_free_enumeration") - }; - - if(!(wrapper.send_feature_report && wrapper.get_feature_report && - wrapper.open_path && wrapper.enumerate && wrapper.free_enumeration && - wrapper.close && wrapper.error && wrapper.get_serial_num_string)) - { - LOG_ERROR("[%s] Couldn't dynamically load one of hidapi-libusb functions for the wrapper (Linux only)", name); - return; - } - - FindAndAddHyperXQuadcastSDevice(HYPERX_VID, HYPERX_QS_PID, wrapper, rgb_controllers); - FindAndAddHyperXQuadcastSDevice(HYPERX_HP_VID, HYPERX_QS_PID_HP_1, wrapper, rgb_controllers); - FindAndAddHyperXQuadcastSDevice(HYPERX_HP_VID, HYPERX_QS_PID_HP_2, wrapper, rgb_controllers); -} - -REGISTER_DETECTOR("HyperX Quadcast S", DetectHyperXQuadcastSControllers); -#else -void DetectHyperXQuadcastSControllers(hid_device_info* info, const std::string& name) -{ - hid_device *dev = hid_open_path(info->path); - - if(!dev) - { - LOG_ERROR("[%s] Unable to open device via hid_open_path(%s): %ls", name.c_str(), info->path, hid_error(dev)); - return; - } - - /*-----------------------------------------*\ - | Setup wrapper for Windows platforms just | - | using the already linked in hidapi | - | functions | - \*-----------------------------------------*/ - HXQS_HIDAPI_WRAPPER wrapper = - { - NULL, // dyn_handle - hid_send_feature_report, - hid_get_feature_report, - hid_get_serial_number_string, - hid_open_path, - hid_enumerate, - hid_free_enumeration, - hid_close, - hid_error - }; - - - HyperXQuadcastSController* controller = new HyperXQuadcastSController(dev, wrapper, info->path); + HyperXQuadcastSController* controller = new HyperXQuadcastSController(wrapper, dev, info->path); RGBController_HyperXQuadcastS *rgb_controller = new RGBController_HyperXQuadcastS(controller); + rgb_controller->name = name; - rgb_controller->name = name; ResourceManager::get()->RegisterRGBController(rgb_controller); - } -REGISTER_HID_DETECTOR_IPU("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_VID, HYPERX_QS_PID, 0, 0xFF90, 0xFF00); -REGISTER_HID_DETECTOR_IPU("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_HP_VID, HYPERX_QS_PID_HP_1, 0, 0xFF90, 0xFF00); -REGISTER_HID_DETECTOR_IPU("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_HP_VID, HYPERX_QS_PID_HP_2, 0, 0xFF90, 0xFF00); -#endif + +REGISTER_HID_WRAPPED_DETECTOR_IPU("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_VID, HYPERX_QS_PID, 0, 0xFF90, 0xFF00); +REGISTER_HID_WRAPPED_DETECTOR_IPU("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_HP_VID, HYPERX_QS_PID_HP_1, 0, 0xFF90, 0xFF00); +REGISTER_HID_WRAPPED_DETECTOR_IPU("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_HP_VID, HYPERX_QS_PID_HP_2, 0, 0xFF90, 0xFF00); diff --git a/Detector.h b/Detector.h index 85779604a..7f1f2e1a5 100644 --- a/Detector.h +++ b/Detector.h @@ -2,25 +2,26 @@ #include "DeviceDetector.h" -#define REGISTER_DETECTOR(name, func) static DeviceDetector device_detector_obj_##func(name, func) -#define REGISTER_I2C_DETECTOR(name, func) static I2CDeviceDetector device_detector_obj_##func(name, func) -#define REGISTER_I2C_PCI_DETECTOR(name, func, ven, dev, subven, subdev, addr) static I2CPCIDeviceDetector device_detector_obj_##ven##dev##subven##subdev##addr##func(name, func, ven, dev, subven, subdev, addr) -#define REGISTER_I2C_BUS_DETECTOR(func) static I2CBusDetector device_detector_obj_##func(func) -#define REGISTER_HID_DETECTOR(name, func, vid, pid) static HIDDeviceDetector device_detector_obj_##vid##pid(name, func, vid, pid, HID_INTERFACE_ANY, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) -#define REGISTER_HID_DETECTOR_I(name, func, vid, pid, interface) static HIDDeviceDetector device_detector_obj_##vid##pid##_##interface(name, func, vid, pid, interface, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) -#define REGISTER_HID_DETECTOR_IP(name, func, vid, pid, interface, page) static HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page(name, func, vid, pid, interface, page, HID_USAGE_ANY) -#define REGISTER_HID_DETECTOR_IPU(name, func, vid, pid, interface, page, usage) static HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page##_##usage(name, func, vid, pid, interface, page, usage) -#define REGISTER_HID_DETECTOR_P(name, func, vid, pid, page) static HIDDeviceDetector device_detector_obj_##vid##pid##__##page(name, func, vid, pid, HID_INTERFACE_ANY, page, HID_USAGE_ANY) -#define REGISTER_HID_DETECTOR_PU(name, func, vid, pid, page, usage) static HIDDeviceDetector device_detector_obj_##vid##pid##__##page##_##usage(name, func, vid, pid, HID_INTERFACE_ANY, page, usage) -#define REGISTER_DYNAMIC_DETECTOR(name, func) static DynamicDetector device_detector_obj_##func(name, func) -#define REGISTER_PRE_DETECTION_HOOK(func) static PreDetectionHook device_detector_obj_##func(func) +#define REGISTER_DETECTOR(name, func) static DeviceDetector device_detector_obj_##func(name, func) +#define REGISTER_I2C_DETECTOR(name, func) static I2CDeviceDetector device_detector_obj_##func(name, func) +#define REGISTER_I2C_PCI_DETECTOR(name, func, ven, dev, subven, subdev, addr) static I2CPCIDeviceDetector device_detector_obj_##ven##dev##subven##subdev##addr##func(name, func, ven, dev, subven, subdev, addr) +#define REGISTER_I2C_BUS_DETECTOR(func) static I2CBusDetector device_detector_obj_##func(func) +#define REGISTER_HID_DETECTOR(name, func, vid, pid) static HIDDeviceDetector device_detector_obj_##vid##pid(name, func, vid, pid, HID_INTERFACE_ANY, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) +#define REGISTER_HID_DETECTOR_I(name, func, vid, pid, interface) static HIDDeviceDetector device_detector_obj_##vid##pid##_##interface(name, func, vid, pid, interface, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) +#define REGISTER_HID_DETECTOR_IP(name, func, vid, pid, interface, page) static HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page(name, func, vid, pid, interface, page, HID_USAGE_ANY) +#define REGISTER_HID_DETECTOR_IPU(name, func, vid, pid, interface, page, usage) static HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page##_##usage(name, func, vid, pid, interface, page, usage) +#define REGISTER_HID_DETECTOR_P(name, func, vid, pid, page) static HIDDeviceDetector device_detector_obj_##vid##pid##__##page(name, func, vid, pid, HID_INTERFACE_ANY, page, HID_USAGE_ANY) +#define REGISTER_HID_DETECTOR_PU(name, func, vid, pid, page, usage) static HIDDeviceDetector device_detector_obj_##vid##pid##__##page##_##usage(name, func, vid, pid, HID_INTERFACE_ANY, page, usage) +#define REGISTER_HID_WRAPPED_DETECTOR_IPU(name, func, vid, pid, interface, page, usage) static HIDWrappedDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page##_##usage(name, func, vid, pid, interface, page, usage) +#define REGISTER_DYNAMIC_DETECTOR(name, func) static DynamicDetector device_detector_obj_##func(name, func) +#define REGISTER_PRE_DETECTION_HOOK(func) static PreDetectionHook device_detector_obj_##func(func) -#define REGISTER_DYNAMIC_I2C_DETECTOR(name, func) I2CDeviceDetector device_detector_obj_##func(name, func) -#define REGISTER_DYNAMIC_I2C_PCI_DETECTOR(name, func, ven, dev, subven, subdev, addr) I2CPCIDeviceDetector device_detector_obj_##ven##dev##subven##subdev##addr##func(name, func, ven, dev, subven, subdev, addr) -#define REGISTER_DYNAMIC_I2C_BUS_DETECTOR(func) I2CBusDetector device_detector_obj_##func(func) -#define REGISTER_DYNAMIC_HID_DETECTOR(name, func, vid, pid) HIDDeviceDetector device_detector_obj_##vid##pid(name, func, vid, pid, HID_INTERFACE_ANY, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) -#define REGISTER_DYNAMIC_HID_DETECTOR_I(name, func, vid, pid, interface) HIDDeviceDetector device_detector_obj_##vid##pid##_##interface(name, func, vid, pid, interface, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) -#define REGISTER_DYNAMIC_HID_DETECTOR_IP(name, func, vid, pid, interface, page) HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page(name, func, vid, pid, interface, page, HID_USAGE_ANY) -#define REGISTER_DYNAMIC_HID_DETECTOR_IPU(name, func, vid, pid, interface, page, usage) HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page##_##usage(name, func, vid, pid, interface, page, usage) -#define REGISTER_DYNAMIC_HID_DETECTOR_P(name, func, vid, pid, page) HIDDeviceDetector device_detector_obj_##vid##pid##__##page(name, func, vid, pid, HID_INTERFACE_ANY, page, HID_USAGE_ANY) -#define REGISTER_DYNAMIC_HID_DETECTOR_PU(name, func, vid, pid, page, usage) HIDDeviceDetector device_detector_obj_##vid##pid##__##page##_##usage(name, func, vid, pid, HID_INTERFACE_ANY, page, usage) +#define REGISTER_DYNAMIC_I2C_DETECTOR(name, func) I2CDeviceDetector device_detector_obj_##func(name, func) +#define REGISTER_DYNAMIC_I2C_PCI_DETECTOR(name, func, ven, dev, subven, subdev, addr) I2CPCIDeviceDetector device_detector_obj_##ven##dev##subven##subdev##addr##func(name, func, ven, dev, subven, subdev, addr) +#define REGISTER_DYNAMIC_I2C_BUS_DETECTOR(func) I2CBusDetector device_detector_obj_##func(func) +#define REGISTER_DYNAMIC_HID_DETECTOR(name, func, vid, pid) HIDDeviceDetector device_detector_obj_##vid##pid(name, func, vid, pid, HID_INTERFACE_ANY, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) +#define REGISTER_DYNAMIC_HID_DETECTOR_I(name, func, vid, pid, interface) HIDDeviceDetector device_detector_obj_##vid##pid##_##interface(name, func, vid, pid, interface, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) +#define REGISTER_DYNAMIC_HID_DETECTOR_IP(name, func, vid, pid, interface, page) HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page(name, func, vid, pid, interface, page, HID_USAGE_ANY) +#define REGISTER_DYNAMIC_HID_DETECTOR_IPU(name, func, vid, pid, interface, page, usage) HIDDeviceDetector device_detector_obj_##vid##pid##_##interface##_##page##_##usage(name, func, vid, pid, interface, page, usage) +#define REGISTER_DYNAMIC_HID_DETECTOR_P(name, func, vid, pid, page) HIDDeviceDetector device_detector_obj_##vid##pid##__##page(name, func, vid, pid, HID_INTERFACE_ANY, page, HID_USAGE_ANY) +#define REGISTER_DYNAMIC_HID_DETECTOR_PU(name, func, vid, pid, page, usage) HIDDeviceDetector device_detector_obj_##vid##pid##__##page##_##usage(name, func, vid, pid, HID_INTERFACE_ANY, page, usage) diff --git a/DeviceDetector.h b/DeviceDetector.h index 280376ae8..6d40d9960 100644 --- a/DeviceDetector.h +++ b/DeviceDetector.h @@ -51,6 +51,15 @@ public: } }; +class HIDWrappedDeviceDetector +{ +public: + HIDWrappedDeviceDetector(std::string name, HIDWrappedDeviceDetectorFunction detector, uint16_t vid, uint16_t pid, int64_t interface, int usage_page, int usage) + { + ResourceManager::get()->RegisterHIDWrappedDeviceDetector(name, detector, vid, pid, interface, usage_page, usage); + } +}; + class DynamicDetector { public: diff --git a/OpenRGB.pro b/OpenRGB.pro index 63f46a3fb..7218e9786 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -68,6 +68,7 @@ INCLUDEPATH += dependencies/libe131/src/ \ dependencies/libcmmk/include/ \ dependencies/mdns \ + hidapi_wrapper/ \ i2c_smbus/ \ i2c_tools/ \ net_port/ \ @@ -206,6 +207,7 @@ HEADERS += qt/OpenRGBDeviceInfoPage.h \ qt/OpenRGBDevicePage.h \ qt/OpenRGBDialog.h \ + hidapi_wrapper/hidapi_wrapper.h \ i2c_smbus/i2c_smbus.h \ i2c_tools/i2c_tools.h \ net_port/net_port.h \ @@ -736,6 +738,7 @@ SOURCES += qt/OpenRGBDeviceInfoPage.cpp \ qt/OpenRGBDevicePage.cpp \ qt/OpenRGBDialog.cpp \ + hidapi_wrapper/hidapi_wrapper.cpp \ i2c_smbus/i2c_smbus.cpp \ i2c_tools/i2c_tools.cpp \ net_port/net_port.cpp \ diff --git a/ResourceManager.cpp b/ResourceManager.cpp index 19ad07190..bfa8a58f4 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -265,6 +265,26 @@ void ResourceManager::RegisterHIDDeviceDetector(std::string name, hid_device_detectors.push_back(block); } +void ResourceManager::RegisterHIDWrappedDeviceDetector(std::string name, + HIDWrappedDeviceDetectorFunction detector, + uint16_t vid, + uint16_t pid, + int interface, + int usage_page, + int usage) +{ + HIDWrappedDeviceDetectorBlock block; + + block.name = name; + block.address = (vid << 16) | pid; + block.function = detector; + block.interface = interface; + block.usage_page = usage_page; + block.usage = usage; + + hid_wrapped_device_detectors.push_back(block); +} + void ResourceManager::RegisterDynamicDetector(std::string name, DynamicDetectorFunction detector) { dynamic_detector_strings.push_back(name); @@ -1203,6 +1223,58 @@ void ResourceManager::DetectDevicesThreadFunction() } } + /*-----------------------------------------------------------------------------*\ + | Loop through all available wrapped HID detectors. If all required | + | information matches, run the detector | + \*-----------------------------------------------------------------------------*/ + for(unsigned int hid_detector_idx = 0; hid_detector_idx < hid_wrapped_device_detectors.size() && detection_is_required.load(); hid_detector_idx++) + { + if(( ( hid_wrapped_device_detectors[hid_detector_idx].address == addr ) ) +#ifdef USE_HID_USAGE + && ( ( hid_wrapped_device_detectors[hid_detector_idx].usage_page == HID_USAGE_PAGE_ANY ) + || ( hid_wrapped_device_detectors[hid_detector_idx].usage_page == current_hid_device->usage_page ) ) + && ( ( hid_wrapped_device_detectors[hid_detector_idx].usage == HID_USAGE_ANY ) + || ( hid_wrapped_device_detectors[hid_detector_idx].usage == current_hid_device->usage ) ) + && ( ( hid_wrapped_device_detectors[hid_detector_idx].interface == HID_INTERFACE_ANY ) + || ( hid_wrapped_device_detectors[hid_detector_idx].interface == current_hid_device->interface_number ) ) +#else + && ( ( hid_wrapped_device_detectors[hid_detector_idx].interface == HID_INTERFACE_ANY ) + || ( hid_wrapped_device_detectors[hid_detector_idx].interface == current_hid_device->interface_number ) ) +#endif + ) + { + detection_string = hid_wrapped_device_detectors[hid_detector_idx].name.c_str(); + + /*-------------------------------------------------*\ + | Check if this detector is enabled or needs to be | + | added to the settings list | + \*-------------------------------------------------*/ + bool this_device_enabled = true; + if(detector_settings.contains("detectors") && detector_settings["detectors"].contains(detection_string)) + { + this_device_enabled = detector_settings["detectors"][detection_string]; + } + + LOG_DEBUG("[%s] is %s", detection_string, ((this_device_enabled == true) ? "enabled" : "disabled")); + + if(this_device_enabled) + { + DetectionProgressChanged(); + + hid_wrapped_device_detectors[hid_detector_idx].function(default_wrapper, current_hid_device, hid_wrapped_device_detectors[hid_detector_idx].name); + + if(rgb_controllers_hw.size() != detection_prev_size) + { + LOG_VERBOSE("[%s] successfully added", detection_string); + } + else + { + LOG_INFO("[%s] is not initialized", detection_string); + } + } + } + } + /*-------------------------------------------------*\ | Update detection percent | \*-------------------------------------------------*/ diff --git a/ResourceManager.h b/ResourceManager.h index c0513e7ac..e81e1f3b9 100644 --- a/ResourceManager.h +++ b/ResourceManager.h @@ -17,6 +17,7 @@ #include #include +#include "hidapi_wrapper.h" #include "i2c_smbus.h" #include "NetworkClient.h" #include "NetworkServer.h" @@ -33,13 +34,14 @@ struct hid_device_info; -typedef std::function I2CBusDetectorFunction; -typedef std::function&)> DeviceDetectorFunction; -typedef std::function&)> I2CDeviceDetectorFunction; -typedef std::function I2CPCIDeviceDetectorFunction; -typedef std::function HIDDeviceDetectorFunction; -typedef std::function DynamicDetectorFunction; -typedef std::function PreDetectionHookFunction; +typedef std::function I2CBusDetectorFunction; +typedef std::function&)> DeviceDetectorFunction; +typedef std::function&)> I2CDeviceDetectorFunction; +typedef std::function I2CPCIDeviceDetectorFunction; +typedef std::function HIDDeviceDetectorFunction; +typedef std::function HIDWrappedDeviceDetectorFunction; +typedef std::function DynamicDetectorFunction; +typedef std::function PreDetectionHookFunction; typedef struct { @@ -51,6 +53,16 @@ typedef struct int usage; } HIDDeviceDetectorBlock; +typedef struct +{ + std::string name; + HIDWrappedDeviceDetectorFunction function; + unsigned int address; + int interface; + int usage_page; + int usage; +} HIDWrappedDeviceDetectorBlock; + typedef struct { std::string name; @@ -134,6 +146,13 @@ public: int interface = HID_INTERFACE_ANY, int usage_page = HID_USAGE_PAGE_ANY, int usage = HID_USAGE_ANY); + void RegisterHIDWrappedDeviceDetector (std::string name, + HIDWrappedDeviceDetectorFunction detector, + uint16_t vid, + uint16_t pid, + int interface = HID_INTERFACE_ANY, + int usage_page = HID_USAGE_PAGE_ANY, + int usage = HID_USAGE_ANY); void RegisterDynamicDetector (std::string name, DynamicDetectorFunction detector); void RegisterPreDetectionHook (PreDetectionHookFunction hook); @@ -240,6 +259,7 @@ private: std::vector i2c_device_detector_strings; std::vector i2c_pci_device_detectors; std::vector hid_device_detectors; + std::vector hid_wrapped_device_detectors; std::vector dynamic_detectors; std::vector dynamic_detector_strings; std::vector pre_detection_hooks; diff --git a/hidapi_wrapper/hidapi_wrapper.cpp b/hidapi_wrapper/hidapi_wrapper.cpp new file mode 100644 index 000000000..df5054e20 --- /dev/null +++ b/hidapi_wrapper/hidapi_wrapper.cpp @@ -0,0 +1,240 @@ +/*-----------------------------------------*\ +| hidapi_wrapper.cpp | +| | +| Wrapper for hidapi that can select from | +| default or libusb backends on Linux | +| | +| Matt Silva (thesilvanator) 2022 | +| Adam Honse (calcprogrammer1) 2023 | +\*-----------------------------------------*/ + +#include +#include "LogManager.h" +#include "hidapi_wrapper.h" + +const hidapi_wrapper default_wrapper = +{ + NULL, + (hidapi_wrapper_send_feature_report) hid_send_feature_report, + (hidapi_wrapper_get_feature_report) hid_get_feature_report, + (hidapi_wrapper_get_serial_num_string) hid_get_serial_number_string, + (hidapi_wrapper_open_path) hid_open_path, + (hidapi_wrapper_enumerate) hid_enumerate, + (hidapi_wrapper_free_enumeration) hid_free_enumeration, + (hidapi_wrapper_close) hid_close, + (hidapi_wrapper_error) hid_error +}; + +// hidapi_wrapper hidapi_wrapper_create(hid_device_info* info) +// { +// hidapi_wrapper wrapper; + +// #if __linux__ +// hid_device * dev = NULL; +// hid_device_info * devs = NULL; +// std::string path; + +// void* dyn_handle = NULL; + +// /*-----------------------------------------*\ +// | Load the libhidapi-libusb library | +// \*-----------------------------------------*/ +// if(!(dyn_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND))) +// { +// return; +// } + +// /*-----------------------------------------*\ +// | Iterate over devices with corresponding | +// | VID and PID and check if there is one | +// | with interface 0 as that is what we use | +// \*-----------------------------------------*/ +// if(!(devs = wrapper.enumerate(vid, pid))) +// { +// LOG_DEBUG("[%s] Dynamic call to hid_enumerate failed or couldn't find a device (Linux only)", name); +// return; +// } + +// hid_device_info *curr = devs; +// while(curr) +// { +// if(curr->interface_number == 0) +// { +// path = curr->path; +// LOG_DEBUG("[%s] Found device with correct 0 interface (Linux only): %s", name, path.c_str()); +// break; +// } +// curr = curr->next; +// } + +// wrapper.free_enumeration(devs); + +// if(!curr) +// { +// LOG_ERROR("[%s] Unable to find device with 0 interface (Linux only)", name); +// return; +// } + + +// if(!(dev = wrapper.open_path(path.c_str()))) +// { +// LOG_ERROR("[%s] Dynamic call to hid_open_path failed (Linux only)", name); +// return; +// } + +// LOG_DEBUG("[%s] Sucessfully opened device as a hidapi_device (Linux only)", name); + +// wrapper = +// { +// .dyn_handle = dyn_handle, +// .hid_send_feature_report = (hidapi_wrapper_send_feature_report) dlsym(dyn_handle,"hid_send_feature_report"), +// .hid_get_feature_report = (hidapi_wrapper_get_feature_report) dlsym(dyn_handle,"hid_get_feature_report"), +// .hid_get_serial_num_string = (hidapi_wrapper_get_serial_num_string) dlsym(dyn_handle,"hid_get_serial_number_string"), +// .hid_open_path = (hidapi_wrapper_open_path) dlsym(dyn_handle,"hid_open_path"), +// .hid_enumerate = (hidapi_wrapper_enumerate) dlsym(dyn_handle,"hid_enumerate"), +// .hid_free_enumeration = (hidapi_wrapper_free_enumeration) dlsym(dyn_handle,"hid_free_enumeration"), +// .hid_close = (hidapi_wrapper_close) dlsym(dyn_handle,"hid_close"), +// .hid_error = (hidapi_wrapper_error) dlsym(dyn_handle,"hid_free_enumeration") +// }; +// #else +// hid_device *dev = hid_open_path(info->path); + +// if(!dev) +// { +// LOG_ERROR("[%s] Unable to open device via hid_open_path(%s): %ls", name.c_str(), info->path, hid_error(dev)); +// return; +// } + +// /*-----------------------------------------*\ +// | Setup wrapper for Windows platforms just | +// | using the already linked in hidapi | +// | functions | +// \*-----------------------------------------*/ +// wrapper = +// { +// .dyn_handle = NULL, +// .hid_send_feature_report = (hidapi_wrapper_send_feature_report) hid_send_feature_report, +// .hid_get_feature_report = (hidapi_wrapper_get_feature_report) hid_get_feature_report, +// .hid_get_serial_num_string = (hidapi_wrapper_get_serial_num_string) hid_get_serial_number_string, +// .hid_open_path = (hidapi_wrapper_open_path) hid_open_path, +// .hid_enumerate = (hidapi_wrapper_enumerate) hid_enumerate, +// .hid_free_enumeration = (hidapi_wrapper_free_enumeration) hid_free_enumeration, +// .hid_close = (hidapi_wrapper_close) hid_close, +// .hid_error = (hidapi_wrapper_error) hid_error +// }; +// #endif + +// return wrapper; +// } + + + + + + + + + + + +// #ifdef __linux__ +// void FindAndAddHyperXQuadcastSDevice(unsigned int vid, unsigned int pid, +// HXQS_HIDAPI_WRAPPER wrapper, +// std::vector& rgb_controllers) +// { +// std::string path; + +// hid_device_info* devs = NULL; +// hid_device *dev = NULL; + +// HyperXQuadcastSController* controller; +// RGBController_HyperXQuadcastS* rgb_controller; + +// /*-----------------------------------------*\ +// | Iterate over devices with corresponding | +// | VID and PID and check if there is one | +// | with interface 0 as that is what we use | +// \*-----------------------------------------*/ +// if(!(devs = wrapper.enumerate(vid, pid))) +// { +// LOG_DEBUG("[%s] Dynamic call to hid_enumerate failed or couldn't find a device (Linux only)", name); +// return; +// } + +// hid_device_info *curr = devs; +// while(curr) +// { +// if(curr->interface_number == 0) +// { +// path = curr->path; +// LOG_DEBUG("[%s] Found device with correct 0 interface (Linux only): %s", name, path.c_str()); +// break; +// } +// curr = curr->next; +// } + +// wrapper.free_enumeration(devs); + +// if(!curr) +// { +// LOG_ERROR("[%s] Unable to find device with 0 interface (Linux only)", name); +// return; +// } + + +// if(!(dev = wrapper.open_path(path.c_str()))) +// { +// LOG_ERROR("[%s] Dynamic call to hid_open_path failed (Linux only)", name); +// return; +// } + +// LOG_DEBUG("[%s] Sucessfully opened device as a hidapi_device (Linux only)", name); + + +// controller = new HyperXQuadcastSController(dev, wrapper, path); +// rgb_controller = new RGBController_HyperXQuadcastS(controller); + +// rgb_controller->name = name; +// rgb_controllers.push_back(rgb_controller); +// } + +// void DetectHyperXQuadcastSControllers(std::vector& rgb_controllers) +// { +// /*-----------------------------------------*\ +// | Dynamically load hidapi-libusb and setup | +// | wrapper for Linux platforms | +// \*-----------------------------------------*/ +// void* dyn_handle = NULL; +// HXQS_HIDAPI_WRAPPER wrapper; + +// if(!(dyn_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND))) +// { +// LOG_ERROR("[%s] Couldn't dynamically load hidapi-libusb (Linux only): %s", name, dlerror()); +// return; +// } + +// wrapper = +// { +// .dyn_handle = dyn_handle, +// .send_feature_report = (HXQS_Report_Send_t) dlsym(dyn_handle,"hid_send_feature_report"), +// .get_feature_report = (HXQS_Report_Get_t) dlsym(dyn_handle,"hid_get_feature_report"), +// .get_serial_num_string = (HXQS_Get_Serial_t) dlsym(dyn_handle,"hid_get_serial_number_string"), +// .open_path = (HXQS_hid_open_path_t) dlsym(dyn_handle,"hid_open_path"), +// .enumerate = (HXQS_hid_enumerate_t) dlsym(dyn_handle,"hid_enumerate"), +// .free_enumeration = (HXQS_hid_free_enumeration_t) dlsym(dyn_handle,"hid_free_enumeration"), +// .close = (HXQS_hid_close_t) dlsym(dyn_handle,"hid_close"), +// .error = (HXQS_hid_error_t) dlsym(dyn_handle,"hid_free_enumeration") +// }; + +// if(!(wrapper.send_feature_report && wrapper.get_feature_report && +// wrapper.open_path && wrapper.enumerate && wrapper.free_enumeration && +// wrapper.close && wrapper.error && wrapper.get_serial_num_string)) +// { +// LOG_ERROR("[%s] Couldn't dynamically load one of hidapi-libusb functions for the wrapper (Linux only)", name); +// return; +// } + +// FindAndAddHyperXQuadcastSDevice(HYPERX_VID, HYPERX_QS_PID, wrapper, rgb_controllers); +// FindAndAddHyperXQuadcastSDevice(HYPERX_HP_VID, HYPERX_QS_PID_HP_1, wrapper, rgb_controllers); +// FindAndAddHyperXQuadcastSDevice(HYPERX_HP_VID, HYPERX_QS_PID_HP_2, wrapper, rgb_controllers); +// } diff --git a/hidapi_wrapper/hidapi_wrapper.h b/hidapi_wrapper/hidapi_wrapper.h new file mode 100644 index 000000000..b4f011842 --- /dev/null +++ b/hidapi_wrapper/hidapi_wrapper.h @@ -0,0 +1,51 @@ +/*-----------------------------------------*\ +| hidapi_wrapper.h | +| | +| Wrapper for hidapi that can select from | +| default or libusb backends on Linux | +| | +| Matt Silva (thesilvanator) 2022 | +| Adam Honse (calcprogrammer1) 2023 | +\*-----------------------------------------*/ + +#pragma once + +#include + +#ifdef __linux__ +#include +#endif + +/*-----------------------------------------------------*\ +| Type definitions for libhidapi function pointers | +\*-----------------------------------------------------*/ +typedef int (*hidapi_wrapper_send_feature_report) (hid_device*, const unsigned char*, size_t); +typedef int (*hidapi_wrapper_get_feature_report) (hid_device*, unsigned char*, size_t); +typedef int (*hidapi_wrapper_get_serial_num_string) (hid_device*, wchar_t*, size_t); +typedef hid_device* (*hidapi_wrapper_open_path) (const char*); +typedef hid_device_info* (*hidapi_wrapper_enumerate) (unsigned short, unsigned short); +typedef void (*hidapi_wrapper_free_enumeration) (hid_device_info*); +typedef void (*hidapi_wrapper_close) (hid_device*); +typedef const wchar_t* (*hidapi_wrapper_error) (hid_device*); + +/*-----------------------------------------------------*\ +| See comment at top of HyperXQuadcastSDetect.cpp for | +| details about the hidapi wrapper for this device | +\*-----------------------------------------------------*/ +struct hidapi_wrapper +{ + void* dyn_handle; + hidapi_wrapper_send_feature_report hid_send_feature_report; + hidapi_wrapper_get_feature_report hid_get_feature_report; + hidapi_wrapper_get_serial_num_string hid_get_serial_num_string; + hidapi_wrapper_open_path hid_open_path; + hidapi_wrapper_enumerate hid_enumerate; + hidapi_wrapper_free_enumeration hid_free_enumeration; + hidapi_wrapper_close hid_close; + hidapi_wrapper_error hid_error; +}; + +/*-----------------------------------------------------*\ +| Define default wrapper as extern | +\*-----------------------------------------------------*/ +extern const hidapi_wrapper default_wrapper;