diff --git a/Controllers/CorsairController/CorsairDeviceGuard.h b/Controllers/CorsairController/CorsairDeviceGuard.h index cb048f16..9ae428d5 100644 --- a/Controllers/CorsairController/CorsairDeviceGuard.h +++ b/Controllers/CorsairController/CorsairDeviceGuard.h @@ -14,6 +14,10 @@ #include "DeviceGuard.h" #ifdef _WIN32 +/*---------------------------------------------------------*\ +| Windows interferes with std::max unless NOMINMAX defined | +\*---------------------------------------------------------*/ +#define NOMINMAX #include #endif diff --git a/Controllers/CorsairICueLinkController/CorsairICueLinkController.cpp b/Controllers/CorsairICueLinkController/CorsairICueLinkController.cpp new file mode 100644 index 00000000..26c9fd3a --- /dev/null +++ b/Controllers/CorsairICueLinkController/CorsairICueLinkController.cpp @@ -0,0 +1,280 @@ +/*---------------------------------------------------------*\ +| CorsairICueLinkController.cpp | +| | +| Driver for Corsair iCue Link System Hub | +| | +| Aiden Vigue (acvigue) 02 Mar 2025 | +| Adam Honse 01 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include + +#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 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 endpoint_data = Read(CORSAIR_ICUE_LINK_MODE_GET_DEVICES, CORSAIR_ICUE_LINK_DATA_TYPE_GET_DEVICES); + unsigned char channel = endpoint_data[6]; + std::vector index = std::vector(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 endpoint_metadata = std::vector(index.begin() + pos, index.begin() + pos + 8); + std::vector endpoint_id = std::vector(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 CorsairICueLinkController::GetEndpoints() +{ + return(endpoints); +} + +void CorsairICueLinkController::UpdateLights(RGBColor* colors, std::size_t num_colors) +{ + /*-------------------------------------------------*\ + | Send color buffer, packed RGBRGBRGB | + \*-------------------------------------------------*/ + std::vector 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> CorsairICueLinkController::ProcessMultiChunkPacket(const std::vector& data, size_t max_chunk_size) +{ + std::vector> result; + size_t offset = 0; + + while(offset < data.size()) + { + size_t end = std::min(max_chunk_size, data.size() - offset); + std::vector chunk(data.begin() + offset, data.begin() + offset + end); + result.push_back(chunk); + offset += end; + } + + return result; +} + +std::vector CorsairICueLinkController::SendCommand(std::vector command, std::vector data, std::vector waitForDataType) +{ + DeviceGuardLock lock = guard_manager_ptr->AwaitExclusiveAccess(); + + std::vector 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 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 CorsairICueLinkController::Read(std::vector endpoint, std::vector 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 res = SendCommand(CORSAIR_ICUE_LINK_CMD_READ, { }, data_type); + SendCommand(CORSAIR_ICUE_LINK_CMD_CLOSE_ENDPOINT, endpoint, { }); + + return res; +} + +void CorsairICueLinkController::Write(std::vector endpoint, std::vector data_type, std::vector data, CORSAIR_ICUE_ENDPOINT_TYPE endpoint_type) +{ + DeviceGuardLock lock = guard_manager_ptr->AwaitExclusiveAccess(); + + std::vector 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 write_color_ep = CORSAIR_ICUE_LINK_CMD_WRITE_COLOR; + std::vector> 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, { }); +} diff --git a/Controllers/CorsairICueLinkController/CorsairICueLinkController.h b/Controllers/CorsairICueLinkController/CorsairICueLinkController.h new file mode 100644 index 00000000..fcc51e66 --- /dev/null +++ b/Controllers/CorsairICueLinkController/CorsairICueLinkController.h @@ -0,0 +1,58 @@ +/*---------------------------------------------------------*\ +| CorsairICueLinkController.h | +| | +| Driver for Corsair iCue Link System Hub | +| | +| Aiden Vigue (acvigue) 02 Mar 2025 | +| Adam Honse 01 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include + +#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 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 endpoints; + + void InitHub(); + + std::vector> ProcessMultiChunkPacket(const std::vector& data, size_t max_chunk_size); + std::vector SendCommand(std::vector command, std::vector data, std::vector waitForDataType); + + std::vector Read(std::vector endpoint, std::vector data_type); + void Write(std::vector endpoint, std::vector data_type, std::vector data, CORSAIR_ICUE_ENDPOINT_TYPE endpoint_type); + +}; diff --git a/Controllers/CorsairICueLinkController/CorsairICueLinkControllerDetect.cpp b/Controllers/CorsairICueLinkController/CorsairICueLinkControllerDetect.cpp new file mode 100644 index 00000000..91e1f396 --- /dev/null +++ b/Controllers/CorsairICueLinkController/CorsairICueLinkControllerDetect.cpp @@ -0,0 +1,35 @@ +/*---------------------------------------------------------*\ +| CorsairICueLinkControllerDetect.cpp | +| | +| Detector for Corsair iCue Link System Hub | +| | +| Aiden Vigue (acvigue) 02 Mar 2025 | +| Adam Honse 01 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#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); diff --git a/Controllers/CorsairICueLinkController/CorsairICueLinkProtocol.cpp b/Controllers/CorsairICueLinkController/CorsairICueLinkProtocol.cpp new file mode 100644 index 00000000..f3244cca --- /dev/null +++ b/Controllers/CorsairICueLinkController/CorsairICueLinkProtocol.cpp @@ -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; +} diff --git a/Controllers/CorsairICueLinkController/CorsairICueLinkProtocol.h b/Controllers/CorsairICueLinkController/CorsairICueLinkProtocol.h new file mode 100644 index 00000000..442c9dbb --- /dev/null +++ b/Controllers/CorsairICueLinkController/CorsairICueLinkProtocol.h @@ -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 + +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); \ No newline at end of file diff --git a/Controllers/CorsairICueLinkController/RGBController_CorsairICueLink.cpp b/Controllers/CorsairICueLinkController/RGBController_CorsairICueLink.cpp new file mode 100644 index 00000000..90fa007d --- /dev/null +++ b/Controllers/CorsairICueLinkController/RGBController_CorsairICueLink.cpp @@ -0,0 +1,126 @@ +/*---------------------------------------------------------*\ +| RGBController_CorsairICueLink.cpp | +| | +| Driver for Corsair iCue Link Devices | +| | +| Aiden Vigue (acvigue) 02 Mar 2025 | +| Adam Honse 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); + } +} \ No newline at end of file diff --git a/Controllers/CorsairICueLinkController/RGBController_CorsairICueLink.h b/Controllers/CorsairICueLinkController/RGBController_CorsairICueLink.h new file mode 100644 index 00000000..a8839e4f --- /dev/null +++ b/Controllers/CorsairICueLinkController/RGBController_CorsairICueLink.h @@ -0,0 +1,43 @@ +/*---------------------------------------------------------*\ +| RGBController_CorsairICueLink.h | +| | +| RGBController for Corsair iCue Link Devices | +| | +| Aiden Vigue (acvigue) 02 Mar 2025 | +| Adam Honse 01 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#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 keepalive_thread_run; + std::chrono::time_point last_commit_time; + + void KeepaliveThread(); +};