Implement the wrapper for Linux in ResourceManager, change IPU to I for HyperX Quadcast S, code cleanup

This commit is contained in:
Adam Honse 2023-01-25 19:42:23 -06:00
parent 45408ae159
commit 29d34f7768
11 changed files with 378 additions and 262 deletions

View file

@ -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;
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<RGBColor> 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 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<RGBColor> 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<RGBColor> 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<RGBColor> 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<RGBColor> 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;
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<RGBColor> 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<RGBColor> 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);
}

View file

@ -9,43 +9,17 @@
#pragma once
#include <string>
#include <hidapi/hidapi.h>
#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<RGBColor> 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);

View file

@ -14,11 +14,7 @@
#include <vector>
#include <LogManager.h>
#ifdef __linux__
#include <dlfcn.h>
#endif
#include <hidapi/hidapi.h>
#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<RGBController*>& 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;
}
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<RGBController*>& 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;
ResourceManager::get()->RegisterRGBController(rgb_controller);
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);

View file

@ -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();
}

View file

@ -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:

View file

@ -12,6 +12,8 @@
#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)

View file

@ -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:

View file

@ -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 \

View file

@ -23,6 +23,19 @@
#include <string>
#include <hidapi/hidapi.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
};
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 |
\*-------------------------------------------------*/

View file

@ -17,6 +17,7 @@
#include <thread>
#include <string>
#include "hidapi_wrapper.h"
#include "i2c_smbus.h"
#include "NetworkClient.h"
#include "NetworkServer.h"
@ -38,6 +39,7 @@ typedef std::function<void(std::vector<RGBController*>&)>
typedef std::function<void(std::vector<i2c_smbus_interface*>&)> I2CDeviceDetectorFunction;
typedef std::function<void(i2c_smbus_interface*, uint8_t, const std::string&)> I2CPCIDeviceDetectorFunction;
typedef std::function<void(hid_device_info*, const std::string&)> HIDDeviceDetectorFunction;
typedef std::function<void(hidapi_wrapper wrapper, hid_device_info*, const std::string&)> HIDWrappedDeviceDetectorFunction;
typedef std::function<void()> DynamicDetectorFunction;
typedef std::function<void()> PreDetectionHookFunction;
@ -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<std::string> i2c_device_detector_strings;
std::vector<I2CPCIDeviceDetectorBlock> i2c_pci_device_detectors;
std::vector<HIDDeviceDetectorBlock> hid_device_detectors;
std::vector<HIDWrappedDeviceDetectorBlock> hid_wrapped_device_detectors;
std::vector<DynamicDetectorFunction> dynamic_detectors;
std::vector<std::string> dynamic_detector_strings;
std::vector<PreDetectionHookFunction> pre_detection_hooks;

View file

@ -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 <hidapi/hidapi.h>
#ifdef __linux__
#include <dlfcn.h>
#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;
};