Support for iCUE Link System Hub & attached devices
Commits amended to adhere to OpenRGB code standards and restructure functional layout by Adam Honse <calcprogrammer1@gmail.com>
This commit is contained in:
parent
b8628bb495
commit
cb3f0fdcbd
8 changed files with 667 additions and 0 deletions
|
|
@ -14,6 +14,10 @@
|
||||||
#include "DeviceGuard.h"
|
#include "DeviceGuard.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| Windows interferes with std::max unless NOMINMAX defined |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
#define NOMINMAX
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,280 @@
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CorsairICueLinkController.cpp |
|
||||||
|
| |
|
||||||
|
| Driver for Corsair iCue Link System Hub |
|
||||||
|
| |
|
||||||
|
| Aiden Vigue (acvigue) 02 Mar 2025 |
|
||||||
|
| Adam Honse <calcprogrammer1@gmail.com> 01 Aug 2025 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-only |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <LogManager.h>
|
||||||
|
|
||||||
|
#include "CorsairDeviceGuard.h"
|
||||||
|
#include "CorsairICueLinkController.h"
|
||||||
|
#include "CorsairICueLinkProtocol.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
CorsairICueLinkController::CorsairICueLinkController(hid_device* dev_handle, const char* path, std::string name)
|
||||||
|
{
|
||||||
|
dev = dev_handle;
|
||||||
|
location = path;
|
||||||
|
this->name = name;
|
||||||
|
|
||||||
|
guard_manager_ptr = new DeviceGuardManager(new CorsairDeviceGuard());
|
||||||
|
|
||||||
|
InitHub();
|
||||||
|
}
|
||||||
|
|
||||||
|
CorsairICueLinkController::~CorsairICueLinkController()
|
||||||
|
{
|
||||||
|
hid_close(dev);
|
||||||
|
|
||||||
|
delete guard_manager_ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorsairICueLinkController::InitHub()
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Get the firmware version |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
std::vector<unsigned char> firmware_data = SendCommand(CORSAIR_ICUE_LINK_CMD_GET_FIRMWARE, { }, { });
|
||||||
|
version[0] = firmware_data[0];
|
||||||
|
version[1] = firmware_data[1];
|
||||||
|
version[2] = firmware_data[2];
|
||||||
|
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Command the hub to enter software mode |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_SOFTWARE_MODE, { }, { });
|
||||||
|
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Get the endpoints data |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
std::vector<unsigned char> endpoint_data = Read(CORSAIR_ICUE_LINK_MODE_GET_DEVICES, CORSAIR_ICUE_LINK_DATA_TYPE_GET_DEVICES);
|
||||||
|
unsigned char channel = endpoint_data[6];
|
||||||
|
std::vector<unsigned char> index = std::vector<unsigned char>(endpoint_data.begin() + 7, endpoint_data.end());
|
||||||
|
std::size_t pos = 0;
|
||||||
|
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Process each channel |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
for(std::size_t channel_idx = 1; channel_idx < (std::size_t)(channel + 1); channel_idx++)
|
||||||
|
{
|
||||||
|
std::size_t device_id_length = index[pos + 7];
|
||||||
|
|
||||||
|
if(device_id_length == 0)
|
||||||
|
{
|
||||||
|
pos += 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------*\
|
||||||
|
| Extract endpoint metadata and ID from data |
|
||||||
|
\*-------------------------------------------------*/
|
||||||
|
std::vector<unsigned char> endpoint_metadata = std::vector<unsigned char>(index.begin() + pos, index.begin() + pos + 8);
|
||||||
|
std::vector<unsigned char> endpoint_id = std::vector<unsigned char>(index.begin() + pos + 8, index.begin() + pos + 8 + device_id_length);
|
||||||
|
|
||||||
|
/*-------------------------------------------------*\
|
||||||
|
| Get device information for this endpoint |
|
||||||
|
\*-------------------------------------------------*/
|
||||||
|
unsigned char type = endpoint_metadata[2];
|
||||||
|
unsigned char model = endpoint_metadata[3];
|
||||||
|
const CorsairICueLinkDevice * device = FindCorsairICueLinkDevice(type, model);
|
||||||
|
|
||||||
|
if(device == nullptr)
|
||||||
|
{
|
||||||
|
pos += 8 + device_id_length;
|
||||||
|
LOG_WARNING("[CorsairICueLinkController] Unknown device type: 0x%02x, model: 0x%02x", type, model);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(device->led_channels == 0)
|
||||||
|
{
|
||||||
|
LOG_WARNING("[CorsairICueLinkController] Device type %s has 0 LEDs, please open issue", device->display_name.c_str());
|
||||||
|
pos += 8 + device_id_length;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-------------------------------------------------*\
|
||||||
|
| Append this endpoint's serial number to the |
|
||||||
|
| device's serial number string |
|
||||||
|
\*-------------------------------------------------*/
|
||||||
|
std::string endpoint_id_str(endpoint_id.begin(), endpoint_id.end());
|
||||||
|
serial += "\r\n" + endpoint_id_str;
|
||||||
|
|
||||||
|
/*-------------------------------------------------*\
|
||||||
|
| Add endpoint device to list |
|
||||||
|
\*-------------------------------------------------*/
|
||||||
|
endpoints.push_back(device);
|
||||||
|
|
||||||
|
pos += 8 + device_id_length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CorsairICueLinkController::GetFirmwareString()
|
||||||
|
{
|
||||||
|
return("v" + std::to_string(version[0]) + "." + std::to_string(version[1]) + "." + std::to_string(version[2]));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CorsairICueLinkController::GetNameString()
|
||||||
|
{
|
||||||
|
return(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CorsairICueLinkController::GetLocationString()
|
||||||
|
{
|
||||||
|
return("HID: " + location);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CorsairICueLinkController::GetSerialString()
|
||||||
|
{
|
||||||
|
return(serial);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<const CorsairICueLinkDevice *> CorsairICueLinkController::GetEndpoints()
|
||||||
|
{
|
||||||
|
return(endpoints);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorsairICueLinkController::UpdateLights(RGBColor* colors, std::size_t num_colors)
|
||||||
|
{
|
||||||
|
/*-------------------------------------------------*\
|
||||||
|
| Send color buffer, packed RGBRGBRGB |
|
||||||
|
\*-------------------------------------------------*/
|
||||||
|
std::vector<unsigned char> color_data;
|
||||||
|
for(std::size_t i = 0; i < num_colors; i++)
|
||||||
|
{
|
||||||
|
color_data.push_back(RGBGetRValue(colors[i]));
|
||||||
|
color_data.push_back(RGBGetGValue(colors[i]));
|
||||||
|
color_data.push_back(RGBGetBValue(colors[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
Write(CORSAIR_ICUE_LINK_MODE_SET_COLOR, CORSAIR_ICUE_LINK_DATA_TYPE_SET_COLOR, color_data, CORSAIR_ICUE_ENDPOINT_TYPE_COLOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<unsigned char>> CorsairICueLinkController::ProcessMultiChunkPacket(const std::vector<unsigned char>& data, size_t max_chunk_size)
|
||||||
|
{
|
||||||
|
std::vector<std::vector<unsigned char>> result;
|
||||||
|
size_t offset = 0;
|
||||||
|
|
||||||
|
while(offset < data.size())
|
||||||
|
{
|
||||||
|
size_t end = std::min(max_chunk_size, data.size() - offset);
|
||||||
|
std::vector<unsigned char> chunk(data.begin() + offset, data.begin() + offset + end);
|
||||||
|
result.push_back(chunk);
|
||||||
|
offset += end;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> CorsairICueLinkController::SendCommand(std::vector<unsigned char> command, std::vector<unsigned char> data, std::vector<unsigned char> waitForDataType)
|
||||||
|
{
|
||||||
|
DeviceGuardLock lock = guard_manager_ptr->AwaitExclusiveAccess();
|
||||||
|
|
||||||
|
std::vector<unsigned char> write_buf(CORSAIR_ICUE_LINK_BUFFER_WRITE_LENGTH);
|
||||||
|
write_buf[2] = 0x01;
|
||||||
|
|
||||||
|
size_t command_size = command.size();
|
||||||
|
size_t data_size = data.size();
|
||||||
|
|
||||||
|
for(size_t i = 0; i < command_size; i++)
|
||||||
|
{
|
||||||
|
write_buf[3 + i] = command[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
for(size_t i = 0; i < data_size; i++)
|
||||||
|
{
|
||||||
|
write_buf[3 + command_size + i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> read_buf(CORSAIR_ICUE_LINK_BUFFER_READ_LENGTH);
|
||||||
|
|
||||||
|
hid_write(dev, write_buf.data(), CORSAIR_ICUE_LINK_BUFFER_WRITE_LENGTH);
|
||||||
|
hid_read_timeout(dev, read_buf.data(), CORSAIR_ICUE_LINK_BUFFER_READ_LENGTH, 1000);
|
||||||
|
|
||||||
|
if(waitForDataType.size() != 2)
|
||||||
|
{
|
||||||
|
return read_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tries = 0;
|
||||||
|
while((read_buf[4] != waitForDataType[0]) && tries < 5)
|
||||||
|
{
|
||||||
|
std::fill(read_buf.begin(), read_buf.end(), 0); // Clear the buffer before reading again
|
||||||
|
hid_read_timeout(dev, read_buf.data(), CORSAIR_ICUE_LINK_BUFFER_READ_LENGTH, 1000);
|
||||||
|
tries++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return read_buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<unsigned char> CorsairICueLinkController::Read(std::vector<unsigned char> endpoint, std::vector<unsigned char> data_type)
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Private function to read data from an endpoint |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
DeviceGuardLock lock = guard_manager_ptr->AwaitExclusiveAccess();
|
||||||
|
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_CLOSE_ENDPOINT, endpoint, { });
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_OPEN_ENDPOINT, endpoint, { });
|
||||||
|
std::vector<unsigned char> res = SendCommand(CORSAIR_ICUE_LINK_CMD_READ, { }, data_type);
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_CLOSE_ENDPOINT, endpoint, { });
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CorsairICueLinkController::Write(std::vector<unsigned char> endpoint, std::vector<unsigned char> data_type, std::vector<unsigned char> data, CORSAIR_ICUE_ENDPOINT_TYPE endpoint_type)
|
||||||
|
{
|
||||||
|
DeviceGuardLock lock = guard_manager_ptr->AwaitExclusiveAccess();
|
||||||
|
|
||||||
|
std::vector<unsigned char> buf(data_type.size() + data.size() + CORSAIR_ICUE_LINK_WRITE_HEADER_SIZE);
|
||||||
|
|
||||||
|
unsigned short data_len = (unsigned short)(data.size() + 2);
|
||||||
|
buf[0] = (unsigned char)(data_len & 0xFF);
|
||||||
|
buf[1] = (unsigned char)((data_len >> 8) & 0xFF);
|
||||||
|
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Pack data into next bytes |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
for(size_t i = 0; i < data_type.size(); i++)
|
||||||
|
{
|
||||||
|
buf[CORSAIR_ICUE_LINK_WRITE_HEADER_SIZE + i] = data_type[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Pack data into next bytes |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
for(size_t i = 0; i < data.size(); i++)
|
||||||
|
{
|
||||||
|
buf[CORSAIR_ICUE_LINK_WRITE_HEADER_SIZE + data_type.size() + i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_CLOSE_ENDPOINT, endpoint, { });
|
||||||
|
|
||||||
|
if(endpoint_type == CORSAIR_ICUE_ENDPOINT_TYPE_DEFAULT)
|
||||||
|
{
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_OPEN_ENDPOINT, endpoint, { });
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_WRITE, buf, { });
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_CLOSE_ENDPOINT, endpoint, { });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_OPEN_COLOR_ENDPOINT, endpoint, { });
|
||||||
|
|
||||||
|
std::vector<unsigned char> write_color_ep = CORSAIR_ICUE_LINK_CMD_WRITE_COLOR;
|
||||||
|
std::vector<std::vector<unsigned char>> chunks = ProcessMultiChunkPacket(buf, CORSAIR_ICUE_LINK_MAXIMUM_BUFFER_PER_REQUEST);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < chunks.size(); i++)
|
||||||
|
{
|
||||||
|
write_color_ep[0] = write_color_ep[0] + (unsigned char)i;
|
||||||
|
SendCommand(write_color_ep, chunks[i], {});
|
||||||
|
}
|
||||||
|
|
||||||
|
SendCommand(CORSAIR_ICUE_LINK_CMD_CLOSE_ENDPOINT, endpoint, { });
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CorsairICueLinkController.h |
|
||||||
|
| |
|
||||||
|
| Driver for Corsair iCue Link System Hub |
|
||||||
|
| |
|
||||||
|
| Aiden Vigue (acvigue) 02 Mar 2025 |
|
||||||
|
| Adam Honse <calcprogrammer1@gmail.com> 01 Aug 2025 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-only |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
#include <vector>
|
||||||
|
#include <hidapi.h>
|
||||||
|
|
||||||
|
#include "CorsairICueLinkProtocol.h"
|
||||||
|
#include "DeviceGuardManager.h"
|
||||||
|
#include "RGBController.h"
|
||||||
|
|
||||||
|
class CorsairICueLinkController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
CorsairICueLinkController(hid_device* dev_handle, const char* path, std::string name);
|
||||||
|
~CorsairICueLinkController();
|
||||||
|
|
||||||
|
std::string GetFirmwareString();
|
||||||
|
std::string GetNameString();
|
||||||
|
std::string GetLocationString();
|
||||||
|
std::string GetSerialString();
|
||||||
|
|
||||||
|
std::vector<const CorsairICueLinkDevice *> GetEndpoints();
|
||||||
|
|
||||||
|
void UpdateLights(RGBColor* colors, std::size_t num_colors);
|
||||||
|
|
||||||
|
private:
|
||||||
|
hid_device* dev;
|
||||||
|
std::string name;
|
||||||
|
std::string location;
|
||||||
|
std::string serial;
|
||||||
|
|
||||||
|
unsigned short int version[3] = { 0, 0, 0 };
|
||||||
|
|
||||||
|
DeviceGuardManager* guard_manager_ptr;
|
||||||
|
|
||||||
|
std::vector<const CorsairICueLinkDevice *> endpoints;
|
||||||
|
|
||||||
|
void InitHub();
|
||||||
|
|
||||||
|
std::vector<std::vector<unsigned char>> ProcessMultiChunkPacket(const std::vector<unsigned char>& data, size_t max_chunk_size);
|
||||||
|
std::vector<unsigned char> SendCommand(std::vector<unsigned char> command, std::vector<unsigned char> data, std::vector<unsigned char> waitForDataType);
|
||||||
|
|
||||||
|
std::vector<unsigned char> Read(std::vector<unsigned char> endpoint, std::vector<unsigned char> data_type);
|
||||||
|
void Write(std::vector<unsigned char> endpoint, std::vector<unsigned char> data_type, std::vector<unsigned char> data, CORSAIR_ICUE_ENDPOINT_TYPE endpoint_type);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CorsairICueLinkControllerDetect.cpp |
|
||||||
|
| |
|
||||||
|
| Detector for Corsair iCue Link System Hub |
|
||||||
|
| |
|
||||||
|
| Aiden Vigue (acvigue) 02 Mar 2025 |
|
||||||
|
| Adam Honse <calcprogrammer1@gmail.com> 01 Aug 2025 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-only |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include <hidapi.h>
|
||||||
|
#include "Detector.h"
|
||||||
|
#include "LogManager.h"
|
||||||
|
#include "CorsairICueLinkController.h"
|
||||||
|
#include "RGBController_CorsairICueLink.h"
|
||||||
|
|
||||||
|
#define CORSAIR_VID 0x1B1C
|
||||||
|
#define CORSAIR_ICUE_LINK_SYSTEM_HUB_PID 0x0C3F
|
||||||
|
|
||||||
|
void DetectCorsairICueLinkControllers(hid_device_info* info, const std::string& name)
|
||||||
|
{
|
||||||
|
hid_device* dev = hid_open_path(info->path);
|
||||||
|
|
||||||
|
if(dev)
|
||||||
|
{
|
||||||
|
CorsairICueLinkController* controller = new CorsairICueLinkController(dev, info->path, name);
|
||||||
|
RGBController_CorsairICueLink* rgb_controller = new RGBController_CorsairICueLink(controller);
|
||||||
|
|
||||||
|
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_HID_DETECTOR_IPU("Corsair iCUE Link System Hub", DetectCorsairICueLinkControllers, CORSAIR_VID, CORSAIR_ICUE_LINK_SYSTEM_HUB_PID, 0x00, 0xFF42, 0x01);
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CorsairICueLinkProtocol.cpp |
|
||||||
|
| |
|
||||||
|
| Driver for Corsair iCue Link System Hub |
|
||||||
|
| |
|
||||||
|
| Aiden Vigue (acvigue) 2 Mar 2025 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-only |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "CorsairICueLinkProtocol.h"
|
||||||
|
|
||||||
|
const CorsairICueLinkDevice* FindCorsairICueLinkDevice(unsigned char type, unsigned char model)
|
||||||
|
{
|
||||||
|
for(size_t i = 0; i < sizeof(known_devices) / sizeof(known_devices[0]); i++)
|
||||||
|
{
|
||||||
|
if(known_devices[i].type == type && known_devices[i].model == model)
|
||||||
|
{
|
||||||
|
return(&known_devices[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| CorsairICueLinkProtocol.h |
|
||||||
|
| |
|
||||||
|
| Driver for Corsair iCue Link System Hub |
|
||||||
|
| |
|
||||||
|
| Aiden Vigue (acvigue) 02 Mar 2025 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-only |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
typedef struct CorsairICueLinkDevice
|
||||||
|
{
|
||||||
|
unsigned char type = 0x00;
|
||||||
|
unsigned char model = 0x00;
|
||||||
|
std::string display_name = "Unknown";
|
||||||
|
unsigned char led_channels = 0;
|
||||||
|
} CorsairICueLinkDevice;
|
||||||
|
|
||||||
|
static const CorsairICueLinkDevice known_devices[] =
|
||||||
|
{
|
||||||
|
{ 0x05, 0x02, "iCUE LINK 5000T RGB", 160 },
|
||||||
|
{ 0x05, 0x01, "iCUE LINK 9000D RGB AIRFLOW", 22 },
|
||||||
|
{ 0x05, 0x00, "iCUE LINK ADAPTER", 16 },
|
||||||
|
{ 0x06, 0x00, "iCUE LINK COOLER PUMP LCD", 24 },
|
||||||
|
{ 0x11, 0x00, "iCUE LINK TITAN 240", 20 },
|
||||||
|
{ 0x11, 0x04, "iCUE LINK TITAN 240", 20 },
|
||||||
|
{ 0x07, 0x00, "iCUE LINK H100i RGB", 20 },
|
||||||
|
{ 0x07, 0x04, "iCUE LINK H100i RGB", 20 },
|
||||||
|
{ 0x11, 0x01, "iCUE LINK TITAN 280", 20 },
|
||||||
|
{ 0x07, 0x01, "iCUE LINK H115i RGB", 20 },
|
||||||
|
{ 0x11, 0x02, "iCUE LINK TITAN 360", 20 },
|
||||||
|
{ 0x11, 0x05, "iCUE LINK TITAN 360", 20 },
|
||||||
|
{ 0x07, 0x02, "iCUE LINK H150i RGB", 20 },
|
||||||
|
{ 0x07, 0x05, "iCUE LINK H150i RGB", 20 },
|
||||||
|
{ 0x11, 0x03, "iCUE LINK TITAN 420", 20 },
|
||||||
|
{ 0x07, 0x03, "iCUE LINK H170i RGB", 20 },
|
||||||
|
{ 0x10, 0x00, "VRM COOLER MODULE", 0 },
|
||||||
|
{ 0x02, 0x00, "iCUE LINK LX RGB", 18 },
|
||||||
|
{ 0x14, 0x00, "ORIGIN OA", 0 },
|
||||||
|
{ 0x01, 0x00, "iCUE LINK QX RGB", 34 },
|
||||||
|
{ 0x13, 0x00, "iCUE LINK RX", 0 },
|
||||||
|
{ 0x04, 0x00, "iCUE LINK RX MAX", 0 },
|
||||||
|
{ 0x0F, 0x00, "iCUE LINK RX RGB", 8 },
|
||||||
|
{ 0x03, 0x00, "iCUE LINK RX RGB MAX", 8 },
|
||||||
|
{ 0x09, 0x00, "iCUE LINK XC7 ELITE", 0 },
|
||||||
|
{ 0x0C, 0x00, "iCUE LINK XD5 ELITE", 22 },
|
||||||
|
{ 0x0E, 0x00, "iCUE LINK XD5 ELITE LCD", 22 },
|
||||||
|
{ 0x0A, 0x00, "iCUE LINK XG3 HYBRID", 0 },
|
||||||
|
{ 0x0D, 0x00, "iCUE LINK XG7 RGB", 16 }
|
||||||
|
};
|
||||||
|
|
||||||
|
//Lengths
|
||||||
|
#define CORSAIR_ICUE_LINK_BUFFER_WRITE_LENGTH 513
|
||||||
|
#define CORSAIR_ICUE_LINK_BUFFER_READ_LENGTH 512
|
||||||
|
#define CORSAIR_ICUE_LINK_READ_HEADER_SIZE 3
|
||||||
|
#define CORSAIR_ICUE_LINK_WRITE_HEADER_SIZE 4
|
||||||
|
#define CORSAIR_ICUE_LINK_MAXIMUM_BUFFER_PER_REQUEST 508
|
||||||
|
|
||||||
|
//Commands
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_OPEN_ENDPOINT {0x0d, 0x01}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_OPEN_COLOR_ENDPOINT {0x0d, 0x00}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_CLOSE_ENDPOINT {0x05, 0x01, 0x01}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_GET_FIRMWARE {0x02, 0x13}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_SOFTWARE_MODE {0x01, 0x03, 0x00, 0x02}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_HARDWARE_MODE {0x01, 0x02, 0x00, 0x01}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_WRITE {0x06, 0x01}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_WRITE_COLOR {0x06, 0x00}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_READ {0x08, 0x01}
|
||||||
|
#define CORSAIR_ICUE_LINK_CMD_GET_DEVICE_MODE {0x01, 0x08, 0x01}
|
||||||
|
|
||||||
|
//Command modes
|
||||||
|
#define CORSAIR_ICUE_LINK_MODE_GET_DEVICES {0x36,}
|
||||||
|
#define CORSAIR_ICUE_LINK_MODE_GET_TEMPERATURES {0x21,}
|
||||||
|
#define CORSAIR_ICUE_LINK_MODE_GET_SPEEDS {0x17,}
|
||||||
|
#define CORSAIR_ICUE_LINK_MODE_SET_SPEED {0x18,}
|
||||||
|
#define CORSAIR_ICUE_LINK_MODE_SET_COLOR {0x22,}
|
||||||
|
|
||||||
|
//Command data types
|
||||||
|
#define CORSAIR_ICUE_LINK_DATA_TYPE_GET_DEVICES {0x21, 0x00}
|
||||||
|
#define CORSAIR_ICUE_LINK_DATA_TYPE_GET_TEMPERATURES {0x10, 0x00}
|
||||||
|
#define CORSAIR_ICUE_LINK_DATA_TYPE_GET_SPEEDS {0x25, 0x00}
|
||||||
|
#define CORSAIR_ICUE_LINK_DATA_TYPE_SET_SPEED {0x07, 0x00}
|
||||||
|
#define CORSAIR_ICUE_LINK_DATA_TYPE_SET_COLOR {0x12, 0x00}
|
||||||
|
|
||||||
|
typedef enum CORSAIR_ICUE_ENDPOINT_TYPE
|
||||||
|
{
|
||||||
|
CORSAIR_ICUE_ENDPOINT_TYPE_DEFAULT,
|
||||||
|
CORSAIR_ICUE_ENDPOINT_TYPE_COLOR
|
||||||
|
} CORSAIR_ICUE_ENDPOINT_TYPE;
|
||||||
|
|
||||||
|
const CorsairICueLinkDevice* FindCorsairICueLinkDevice(unsigned char type, unsigned char model);
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| RGBController_CorsairICueLink.cpp |
|
||||||
|
| |
|
||||||
|
| Driver for Corsair iCue Link Devices |
|
||||||
|
| |
|
||||||
|
| Aiden Vigue (acvigue) 02 Mar 2025 |
|
||||||
|
| Adam Honse <calcprogrammer1@gmail.com> 01 Aug 2025 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-only |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#include "CorsairICueLinkProtocol.h"
|
||||||
|
#include "RGBController_CorsairICueLink.h"
|
||||||
|
|
||||||
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
|
/**------------------------------------------------------------------*\
|
||||||
|
@name Corsair iCUE Link Device Controller
|
||||||
|
@category Cooler
|
||||||
|
@type USB
|
||||||
|
@save :x:
|
||||||
|
@direct :white_check_mark:
|
||||||
|
@effects :x:
|
||||||
|
@detectors DetectCorsairICueLinkController
|
||||||
|
@comment
|
||||||
|
\*-------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
RGBController_CorsairICueLink::RGBController_CorsairICueLink(CorsairICueLinkController* controller)
|
||||||
|
{
|
||||||
|
this->controller = controller;
|
||||||
|
|
||||||
|
name = controller->GetNameString();
|
||||||
|
vendor = "Corsair";
|
||||||
|
description = "iCUE Link Device";
|
||||||
|
version = controller->GetFirmwareString();
|
||||||
|
location = controller->GetLocationString();
|
||||||
|
serial = controller->GetSerialString();
|
||||||
|
type = DEVICE_TYPE_COOLER;
|
||||||
|
|
||||||
|
mode Direct;
|
||||||
|
Direct.name = "Direct";
|
||||||
|
Direct.value = 0;
|
||||||
|
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
|
||||||
|
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||||
|
modes.push_back(Direct);
|
||||||
|
|
||||||
|
SetupZones();
|
||||||
|
|
||||||
|
keepalive_thread_run = 1;
|
||||||
|
keepalive_thread = new std::thread(&RGBController_CorsairICueLink::KeepaliveThread, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
RGBController_CorsairICueLink::~RGBController_CorsairICueLink()
|
||||||
|
{
|
||||||
|
keepalive_thread_run = 0;
|
||||||
|
keepalive_thread->join();
|
||||||
|
delete keepalive_thread;
|
||||||
|
|
||||||
|
delete controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CorsairICueLink::SetupZones()
|
||||||
|
{
|
||||||
|
for(std::size_t zone_idx = 0; zone_idx < controller->GetEndpoints().size(); zone_idx++)
|
||||||
|
{
|
||||||
|
zone new_zone;
|
||||||
|
|
||||||
|
new_zone.name = controller->GetEndpoints()[zone_idx]->display_name;
|
||||||
|
new_zone.type = ZONE_TYPE_LINEAR;
|
||||||
|
new_zone.leds_min = controller->GetEndpoints()[zone_idx]->led_channels;
|
||||||
|
new_zone.leds_max = new_zone.leds_min;
|
||||||
|
new_zone.leds_count = new_zone.leds_min;
|
||||||
|
|
||||||
|
zones.push_back(new_zone);
|
||||||
|
|
||||||
|
for(unsigned int led_idx = 0; led_idx < new_zone.leds_count; led_idx++)
|
||||||
|
{
|
||||||
|
led new_led;
|
||||||
|
new_led.name = "LED " + std::to_string(led_idx + 1);
|
||||||
|
|
||||||
|
leds.push_back(new_led);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetupColors();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CorsairICueLink::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||||
|
{
|
||||||
|
/*-----------------------------------------------------*\
|
||||||
|
| Device does not support resizing zones |
|
||||||
|
\*-----------------------------------------------------*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CorsairICueLink::DeviceUpdateLEDs()
|
||||||
|
{
|
||||||
|
controller->UpdateLights(&colors[0], colors.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CorsairICueLink::UpdateZoneLEDs(int /*zone*/)
|
||||||
|
{
|
||||||
|
DeviceUpdateLEDs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CorsairICueLink::UpdateSingleLED(int /*led*/)
|
||||||
|
{
|
||||||
|
DeviceUpdateLEDs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CorsairICueLink::DeviceUpdateMode()
|
||||||
|
{
|
||||||
|
DeviceUpdateLEDs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RGBController_CorsairICueLink::KeepaliveThread()
|
||||||
|
{
|
||||||
|
while(keepalive_thread_run.load())
|
||||||
|
{
|
||||||
|
if((std::chrono::steady_clock::now() - last_commit_time) > std::chrono::seconds(5))
|
||||||
|
{
|
||||||
|
DeviceUpdateLEDs();
|
||||||
|
}
|
||||||
|
std::this_thread::sleep_for(1s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*---------------------------------------------------------*\
|
||||||
|
| RGBController_CorsairICueLink.h |
|
||||||
|
| |
|
||||||
|
| RGBController for Corsair iCue Link Devices |
|
||||||
|
| |
|
||||||
|
| Aiden Vigue (acvigue) 02 Mar 2025 |
|
||||||
|
| Adam Honse <calcprogrammer1@gmail.com> 01 Aug 2025 |
|
||||||
|
| |
|
||||||
|
| This file is part of the OpenRGB project |
|
||||||
|
| SPDX-License-Identifier: GPL-2.0-only |
|
||||||
|
\*---------------------------------------------------------*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <chrono>
|
||||||
|
#include <thread>
|
||||||
|
#include "CorsairICueLinkController.h"
|
||||||
|
#include "RGBController.h"
|
||||||
|
|
||||||
|
class RGBController_CorsairICueLink : public RGBController
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
RGBController_CorsairICueLink(CorsairICueLinkController* controller);
|
||||||
|
~RGBController_CorsairICueLink();
|
||||||
|
|
||||||
|
void SetupZones();
|
||||||
|
|
||||||
|
void ResizeZone(int zone, int new_size);
|
||||||
|
void DeviceUpdateLEDs();
|
||||||
|
void UpdateZoneLEDs(int zone);
|
||||||
|
void UpdateSingleLED(int led);
|
||||||
|
|
||||||
|
void DeviceUpdateMode();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CorsairICueLinkController* controller;
|
||||||
|
std::thread* keepalive_thread;
|
||||||
|
std::atomic<bool> keepalive_thread_run;
|
||||||
|
std::chrono::time_point<std::chrono::steady_clock> last_commit_time;
|
||||||
|
|
||||||
|
void KeepaliveThread();
|
||||||
|
};
|
||||||
Loading…
Add table
Add a link
Reference in a new issue