From 29d34f7768035adae607ce614493c632b9f4c160 Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Wed, 25 Jan 2023 19:42:23 -0600 Subject: [PATCH] Implement the wrapper for Linux in ResourceManager, change IPU to I for HyperX Quadcast S, code cleanup --- .../HyperXQuadcastSController.cpp | 83 +++---- .../HyperXQuadcastSController.h | 36 +-- .../HyperXQuadcastSControllerDetect.cpp | 157 +------------ .../RGBController_HyperXQuadcastS.cpp | 8 +- .../RGBController_HyperXQuadcastS.h | 6 - Detector.h | 44 ++-- DeviceDetector.h | 9 + OpenRGB.pro | 6 +- ResourceManager.cpp | 211 ++++++++++++++++++ ResourceManager.h | 34 ++- hidapi_wrapper/hidapi_wrapper.h | 46 ++++ 11 files changed, 378 insertions(+), 262 deletions(-) create mode 100644 hidapi_wrapper/hidapi_wrapper.h diff --git a/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp b/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp index 14ec6e5d..f950aef7 100644 --- a/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp +++ b/Controllers/HyperXQuadcastController/HyperXQuadcastSController.cpp @@ -6,16 +6,19 @@ | | | Matt Silva (thesilvanator) 2022 | \*-----------------------------------------*/ + #include "HyperXQuadcastSController.h" -HyperXQuadcastSController::HyperXQuadcastSController(hid_device* dev_handle, HXQS_HIDAPI_WRAPPER wrapper, std::string path) +using namespace std::chrono_literals; + +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 +33,9 @@ HyperXQuadcastSController::HyperXQuadcastSController(hid_device* dev_handle, HXQ HyperXQuadcastSController::~HyperXQuadcastSController() { - if(dev) { - hidapi_wrapper.close(dev); + wrapper.hid_close(dev); } } @@ -47,16 +49,12 @@ std::string HyperXQuadcastSController::GetSerialString() return serial_number; } - void HyperXQuadcastSController::SaveColors(std::vector colors, unsigned int num_frames) { - using namespace std::chrono_literals; - - int res; - unsigned int num_color_packets = 0; - unsigned int frame = 0; - unsigned char color[HXQS_PACKET_SIZE] = {0}; - unsigned char empty[HXQS_PACKET_SIZE] = {0}; + unsigned int num_color_packets = 0; + unsigned int frame = 0; + unsigned char color[HYPERX_QUADCAST_S_PACKET_SIZE] = {0}; + unsigned char empty[HYPERX_QUADCAST_S_PACKET_SIZE] = {0}; num_color_packets = num_frames/8; if(num_frames % 8) @@ -74,12 +72,12 @@ void HyperXQuadcastSController::SaveColors(std::vector colors, unsigne while(frame < num_frames) { - memset(color, 0, HXQS_PACKET_SIZE); + memset(color, 0, HYPERX_QUADCAST_S_PACKET_SIZE); unsigned int i = 0; while(i < 8 && frame < num_frames) { - int index = HXQS_FRAME_SIZE * i; + int index = HYPERX_QUADCAST_S_FRAME_SIZE * i; RGBColor top = colors[frame*2]; RGBColor bot = colors[frame*2 + 1]; @@ -97,7 +95,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); + wrapper.hid_send_feature_report(dev, color, HYPERX_QUADCAST_S_PACKET_SIZE); } /*---------------------------------------------------------*\ @@ -122,29 +120,33 @@ void HyperXQuadcastSController::SaveColors(std::vector colors, unsigne lock.unlock(); - // likes to have one temporary direct packet after the save for some reason + /*---------------------------------------------------------*\ + | Likes to have one temporary direct packet after the save | + | for some reason | + \*---------------------------------------------------------*/ SendDirect(colors); } void HyperXQuadcastSController::SendDirect(std::vector colors) { - using namespace std::chrono_literals; - + /*---------------------------------------------------------*\ + | Verify colors size | + \*---------------------------------------------------------*/ if(colors.size() != 2) { - LOG_ERROR("[HyperX Quadcast S] Unable to send direct packet, incorrect size: %d", colors.size()); return; } - int res; + int res; RGBColor c1 = colors[0]; RGBColor c2 = colors[1]; - uint8_t buffer[HXQS_PACKET_SIZE]; + uint8_t buffer[HYPERX_QUADCAST_S_PACKET_SIZE]; - // colour packet - memset(buffer,0,HXQS_PACKET_SIZE); + /*---------------------------------------------------------*\ + | Colour packet | + \*---------------------------------------------------------*/ + memset(buffer, 0, HYPERX_QUADCAST_S_PACKET_SIZE); - //buffer[0x00] = 0; //buffer requires 0 at index 0 as device does not use ReportIDs buffer[0x01] = 0x81; buffer[0x02] = RGBGetRValue(c1); buffer[0x03] = RGBGetGValue(c1); @@ -156,7 +158,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, HYPERX_QUADCAST_S_PACKET_SIZE); std::this_thread::sleep_for(15ms); SendToRegister(0xF2, 0, 1); @@ -166,12 +168,10 @@ void HyperXQuadcastSController::SendDirect(std::vector colors) void HyperXQuadcastSController::SendEOT(uint8_t frame_count) { - using namespace std::chrono_literals; - uint8_t buffer[HXQS_PACKET_SIZE]; + uint8_t buffer[HYPERX_QUADCAST_S_PACKET_SIZE]; - memset(buffer,0,HXQS_PACKET_SIZE); + memset(buffer, 0, HYPERX_QUADCAST_S_PACKET_SIZE); - //buffer[0x00] = 0; //buffer requires 0 at index 0 as device does not use ReportIDs buffer[0x01] = 0x08; buffer[0x3C] = 0x28; buffer[0x3D] = frame_count; @@ -179,32 +179,21 @@ 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); - LOG_DEBUG("[HyperX Quadcast S] SendEOT with frame count %02X wrote %d bytes", frame_count, result); + wrapper.hid_send_feature_report(dev, buffer, HYPERX_QUADCAST_S_PACKET_SIZE); std::this_thread::sleep_for(15ms); } void HyperXQuadcastSController::SendToRegister(uint8_t reg, uint8_t param1, uint8_t param2) { - using namespace std::chrono_literals; - uint8_t buffer[HXQS_PACKET_SIZE]; + uint8_t buffer[HYPERX_QUADCAST_S_PACKET_SIZE]; - memset(buffer,0,HXQS_PACKET_SIZE); + memset(buffer, 0, HYPERX_QUADCAST_S_PACKET_SIZE); - //buffer[0x00] = 0; //buffer requires 0 at index 0 as device does not use ReportIDs buffer[0x01] = 0x04; buffer[0x02] = reg; // 0xF2 Apply, 0x53 Save buffer[0x08] = param1; buffer[0x09] = param2; - int result = hidapi_wrapper.send_feature_report(dev, buffer, HXQS_PACKET_SIZE); - if(result < 0) - { - LOG_ERROR("[HyperX Quadcast S] SendToRegister failed: %ls", hidapi_wrapper.error(dev)); - } - else - { - LOG_DEBUG("[HyperX Quadcast S] SendToRegister %02X with P1 %02X P2 %02X wrote %d bytes", reg, param1, param2, result); - } + wrapper.hid_send_feature_report(dev, buffer, HYPERX_QUADCAST_S_PACKET_SIZE); std::this_thread::sleep_for(15ms); } diff --git a/Controllers/HyperXQuadcastController/HyperXQuadcastSController.h b/Controllers/HyperXQuadcastController/HyperXQuadcastSController.h index b8cc0977..18e96c76 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; -}; +#define HYPERX_QUADCAST_S_PACKET_SIZE 64 + 1 +#define HYPERX_QUADCAST_S_FRAME_SIZE 8 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 30c79ad0..0967b2e6 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 | @@ -31,149 +27,20 @@ #define HYPERX_QS_PID_HP_1 0x0F8B #define HYPERX_QS_PID_HP_2 0x068C -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))) + if(dev) { - LOG_DEBUG("[%s] Dynamic call to hid_enumerate failed or couldn't find a device (Linux only)", name); - return; + HyperXQuadcastSController* controller = new HyperXQuadcastSController(wrapper, dev, info->path); + RGBController_HyperXQuadcastS *rgb_controller = new RGBController_HyperXQuadcastS(controller); + rgb_controller->name = name; + + ResourceManager::get()->RegisterRGBController(rgb_controller); } - - 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); - RGBController_HyperXQuadcastS *rgb_controller = new RGBController_HyperXQuadcastS(controller); - - 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_I("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_VID, HYPERX_QS_PID, 0);//, 0xFF90, 0xFF00); +REGISTER_HID_WRAPPED_DETECTOR_I("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_HP_VID, HYPERX_QS_PID_HP_1, 0);//, 0xFF90, 0xFF00); +REGISTER_HID_WRAPPED_DETECTOR_I("HyperX Quadcast S", DetectHyperXQuadcastSControllers, HYPERX_HP_VID, HYPERX_QS_PID_HP_2, 0);//, 0xFF90, 0xFF00); diff --git a/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.cpp b/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.cpp index 6e42c936..236dfc1d 100644 --- a/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.cpp +++ b/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.cpp @@ -110,7 +110,9 @@ void RGBController_HyperXQuadcastS::SetupZones() void RGBController_HyperXQuadcastS::ResizeZone(int /*zone*/, int /*new_size*/) { - + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ } void RGBController_HyperXQuadcastS::DeviceUpdateLEDs() @@ -118,11 +120,11 @@ void RGBController_HyperXQuadcastS::DeviceUpdateLEDs() last_update_time = std::chrono::steady_clock::now(); controller->SendDirect(colors); } -void RGBController_HyperXQuadcastS::UpdateZoneLEDs(int zone) +void RGBController_HyperXQuadcastS::UpdateZoneLEDs(int /*zone*/) { DeviceUpdateLEDs(); } -void RGBController_HyperXQuadcastS::UpdateSingleLED(int led) +void RGBController_HyperXQuadcastS::UpdateSingleLED(int /*led*/) { DeviceUpdateLEDs(); } diff --git a/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.h b/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.h index b227d429..b6a03c9b 100644 --- a/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.h +++ b/Controllers/HyperXQuadcastController/RGBController_HyperXQuadcastS.h @@ -13,12 +13,6 @@ #include "RGBController.h" #include "HyperXQuadcastSController.h" -enum -{ - HXQS_MODE_DIRECT = 0, - HXQS_MODE_OFF = 1, -}; - class RGBController_HyperXQuadcastS : public RGBController { public: diff --git a/Detector.h b/Detector.h index 85779604..0aa73b2b 100644 --- a/Detector.h +++ b/Detector.h @@ -2,25 +2,27 @@ #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_I(name, func, vid, pid, interface) static HIDWrappedDeviceDetector device_detector_obj_##vid##pid##_##interface(name, func, vid, pid, interface, HID_USAGE_PAGE_ANY, HID_USAGE_ANY) +#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 280376ae..6d40d996 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 63f46a3f..587dddb4 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 \ @@ -741,8 +743,8 @@ SOURCES += net_port/net_port.cpp \ qt/DeviceView.cpp \ qt/OpenRGBDialog2.cpp \ - qt/OpenRGBElgatoKeyLightSettingsPage/OpenRGBElgatoKeyLightSettingsEntry.cpp \ - qt/OpenRGBElgatoKeyLightSettingsPage/OpenRGBElgatoKeyLightSettingsPage.cpp \ + qt/OpenRGBElgatoKeyLightSettingsPage/OpenRGBElgatoKeyLightSettingsEntry.cpp \ + qt/OpenRGBElgatoKeyLightSettingsPage/OpenRGBElgatoKeyLightSettingsPage.cpp \ qt/OpenRGBPluginContainer.cpp \ qt/OpenRGBPluginsPage/OpenRGBPluginsEntry.cpp \ qt/OpenRGBPluginsPage/OpenRGBPluginsList.cpp \ diff --git a/ResourceManager.cpp b/ResourceManager.cpp index 19ad0719..89dde34b 100644 --- a/ResourceManager.cpp +++ b/ResourceManager.cpp @@ -23,6 +23,19 @@ #include #include +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 +}; + ResourceManager* ResourceManager::instance; using namespace std::chrono_literals; @@ -265,6 +278,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 +1236,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 | \*-------------------------------------------------*/ @@ -1224,6 +1309,132 @@ void ResourceManager::DetectDevicesThreadFunction() hid_free_enumeration(hid_devices); } + /*-------------------------------------------------*\ + | Detect HID devices | + | | + | Reset current device pointer to first device | + \*-------------------------------------------------*/ +#ifdef __linux__ + LOG_INFO("------------------------------------------------------"); + LOG_INFO("| Detecting libusb HID devices |"); + LOG_INFO("------------------------------------------------------"); + + void * dyn_handle = NULL; + hidapi_wrapper wrapper; + + /*-------------------------------------------------*\ + | Load the libhidapi-libusb library | + \*-------------------------------------------------*/ + if(dyn_handle = dlopen("libhidapi-libusb.so", RTLD_NOW | RTLD_NODELETE | RTLD_DEEPBIND)) + { + /*-------------------------------------------------*\ + | Create a wrapper with the libusb functions | + \*-------------------------------------------------*/ + 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") + }; + + hid_devices = wrapper.hid_enumerate(0, 0); + + current_hid_device = hid_devices; + + /*-------------------------------------------------*\ + | Iterate through all devices in list and run | + | detectors | + \*-------------------------------------------------*/ + hid_device_count = 0; + + while(current_hid_device) + { + if(LogManager::get()->getLoglevel() >= LL_DEBUG) + { + const char* manu_name = wchar_to_char(current_hid_device->manufacturer_string); + const char* prod_name = wchar_to_char(current_hid_device->product_string); + LOG_DEBUG("[%04X:%04X U=%04X P=0x%04X I=%d] %-25s - %s", current_hid_device->vendor_id, current_hid_device->product_id, current_hid_device->usage, current_hid_device->usage_page, current_hid_device->interface_number, manu_name, prod_name); + } + detection_string = ""; + DetectionProgressChanged(); + + unsigned int addr = (current_hid_device->vendor_id << 16) | current_hid_device->product_id; + + /*-----------------------------------------------------------------------------*\ + | 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 ) ) + && ( ( 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 ) ) + ) + { + 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(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 | + \*-------------------------------------------------*/ + hid_device_count++; + + percent = (i2c_device_detectors.size() + i2c_pci_device_detectors.size() + hid_device_count) / percent_denominator; + + detection_percent = percent * 100.0f; + + /*-------------------------------------------------*\ + | Move on to the next HID device | + \*-------------------------------------------------*/ + current_hid_device = current_hid_device->next; + } + + /*-------------------------------------------------*\ + | Done using the device list, free it | + \*-------------------------------------------------*/ + wrapper.hid_free_enumeration(hid_devices); + } +#endif + /*-------------------------------------------------*\ | Detect other devices | \*-------------------------------------------------*/ diff --git a/ResourceManager.h b/ResourceManager.h index c0513e7a..e81e1f3b 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.h b/hidapi_wrapper/hidapi_wrapper.h new file mode 100644 index 00000000..85eb5f62 --- /dev/null +++ b/hidapi_wrapper/hidapi_wrapper.h @@ -0,0 +1,46 @@ +/*-----------------------------------------*\ +| 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; +};