From 41ac14dd41975701e67d0c7efdeb8f1c084ba693 Mon Sep 17 00:00:00 2001 From: Chris Date: Mon, 26 Jul 2021 00:08:33 +1000 Subject: [PATCH] Adding DEBUG logging & detection fixes to resolve #1592 + Logitech detection and set up includes debug logging for troubleshooting + Adding a pre check to LogitechLightspeedController::GetSerialString() * Rearranging check logic to ensure that all usages per device are bundled * Adding PID check to usage bundle to ensure we don't roll into the next device in hid_device_info - Code cleanup to remove dev_use1 post detection & decoupling the bundled usages for wired lightspeed devices * Changing wired lightspeed devices to REGISTER_HID_DETECTOR_IPU to target the correct FAP long message usage + Adding device validity check isValid() from @cheerpipe + Adding wireless check into connected() prior to initialising device + Adding the getDeviceFeatureList() back into the Logitech Lightspeed device set up + Changed getRGBconfig() for more robust detection + Adding Powerplay Mat virtual PID for Linux + Adding Logitech G733 for testing @ I=2 P=0xFF43 U=514 + Adding LOGITECH_POWERPLAY_MAT_VIRTUAL_PID to Linux detection + Adding LOGITECH_POWERPLAY_MAT_VIRTUAL_PID and LOGITECH_G733_PID to 60-openrgb.rules + Adding LOGITECH_DEVICE_TYPE mapping and extending validity to include new HEADSET type --- 60-openrgb.rules | 10 +- .../LogitechControllerDetect.cpp | 130 ++++++-- .../LogitechLightspeedController.cpp | 23 +- .../LogitechLightspeedController.h | 1 + .../LogitechProtocolCommon.cpp | 281 ++++++++++++------ .../LogitechProtocolCommon.h | 19 +- .../RGBController_LogitechLightspeed.cpp | 8 + 7 files changed, 337 insertions(+), 135 deletions(-) diff --git a/60-openrgb.rules b/60-openrgb.rules index 3f45325e..b11c9cde 100644 --- a/60-openrgb.rules +++ b/60-openrgb.rules @@ -370,7 +370,7 @@ SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c08b", TAG+="uacces SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c08d", TAG+="uaccess" SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="407f", TAG+="uaccess" SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c087", TAG+="uaccess" -SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="4070", TAG+="uaccess" +SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="4070", TAG+="uaccess" #G703 Virtual PID SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c081", TAG+="uaccess" SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="4053", TAG+="uaccess" SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c086", TAG+="uaccess" @@ -381,11 +381,13 @@ SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c08c", TAG+="uacces SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c088", TAG+="uaccess" SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="4079", TAG+="uaccess" -SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c53a", TAG+="uaccess" +SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="c53a", TAG+="uaccess" #Powerplay Mat Reciever +SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="405F", TAG+="uaccess" #Powerplay Mat Virtual PID -SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="0a78", TAG+="uaccess" +SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="0a78", TAG+="uaccess" #G560 -SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="0a5b", TAG+="uaccess" +SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="0a5b", TAG+="uaccess" #G933 +SUBSYSTEMS=="usb", ATTR{idVendor}=="046d", ATTR{idProduct}=="0ab5", TAG+="uaccess" #G733 SUBSYSTEMS=="usb", ATTR{idVendor}=="0738", ATTR{idProduct}=="2221", TAG+="uaccess" SUBSYSTEMS=="usb", ATTR{idVendor}=="0738", ATTR{idProduct}=="A221", TAG+="uaccess" diff --git a/Controllers/LogitechController/LogitechControllerDetect.cpp b/Controllers/LogitechController/LogitechControllerDetect.cpp index 4f2e1837..29fb9428 100644 --- a/Controllers/LogitechController/LogitechControllerDetect.cpp +++ b/Controllers/LogitechController/LogitechControllerDetect.cpp @@ -24,13 +24,18 @@ #include "RGBController_LogitechLightspeed.h" #include "RGBController_LogitechGPowerPlay.h" #include "RGBController_LogitechX56.h" +#include +#include #include #include +using namespace std::chrono_literals; + /*-----------------------------------------------------*\ | Logitech vendor ID | \*-----------------------------------------------------*/ #define LOGITECH_VID 0x046D +#define LOGITECH_LIGHTSPEED_DETECT_MAX_RETRY 10 /*-----------------------------------------------------*\ | Keyboard product IDs | @@ -80,6 +85,7 @@ | Headset product IDs | \*-----------------------------------------------------*/ #define LOGITECH_G933_PID 0x0A5B +#define LOGITECH_G733_PID 0x0AB5 /*-----------------------------------------------------*\ | Unifying Device IDs (Including Lightspeed receivers) | @@ -98,6 +104,7 @@ #define LOGITECH_G900_LIGHTSPEED_VIRTUAL_PID 0x4053 #define LOGITECH_G903_LIGHTSPEED_VIRTUAL_PID 0x4067 #define LOGITECH_G_PRO_WIRELESS_VIRTUAL_PID 0x4079 +#define LOGITECH_POWERPLAY_MAT_VIRTUAL_PID 0x405F /*-----------------------------------------------------*\ | Joystick product IDs | @@ -570,25 +577,37 @@ REGISTER_HID_DETECTOR_IP("Logitech X56 Rhino Hotas Throttle", Dete usages BundleLogitechUsages(hid_device_info* info) { - usages temp_usages; - /*-----------------------------------------------------------------*\ | Need a unique ID to group usages for 1 device if multiple exist | | Grab all usages that you can open. For normal Logitech FAP | | devices this will be usage 1, 2 and 4 | \*-----------------------------------------------------------------*/ - if(info->usage == 1) + + usages temp_usages; + uint16_t current_pid = info->product_id; + hid_device_info* temp_info = info; + + /*-----------------------------------------------------------------*\ + | To avoid duplicate entries per device only look from usage 1 | + \*-----------------------------------------------------------------*/ + if(temp_info->usage == 1) { - while(info) + while(temp_info) { - hid_device* dev = hid_open_path(info->path); - - if(dev) + /*-----------------------------------------------------------------*\ + | Only bundle the device that triggered this callback | + \*-----------------------------------------------------------------*/ + if(temp_info->product_id == current_pid) { - temp_usages.emplace((uint8_t)info->usage, dev); - } + hid_device* dev = hid_open_path(temp_info->path); - info = info->next; + if(dev) + { + LOG_DEBUG("Adding Usage %i for device @ path %s", temp_info->usage, temp_info->path); + temp_usages.emplace((uint8_t)temp_info->usage, dev); + } + } + temp_info = temp_info->next; } } @@ -597,10 +616,29 @@ usages BundleLogitechUsages(hid_device_info* info) void CreateLogitechLightspeedDevice(char *path, usages device_usages, uint8_t device_index, bool wireless, std::shared_ptr mutex_ptr) { - LogitechLightspeedController* controller = new LogitechLightspeedController(device_usages.find(2)->second, path); - controller->lightspeed = new logitech_device(path, device_usages, device_index, wireless, mutex_ptr); - RGBController_LogitechLightspeed* rgb_controller = new RGBController_LogitechLightspeed(controller); - ResourceManager::get()->RegisterRGBController(rgb_controller); + LogitechLightspeedController* controller = new LogitechLightspeedController(device_usages.find(2)->second, path); + bool lightspeedDeviceIsValid = false; + int retryCount = 0; + + while (!lightspeedDeviceIsValid && retryCount < LOGITECH_LIGHTSPEED_DETECT_MAX_RETRY) + { + std::this_thread::sleep_for(50ms); + controller->lightspeed = new logitech_device(path, device_usages, device_index, wireless, mutex_ptr); + lightspeedDeviceIsValid = controller->lightspeed->is_valid(); + retryCount++; + } + + if (retryCount < LOGITECH_LIGHTSPEED_DETECT_MAX_RETRY) + { + RGBController_LogitechLightspeed* rgb_controller = new RGBController_LogitechLightspeed(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + LOG_DEBUG("Added controller in %i retries", retryCount); + } + else + { + delete controller; + LOG_DEBUG("Failed to set up device - exceeded retries"); + } } void DetectLogitechLightspeedReceiver(hid_device_info* info, const std::string& /*name*/) @@ -638,15 +676,27 @@ void DetectLogitechLightspeedReceiver(hid_device_info* info, const std::string& void DetectLogitechWired(hid_device_info* info, const std::string& /*name*/) { /*-----------------------------------------------------------------*\ - | Need to save the device path before iterating | - | over "info" in BundleLogitechUsages() | + | Wired lightspeed devices don't use the FAP short message | + | Be sure to specify a Page AND Usage when using this detector | + | i.e. REGISTER_HID_DETECTOR_IPU | \*-----------------------------------------------------------------*/ - char *path = info->path; - usages device_usages = BundleLogitechUsages(info); + //char *path = info->path; + usages device_usages; + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + LOG_DEBUG("Adding Usage %i for device @ path %s", info->usage, info->path); + device_usages.emplace((uint8_t)info->usage, dev); + } + else + { + LOG_DEBUG("Error opening Usage %i for device @ path %s", info->usage, info->path); + } if(device_usages.size() > 0) { - CreateLogitechLightspeedDevice(path, device_usages, 0xFF, false, nullptr); + CreateLogitechLightspeedDevice(info->path, device_usages, 0xFF, false, nullptr); } } @@ -659,12 +709,13 @@ REGISTER_HID_DETECTOR_IP("Logitech G Powerplay Mousepad", /*-------------------------------------------------------------------------------------------------------------------------------------------------*\ | Lightspeed Wireless Devices (Windows Wired) | \*-------------------------------------------------------------------------------------------------------------------------------------------------*/ -REGISTER_HID_DETECTOR_IP("Logitech G403 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G403_LIGHTSPEED_PID, 1, 0xFF00); -REGISTER_HID_DETECTOR_IP("Logitech G502 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_LIGHTSPEED_PID, 1, 0xFF00); -REGISTER_HID_DETECTOR_IP("Logitech G703 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G703_LIGHTSPEED_PID, 1, 0xFF00); -REGISTER_HID_DETECTOR_IP("Logitech G900 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G900_LIGHTSPEED_PID, 1, 0xFF00); -REGISTER_HID_DETECTOR_IP("Logitech G903 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G903_LIGHTSPEED_PID, 1, 0xFF00); -REGISTER_HID_DETECTOR_IP("Logitech G Pro Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G_PRO_WIRELESS_PID, 2, 0xFF00); +REGISTER_HID_DETECTOR_IPU("Logitech G403 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G403_LIGHTSPEED_PID, 1, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech G502 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G502_LIGHTSPEED_PID, 1, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech G703 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G703_LIGHTSPEED_PID, 1, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech G900 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G900_LIGHTSPEED_PID, 1, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech G903 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G903_LIGHTSPEED_PID, 1, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech G Pro Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G_PRO_WIRELESS_PID, 2, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech G733 Gaming Headset", DetectLogitechWired, LOGITECH_VID, LOGITECH_G733_PID, 2, 0xFF43, 514); #endif @@ -688,10 +739,29 @@ void CreateLogitechLightspeedDevice(hid_device_info* info, bool wireless) if(device_usages.size() > 0) { - LogitechLightspeedController* controller = new LogitechLightspeedController(device_usages.find(0)->second, info->path); - controller->lightspeed = new logitech_device(info->path, device_usages, 0xFF, wireless); - RGBController_LogitechLightspeed* rgb_controller = new RGBController_LogitechLightspeed(controller); - ResourceManager::get()->RegisterRGBController(rgb_controller); + LogitechLightspeedController* controller = new LogitechLightspeedController(device_usages.find(0)->second, info->path); + bool lightspeedDeviceIsValid = false; + int retryCount = 0; + + while (!lightspeedDeviceIsValid && retryCount < LOGITECH_LIGHTSPEED_DETECT_MAX_RETRY) + { + std::this_thread::sleep_for(50ms); + controller->lightspeed = new logitech_device(info->path, device_usages, 0xFF, wireless); + lightspeedDeviceIsValid = controller->lightspeed->is_valid(); + retryCount++; + } + + if (retryCount < LOGITECH_LIGHTSPEED_DETECT_MAX_RETRY) + { + RGBController_LogitechLightspeed* rgb_controller = new RGBController_LogitechLightspeed(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + LOG_DEBUG("Added controller in %i retries", retryCount); + } + else + { + delete controller; + LOG_DEBUG("Failed to set up device - exceeded retries"); + } } } @@ -714,6 +784,7 @@ REGISTER_HID_DETECTOR_IPU("Logitech G703 Wireless Gaming Mouse", REGISTER_HID_DETECTOR_IPU("Logitech G900 Wireless Gaming Mouse", DetectLogitechWireless, LOGITECH_VID, LOGITECH_G900_LIGHTSPEED_VIRTUAL_PID, 2, 0xFF00, 2); REGISTER_HID_DETECTOR_IPU("Logitech G903 Wireless Gaming Mouse", DetectLogitechWireless, LOGITECH_VID, LOGITECH_G903_LIGHTSPEED_VIRTUAL_PID, 2, 0xFF00, 2); REGISTER_HID_DETECTOR_IPU("Logitech G Pro Wireless Gaming Mouse", DetectLogitechWireless, LOGITECH_VID, LOGITECH_G_PRO_WIRELESS_VIRTUAL_PID, 2, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech Powerplay Mat", DetectLogitechWireless, LOGITECH_VID, LOGITECH_POWERPLAY_MAT_VIRTUAL_PID, 2, 0xFF00, 2); /*-------------------------------------------------------------------------------------------------------------------------------------------------*\ | Lightspeed Wireless Devices (Linux Wired) | @@ -724,5 +795,6 @@ REGISTER_HID_DETECTOR_IPU("Logitech G703 Wireless Gaming Mouse (wired)", REGISTER_HID_DETECTOR_IPU("Logitech G900 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G900_LIGHTSPEED_PID, 1, 0xFF00, 2); REGISTER_HID_DETECTOR_IPU("Logitech G903 Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G903_LIGHTSPEED_PID, 1, 0xFF00, 2); REGISTER_HID_DETECTOR_IPU("Logitech G Pro Wireless Gaming Mouse (wired)", DetectLogitechWired, LOGITECH_VID, LOGITECH_G_PRO_WIRELESS_PID, 2, 0xFF00, 2); +REGISTER_HID_DETECTOR_IPU("Logitech G733 Gaming Headset", DetectLogitechWired, LOGITECH_VID, LOGITECH_G733_PID, 2, 0xFF43, 514); #endif diff --git a/Controllers/LogitechController/LogitechLightspeedController.cpp b/Controllers/LogitechController/LogitechLightspeedController.cpp index dc8d2d6b..a8acb55e 100644 --- a/Controllers/LogitechController/LogitechLightspeedController.cpp +++ b/Controllers/LogitechController/LogitechLightspeedController.cpp @@ -29,18 +29,27 @@ std::string LogitechLightspeedController::GetDeviceLocation() std::string LogitechLightspeedController::GetSerialString() { - wchar_t serial_string[128]; - int ret = hid_get_serial_number_string(dev, serial_string, 128); - - if(ret != 0) + if (lightspeed->device_index == 255 && lightspeed->wireless) { + LOG_DEBUG("[%s] Skipped get serial number as this is the reciever", lightspeed->device_name.c_str()); return(""); } + else + { + wchar_t serial_string[128]; + int ret = hid_get_serial_number_string(dev, serial_string, 128); + LOG_DEBUG("[%s] hid_get_serial_number_string Returned status - %i : %s", lightspeed->device_name.c_str(), ret, ((ret == 0) ? "SUCCESS" : "FAILED")); - std::wstring return_wstring = serial_string; - std::string return_string(return_wstring.begin(), return_wstring.end()); + if(ret != 0) + { + return(""); + } - return(return_string); + std::wstring return_wstring = serial_string; + std::string return_string(return_wstring.begin(), return_wstring.end()); + + return(return_string); + } } void LogitechLightspeedController::SendMouseMode diff --git a/Controllers/LogitechController/LogitechLightspeedController.h b/Controllers/LogitechController/LogitechLightspeedController.h index 3212581e..ac4dd39d 100644 --- a/Controllers/LogitechController/LogitechLightspeedController.h +++ b/Controllers/LogitechController/LogitechLightspeedController.h @@ -9,6 +9,7 @@ \*-----------------------------------------*/ #include "RGBController.h" +#include "LogManager.h" #include "LogitechProtocolCommon.h" #include diff --git a/Controllers/LogitechController/LogitechProtocolCommon.cpp b/Controllers/LogitechController/LogitechProtocolCommon.cpp index 8a59f4f1..8615499c 100644 --- a/Controllers/LogitechController/LogitechProtocolCommon.cpp +++ b/Controllers/LogitechController/LogitechProtocolCommon.cpp @@ -115,7 +115,6 @@ logitech_device::logitech_device(char *path, usages _usages, uint8_t _device_ind device_usages = _usages; wireless = _wireless; RGB_feature_index = 0; - LED_count = 0; mutex = nullptr; initialiseDevice(); @@ -128,7 +127,6 @@ logitech_device::logitech_device(char *path, usages _usages, uint8_t _device_ind device_usages = _usages; wireless = _wireless; RGB_feature_index = 0; - LED_count = 0; mutex = mutex_ptr; initialiseDevice(); @@ -144,56 +142,100 @@ logitech_device::~logitech_device() void logitech_device::initialiseDevice() { + bool is_connected = connected(); flushReadQueue(); - getDeviceName(); //This will get the name of the device if it exists - for(std::vector::iterator page = logitech_RGB_pages.begin(); page != logitech_RGB_pages.end(); page++) + if(is_connected) { - int feature_index = getFeatureIndex(*page); - if(feature_index > 0) + getDeviceName(); //This will get the name of the device if it exists + if(LogManager::get()->getLoglevel() > 4) { - feature_list.emplace(*page, feature_index); - RGB_feature_index = feature_index; + getDeviceFeatureList(); //This will populate the feature list + } + + for(std::vector::iterator page = logitech_RGB_pages.begin(); page != logitech_RGB_pages.end(); page++) + { + int feature_index = getFeatureIndex(*page); + if(feature_index > 0) + { + feature_list.emplace(*page, feature_index); + RGB_feature_index = feature_index; + } + } + + if (RGB_feature_index == 0) + { + /*-----------------------------------------------------------------*\ + | If there was no RGB Effect Feature page found | + | dump the entire Feature list to log | + \*-----------------------------------------------------------------*/ + LOG_INFO("[%s] Unable add this device due to missing RGB Effects Feature", device_name.c_str()); + /*for(features::iterator feature = feature_list.begin(); feature != feature_list.end(); feature++) + { + LOG_INFO("Feature Index: %02X\tFeature Page: %04X", feature->second, feature->first); + }*/ + } + else + { + getRGBconfig(); } } +} - if (RGB_feature_index == 0) +bool logitech_device::is_valid() +{ + bool is_connected = connected(); + bool valid_test = false; + + if(is_connected) { - /*-----------------------------------------------------------------*\ - | If there was no RGB Effect Feature page found | - | dump the entire Feature list to log | - \*-----------------------------------------------------------------*/ - getDeviceFeatureList(); //This will populate the feature list - LOG_INFO("Unable add this device due to missing RGB Effects Feature"); - for(features::iterator feature = feature_list.begin(); feature != feature_list.end(); feature++) - { - LOG_INFO("Feature Index: %02X\tFeature Page: %04X", feature->second, feature->first); - } + LOG_DEBUG("[%s] valid_test - type %i led_count - %i RGB_index - %i", device_name.c_str(), logitech_device_type, leds.size(), RGB_feature_index); + + valid_test = !device_name.empty() // Check if device name exists + && (logitech_device_type >= 0 && logitech_device_type <= 8) // Check if device type has a valid index + && (device_name[0] >= 32 && device_name[0] < 122) // Check for non valid characters in device name + && device_name.length() > 3 // Check for valid device names lenght + && leds.size() > 0 // Check if a device has at least 1 led + && RGB_feature_index > 0; // Check if a feature index is "valid" } else { - getRGBconfig(); + LOG_INFO("Unable add this Logitech device: Not Connected"); } + + return valid_test; } bool logitech_device::connected() { - bool test = false; - hid_device* dev_use1 = getDevice(1); - - if(dev_use1) + /*-----------------------------------------------------------------*\ + | If this is a wireless device test that it's connected | + | Wired devices will always be connected. | + \*-----------------------------------------------------------------*/ + if(wireless) { - blankFAPmessage response; - response.init(); //zero out the response + bool test = false; + hid_device* dev_use1 = getDevice(1); - shortFAPrequest get_connected_devices; - get_connected_devices.init(device_index, LOGITECH_GET_REGISTER_REQUEST); - get_connected_devices.feature_command = 0x02; //0x02 Connection State register. Essentially asking for count of paired devices - hid_write(dev_use1, get_connected_devices.buffer, get_connected_devices.size()); - hid_read_timeout(dev_use1, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - test = (response.data[1] != 0x09); //ERR_RESOURCE_ERROR i.e. not currently connected + if(dev_use1) + { + shortFAPrequest get_connected_devices; + get_connected_devices.init(device_index, LOGITECH_GET_REGISTER_REQUEST); + get_connected_devices.feature_command = 0x02; //0x02 Connection State register. Essentially asking for count of paired devices + + hid_write(dev_use1, get_connected_devices.buffer, get_connected_devices.size()); + //This hid_read will not timeout as we need to be sure the wireless device is connected + hid_read(dev_use1, get_connected_devices.buffer, get_connected_devices.size()); + test = (get_connected_devices.data[1] != 0x09); //ERR_RESOURCE_ERROR i.e. not currently connected + LOG_DEBUG("Wireless device index %i is %s - %02X %02X %02X", get_connected_devices.device_index, + (test ? "connected" : "disconnected"), get_connected_devices.data[0], get_connected_devices.data[1], get_connected_devices.data[2]); + } + return test; + } + else + { + return true; } - return test; } uint8_t logitech_device::getLEDinfo() @@ -202,7 +244,7 @@ uint8_t logitech_device::getLEDinfo() | Get all info about the LEDs and Zones | \*-----------------------------------------------------------------*/ - return LED_count; + return leds.size(); } void logitech_device::flushReadQueue() @@ -216,11 +258,19 @@ void logitech_device::flushReadQueue() for(usages::iterator dev = device_usages.begin(); dev != device_usages.end(); dev++) { //Flush the buffer - int result = 1; + int flushed = 0; + int result = 1; + while( result > 0 ) { result = hid_read_timeout(dev->second, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); + if (result > 0) + { + flushed++; + } } + //device_name has not yet been set so can not use it in the log + LOG_DEBUG("Preparing read queue for device %i - flushed %i packet%s", dev->first, flushed, ((flushed == 1) ? "" : "s")); } } @@ -233,6 +283,7 @@ hid_device* logitech_device::getDevice(uint8_t usage_index) #ifdef WIN32 usages::iterator find_usage = device_usages.find(usage_index); #else + //Linux does not need bundle the device usages hence .begin() usages::iterator find_usage = device_usages.begin(); #endif //WIN32 @@ -269,7 +320,10 @@ uint8_t logitech_device::getFeatureIndex(uint16_t feature_page) result = hid_write(dev_use2, get_index.buffer, get_index.size()); result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); feature_index = response.data[0]; + LOG_DEBUG("[%s] Feature Page %04X found @ index %02X - %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), feature_page, feature_index, + response.data[0], response.data[1], response.data[2], response.data[3], response.data[4], response.data[5], response.data[6], response.data[7]); } + return feature_index; } @@ -281,10 +335,10 @@ int logitech_device::getDeviceFeatureList() | Check the usage map for usage1 (0x10 Short FAP Message) & usage2 | | (0x11 Long FAP Message) then list all features for device | \*-----------------------------------------------------------------*/ - hid_device* dev_use1 = getDevice(1); + //hid_device* dev_use1 = getDevice(1); hid_device* dev_use2 = getDevice(2); - if(dev_use1 && dev_use2) + if(/*dev_use1 &&*/ dev_use2) { /*-----------------------------------------------------------------*\ | Create a buffer for reads | @@ -296,48 +350,46 @@ int logitech_device::getDeviceFeatureList() | Query the root index for the index of the feature list | | This is done for safety as it is generaly at feature index 0x01 | \*-----------------------------------------------------------------*/ - shortFAPrequest get_index; - get_index.init(device_index, LOGITECH_HIDPP_PAGE_ROOT_IDX); - get_index.feature_command = LOGITECH_CMD_ROOT_GET_FEATURE; - get_index.data[0] = LOGITECH_HIDPP_PAGE_FEATURE_SET >> 8; //Get feature index of the Feature Set 0x0001 - get_index.data[1] = LOGITECH_HIDPP_PAGE_FEATURE_SET & 0xFF; - - result = hid_write(dev_use1, get_index.buffer, get_index.size()); - result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - uint8_t feature_index = response.data[0]; + int feature_index = getFeatureIndex(LOGITECH_HIDPP_PAGE_FEATURE_SET); /*-----------------------------------------------------------------*\ | Get the count of Features | \*-----------------------------------------------------------------*/ - shortFAPrequest get_count; - get_count.init(device_index, feature_index); - get_count.feature_command = LOGITECH_CMD_FEATURE_SET_GET_COUNT; + //shortFAPrequest get_count; + longFAPrequest get_count; + //get_count.init(device_index, feature_index); + //get_count.feature_command = LOGITECH_CMD_FEATURE_SET_GET_COUNT; + get_count.init(device_index, feature_index, LOGITECH_CMD_FEATURE_SET_GET_COUNT); - result = hid_write(dev_use1, get_count.buffer, get_count.size()); + //result = hid_write(dev_use1, get_count.buffer, get_count.size()); + result = hid_write(dev_use2, get_count.buffer, get_count.size()); result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); unsigned int feature_count = response.data[0]; - shortFAPrequest get_features; - get_features.init(device_index, feature_index); - get_features.feature_command = LOGITECH_CMD_FEATURE_SET_GET_ID; + //shortFAPrequest get_features; + longFAPrequest get_features; + //get_features.init(device_index, feature_index); + //get_features.feature_command = LOGITECH_CMD_FEATURE_SET_GET_ID; + get_features.init(device_index, feature_index, LOGITECH_CMD_FEATURE_SET_GET_ID); for(std::size_t i = 1; feature_list.size() < feature_count; i++ ) { get_features.data[0] = i; - result = hid_write(dev_use1, get_features.buffer, get_features.size()); + //result = hid_write(dev_use1, get_features.buffer, get_features.size()); + result = hid_write(dev_use2, get_features.buffer, get_features.size()); result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - LOG_DEBUG("Reading HID++ Feature %04X at index: %02X", (response.data[0] << 8) | response.data[1], i); + LOG_DEBUG("[%s] Feature %04X @ index: %02X", device_name.c_str(), (response.data[0] << 8) | response.data[1], i); feature_list.emplace((response.data[0] << 8) | response.data[1], i); } } else { - if(!dev_use1) + /*if(!dev_use1) { - LOG_INFO("Unable add this device due to missing FAP Short Message (0x10) usage"); - } + LOG_INFO("[%s] Unable get the feature index list - missing Short Message (0x10) usage", device_name.c_str()); + }*/ if(!dev_use2) { - LOG_INFO("Unable add this device due to missing FAP Long Message (0x11) usage"); + LOG_INFO("[%s] Unable get the feature index list - missing FAP Long Message (0x11) usage", device_name.c_str()); } } @@ -361,11 +413,16 @@ int logitech_device::getDeviceName() response.init(); int result; + /*-----------------------------------------------------------------*\ + | Query the root index for the index of the name feature | + \*-----------------------------------------------------------------*/ + int feature_index = getFeatureIndex(LOGITECH_HIDPP_PAGE_DEVICE_NAME_TYPE); + /*-----------------------------------------------------------------*\ | Check if the feature_list contains an index for the Device_name | | feature otherwise query the root index. If not found return 0 | \*-----------------------------------------------------------------*/ - uint8_t name_feature_index; + /*uint8_t name_feature_index; features::iterator find_feature = feature_list.find(LOGITECH_HIDPP_PAGE_DEVICE_NAME_TYPE); if (find_feature == feature_list.end()) { @@ -381,32 +438,44 @@ int logitech_device::getDeviceName() else { name_feature_index = find_feature->second; - } + }*/ /*-----------------------------------------------------------------*\ | Get the device name length | \*-----------------------------------------------------------------*/ - longFAPrequest get_length; - get_length.init(device_index, name_feature_index, LOTITECH_CMD_DEVICE_NAME_TYPE_GET_COUNT); - result = hid_write(dev_use2, get_length.buffer, get_length.size()); - result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - unsigned int name_length = response.data[0]; - - longFAPrequest get_name; - get_name.init(device_index, name_feature_index, LOGITECH_CMD_DEVICE_NAME_TYPE_GET_DEVICE_NAME); - while(device_name.length() < name_length) + if(feature_index > 0) { - get_name.data[0] = device_name.length(); //This sets the character index to get from the device + longFAPrequest get_length; + get_length.init(device_index, feature_index, LOTITECH_CMD_DEVICE_NAME_TYPE_GET_COUNT); + result = hid_write(dev_use2, get_length.buffer, get_length.size()); + result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); + unsigned int name_length = response.data[0]; + LOG_DEBUG("[%s] Name Length %02i - %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), name_length, + response.data[0], response.data[1], response.data[2], response.data[3], response.data[4], response.data[5], response.data[6], response.data[7], + response.data[8], response.data[9], response.data[10], response.data[11], response.data[12], response.data[13], response.data[14], response.data[15]); + + longFAPrequest get_name; + get_name.init(device_index, feature_index, LOGITECH_CMD_DEVICE_NAME_TYPE_GET_DEVICE_NAME); + while(device_name.length() < name_length) + { + get_name.data[0] = device_name.length(); //This sets the character index to get from the device + result = hid_write(dev_use2, get_name.buffer, get_name.size()); + result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); + std::string temp = (char *)&response.data; + device_name.append(temp); + LOG_DEBUG("[%s] Get Name %02i - %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), device_name.length(), + response.data[0], response.data[1], response.data[2], response.data[3], response.data[4], response.data[5], response.data[6], response.data[7], + response.data[8], response.data[9], response.data[10], response.data[11], response.data[12], response.data[13], response.data[14], response.data[15]); + } + + get_name.init(device_index, feature_index, LOGITECH_CMD_DEVICE_NAME_TYPE_GET_TYPE); result = hid_write(dev_use2, get_name.buffer, get_name.size()); result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - std::string temp = (char *)&response.data; - device_name.append(temp); + logitech_device_type = response.data[0]; + LOG_DEBUG("[%s] Get Type %02i - %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), logitech_device_type, + response.data[0], response.data[1], response.data[2], response.data[3], response.data[4], response.data[5], response.data[6], response.data[7], + response.data[8], response.data[9], response.data[10], response.data[11], response.data[12], response.data[13], response.data[14], response.data[15]); } - - get_name.init(device_index, name_feature_index, LOGITECH_CMD_DEVICE_NAME_TYPE_GET_TYPE); - result = hid_write(dev_use2, get_name.buffer, get_name.size()); - result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - logitech_device_type = response.data[0]; } return device_name.length(); @@ -418,7 +487,9 @@ void logitech_device::getRGBconfig() | Check the usage map for usage2 (0x11 Long FAP Message) | | Then use it to get the name for this device | \*-----------------------------------------------------------------*/ - hid_device* dev_use2 = getDevice(2); + hid_device* dev_use2 = getDevice(2); + uint8_t led_response = 0; + uint8_t led_counter = 0; if(dev_use2) { @@ -433,17 +504,39 @@ void logitech_device::getRGBconfig() get_count.init(device_index, RGB_feature_index, LOGITECH_CMD_RGB_EFFECTS_GET_COUNT); result = hid_write(dev_use2, get_count.buffer, get_count.size()); - result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - LED_count = response.data[0]; + do + { + result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); + LOG_DEBUG("[%s] LED Count - %02X : %04X %04X %04X %04X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), + response.data[0], (response.data[1] << 8 | response.data[2]), (response.data[3] << 8 | response.data[4]), (response.data[5] << 8 | response.data[6]), + (response.data[7] << 8 | response.data[8]), response.data[9], response.data[10], response.data[11], response.data[12], response.data[13], response.data[14], response.data[15]); + } while ((result == 20) && (get_count.feature_index != response.feature_index) && (get_count.feature_command != response.feature_command)); + + led_response = response.data[0]; get_count.feature_command = LOGITECH_CMD_RGB_EFFECTS_GET_INFO; - for(std::size_t i = 0; i < LED_count; i++ ) + do { //TODO: Push this info into a vector for later enumeration by the RGBController - get_count.data[0] = i; + get_count.data[0] = leds.size(); result = hid_write(dev_use2, get_count.buffer, get_count.size()); result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); - } + LOG_DEBUG("[%s] LED %02i - %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(), led_counter, + response.data[0], response.data[1], response.data[2], response.data[3], response.data[4], response.data[5], response.data[6], response.data[7], + response.data[8], response.data[9], response.data[10], response.data[11], response.data[12], response.data[13], response.data[14], response.data[15]); + if(result == 20 && get_count.feature_index == response.feature_index && get_count.feature_command == response.feature_command && response.data[0] != 0x10 && response.data[1] != 0x02) + { + //If the response is the correct length (i.e. no USB error) and is for the RGB_feature_index and LOGITECH_CMD_RGB_EFFECTS_GET_INFO and no error occured with the led_counter then bump the counter + logitech_led new_led; + + new_led.value = response.data[0]; + new_led.param1 = response.data[1]; + new_led.param2 = response.data[2]; + new_led.param3 = response.data[3]; + + leds.push_back(new_led); + } + } while ((result == 20) && (get_count.feature_index == response.feature_index) && (get_count.feature_command == response.feature_command) && (response.data[0] != 0x10) && (response.data[1] != 0x02)); /*get_count.feature_command = LOGITECH_CMD_RGB_EFFECTS_GET_STATE; for(std::size_t i = 0; i < feature_count; i++ ) @@ -461,6 +554,8 @@ void logitech_device::getRGBconfig() result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); }*/ } + + LOG_DEBUG("[%s] led_response returned %i led_counter returned %i : setting controller to %i LED%s", device_name.c_str(), led_response, led_counter, leds.size(), ((leds.size() == 1) ? "" : "s")); } uint8_t logitech_device::setDirectMode(bool direct) @@ -472,10 +567,10 @@ uint8_t logitech_device::setDirectMode(bool direct) | (0x11 Long FAP Message) then set the device into direct mode | | via register 0x8A | \*-----------------------------------------------------------------*/ - hid_device* dev_use1 = getDevice(1); + //hid_device* dev_use1 = getDevice(1); hid_device* dev_use2 = getDevice(2); - if(dev_use1 && dev_use2) + if(/*dev_use1 &&*/ dev_use2) { /*-----------------------------------------------------------------*\ | Create a buffer for reads | @@ -486,9 +581,11 @@ uint8_t logitech_device::setDirectMode(bool direct) /*-----------------------------------------------------------------*\ | Turn the direct mode on or off via the RGB_feature_index | \*-----------------------------------------------------------------*/ - shortFAPrequest set_direct; - set_direct.init(device_index, RGB_feature_index); - set_direct.feature_command = LOGITECH_CMD_RGB_EFFECTS_UNKNOWN; + //shortFAPrequest set_direct; + longFAPrequest set_direct; + //set_direct.init(device_index, RGB_feature_index); + //set_direct.feature_command = LOGITECH_CMD_RGB_EFFECTS_UNKNOWN; + set_direct.init(device_index, RGB_feature_index, LOGITECH_CMD_RGB_EFFECTS_UNKNOWN); set_direct.data[0] = (direct) ? 1 : 0; set_direct.data[1] = set_direct.data[0]; @@ -503,12 +600,14 @@ uint8_t logitech_device::setDirectMode(bool direct) { std::lock_guard guard(*mutex); - result = hid_write(dev_use1, set_direct.buffer, set_direct.size()); + //result = hid_write(dev_use1, set_direct.buffer, set_direct.size()); + result = hid_write(dev_use2, set_direct.buffer, set_direct.size()); result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); } else { - result = hid_write(dev_use1, set_direct.buffer, set_direct.size()); + //result = hid_write(dev_use1, set_direct.buffer, set_direct.size()); + result = hid_write(dev_use2, set_direct.buffer, set_direct.size()); result = hid_read_timeout(dev_use2, response.buffer, response.size(), LOGITECH_PROTOCOL_TIMEOUT); } } diff --git a/Controllers/LogitechController/LogitechProtocolCommon.h b/Controllers/LogitechController/LogitechProtocolCommon.h index 48be1606..992ed575 100644 --- a/Controllers/LogitechController/LogitechProtocolCommon.h +++ b/Controllers/LogitechController/LogitechProtocolCommon.h @@ -8,6 +8,7 @@ \*-------------------------------------------------------------------*/ #include +#include #include #include "LogManager.h" @@ -56,10 +57,11 @@ enum LOGITECH_DEVICE_TYPE LOGITECH_DEVICE_TYPE_REMOTECONTROL =1, LOGITECH_DEVICE_TYPE_NUMPAD = 2, LOGITECH_DEVICE_TYPE_MOUSE = 3, - LOGITECH_DEVICE_TYPE_TOUCHPAD = 4, + LOGITECH_DEVICE_TYPE_MOUSEPAD = 4, LOGITECH_DEVICE_TYPE_TRACKBALL = 5, LOGITECH_DEVICE_TYPE_PRESENTER = 6, - LOGITECH_DEVICE_TYPE_RECEIVER = 7 + LOGITECH_DEVICE_TYPE_RECEIVER = 7, + LOGITECH_DEVICE_TYPE_HEADSET = 8 }; // Used for: {GET,SET}_REGISTER_{REQ,RSP}, SET_LONG_REGISTER_RSP, GET_LONG_REGISTER_REQ @@ -150,7 +152,7 @@ union blankFAPmessage uint8_t buffer[LOGITECH_FAP_RESPONSE_LEN]; struct { - uint8_t command; + uint8_t report_id; uint8_t device_index; uint8_t feature_index; uint8_t feature_command; @@ -172,6 +174,14 @@ union blankFAPmessage }; }; +struct logitech_led +{ + uint8_t value; + uint8_t param1; + uint8_t param2; + uint8_t param3; +}; + typedef std::map usages; typedef std::map features; typedef std::map wireless_map; @@ -201,6 +211,7 @@ public: std::string protocol_version; bool connected(); + bool is_valid(); void flushReadQueue(); uint8_t getFeatureIndex(uint16_t feature_page); uint8_t getLEDinfo(); @@ -208,7 +219,7 @@ public: uint8_t setMode(uint8_t mode, uint16_t speed, uint8_t zone, uint8_t red, uint8_t green, uint8_t blue, uint8_t brightness); int getDeviceName(); private: - uint8_t LED_count; + std::vector leds; std::shared_ptr mutex; hid_device* getDevice(uint8_t usage_index); diff --git a/Controllers/LogitechController/RGBController_LogitechLightspeed.cpp b/Controllers/LogitechController/RGBController_LogitechLightspeed.cpp index a7a1a006..c21a1dad 100644 --- a/Controllers/LogitechController/RGBController_LogitechLightspeed.cpp +++ b/Controllers/LogitechController/RGBController_LogitechLightspeed.cpp @@ -39,6 +39,14 @@ RGBController_LogitechLightspeed::RGBController_LogitechLightspeed(LogitechLight type = DEVICE_TYPE_MOUSE; break; + case LOGITECH_DEVICE_TYPE_MOUSEPAD: + type = DEVICE_TYPE_MOUSEMAT; + break; + + case LOGITECH_DEVICE_TYPE_HEADSET: + type = DEVICE_TYPE_HEADSET; + break; + default: type = DEVICE_TYPE_UNKNOWN; LOG_INFO("Logitech device type not known: %i", logitech->lightspeed->logitech_device_type);