From fe11115f32b33ea0cab7b9df6e66dffd0d9f2d02 Mon Sep 17 00:00:00 2001 From: Jeff P Date: Sat, 5 Jun 2021 03:23:51 +0000 Subject: [PATCH] Add support for Corsair Commander Core / Elite Capellix Amended for code style by Adam Honse --- .../CorsairCommanderCoreController.cpp | 276 ++++++++++++++++++ .../CorsairCommanderCoreController.h | 65 +++++ .../CorsairCommanderCoreControllerDetect.cpp | 41 +++ .../RGBController_CorsairCommanderCore.cpp | 125 ++++++++ .../RGBController_CorsairCommanderCore.h | 33 +++ OpenRGB.pro | 6 + 6 files changed, 546 insertions(+) create mode 100644 Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.cpp create mode 100644 Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.h create mode 100644 Controllers/CorsairCommanderCoreController/CorsairCommanderCoreControllerDetect.cpp create mode 100644 Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.cpp create mode 100644 Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.h diff --git a/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.cpp b/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.cpp new file mode 100644 index 00000000..0c6b772d --- /dev/null +++ b/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.cpp @@ -0,0 +1,276 @@ +/*---------------------------------------------------------*\ +| CorsairCommanderCoreController.cpp | +| | +| Processing Code for Corsair Commander Core | +| | +| Jeff P. | +\*---------------------------------------------------------*/ + +#include "CorsairCommanderCoreController.h" + +#include +#include +#include + +using namespace std::chrono_literals; + +CorsairCommanderCoreController::CorsairCommanderCoreController(hid_device* dev_handle, const char* path) +{ + dev = dev_handle; + location = path; + keepalive_thread_run = 1; + controller_ready = 0; + + /*-----------------------------------------------------*\ + | Initialize controller | + \*-----------------------------------------------------*/ + InitController(); + + /*-----------------------------------------------------*\ + | Start keepalive thread | + \*-----------------------------------------------------*/ + keepalive_thread = new std::thread(&CorsairCommanderCoreController::KeepaliveThread, this); +} + +CorsairCommanderCoreController::~CorsairCommanderCoreController() +{ + /*-----------------------------------------------------*\ + | Close keepalive thread | + \*-----------------------------------------------------*/ + keepalive_thread_run = 0; + keepalive_thread->join(); + delete keepalive_thread; + + /*-----------------------------------------------------*\ + | Close HID device | + \*-----------------------------------------------------*/ + hid_close(dev); +} + +void CorsairCommanderCoreController::InitController() +{ + /*-----------------------------------------------------*\ + | Packet sequence to put controller into direct mode | + \*-----------------------------------------------------*/ + unsigned char buffarray[][5] = + { + {0x08, 0x01, 0x03, 0x00, 0x02}, + {0x08, 0x0D, 0x00, 0x22, 0x00}, + }; + + SendMultiPkt(buffarray, sizeof(buffarray) / sizeof(buffarray[0]), sizeof(buffarray)[0] / sizeof(buffarray[0][0])); + SetFanMode(); +} + +std::string CorsairCommanderCoreController::GetLocationString() +{ + return("HID: " + location); +} + +void CorsairCommanderCoreController::KeepaliveThread() +{ + while(keepalive_thread_run.load()) + { + if (controller_ready) + { + if((std::chrono::steady_clock::now() - last_commit_time) > std::chrono::seconds(10)) + { + SendCommit(); + } + } + std::this_thread::sleep_for(1s); + } +} + +void CorsairCommanderCoreController::SendCommit() +{ + if(!lastcolors.empty()) + { + /*-----------------------------------------------------*\ + | If colors remain to be sent, send them | + \*-----------------------------------------------------*/ + SetDirectColor(lastcolors, lastzones); + } + else + { + unsigned char usb_buf[1025]; + + /*-----------------------------------------------------*\ + | Zero out buffer | + \*-----------------------------------------------------*/ + memset(usb_buf, 0x00, sizeof(usb_buf)); + + /*-----------------------------------------------------*\ + | Update last commit time | + \*-----------------------------------------------------*/ + last_commit_time = std::chrono::steady_clock::now(); + + /*-----------------------------------------------------*\ + | Set up Commit packet | + \*-----------------------------------------------------*/ + memset(usb_buf, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + + usb_buf[0] = 0x00; + usb_buf[1] = 0x08; + usb_buf[2] = 0x06; + usb_buf[4] = 0xBD; + usb_buf[5] = 0x02; + usb_buf[8] = 0x12; + + hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + } +} + + +void CorsairCommanderCoreController::SendMultiPkt(unsigned char buffarray[][5], int r, int c) +{ + /*---------------------------------------------------------*\ + | Private function to send multiple packets | + \*---------------------------------------------------------*/ + unsigned char* hidtemp = new unsigned char[CORSAIR_COMMANDER_CORE_PACKET_SIZE]; + + for(unsigned int i = 0; i < r; i++) + { + memset(hidtemp, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + + for(unsigned int j = 0; j < c; j++) + { + hidtemp[j+1] = buffarray[i][j]; + } + + hid_write(dev, hidtemp, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + hid_read(dev, hidtemp, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + } +} + +void CorsairCommanderCoreController::SetDirectColor + ( + std::vector colors, + std::vector zones + ) +{ + if(controller_ready == 1 && ((std::chrono::steady_clock::now() - last_commit_time) > std::chrono::milliseconds(33))) + { + lastcolors = colors; + lastzones = zones; + int packet_offset = CORSAIR_COMMANDER_CORE_PREAMBLE_OFFSET; + int led_idx = 0; + int channel_idx = 0; + unsigned char* usb_buf = new unsigned char[CORSAIR_COMMANDER_CORE_PACKET_SIZE]; + + memset(usb_buf, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + + /*-----------------------------------------------------*\ + | Prepare color information packet | + \*-----------------------------------------------------*/ + usb_buf[0] = 0x00; + usb_buf[1] = 0x08; + usb_buf[2] = 0x06; + usb_buf[4] = 0xBD; + usb_buf[5] = 0x02; + usb_buf[8] = 0x12; + + for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++) + { + /*-------------------------------------------------*\ + | Add led colors | + \*-------------------------------------------------*/ + for(unsigned int i = led_idx; i < led_idx + zones[zone_idx].leds_count; i++) + { + usb_buf[packet_offset] = RGBGetRValue(colors[i]); + usb_buf[packet_offset+1] = RGBGetGValue(colors[i]); + usb_buf[packet_offset+2] = RGBGetBValue(colors[i]); + + packet_offset = packet_offset + 3; + } + + led_idx = led_idx + zones[zone_idx].leds_count; + + /*-------------------------------------------------*\ + | Move offset for pump zone with less than 29 LEDs | + \*-------------------------------------------------*/ + if(zone_idx == 0) + { + packet_offset = packet_offset + 3 * (29 - zones[zone_idx].leds_count); + } + + /*-------------------------------------------------*\ + | Move offset for fans with less than 34 LEDs | + \*-------------------------------------------------*/ + if(zone_idx != 0) + { + packet_offset = packet_offset + 3 * (34 - zones[zone_idx].leds_count); + } + + channel_idx++; + } + + /*-----------------------------------------------------*\ + | Sending a direct mode color packet resets the timeout | + \*-----------------------------------------------------*/ + last_commit_time = std::chrono::steady_clock::now(); + + hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + } +} + +void CorsairCommanderCoreController::SetFanMode() +{ + /*--------------------------------------------------------------------------------------------------*\ + | Force controller to 6 QL fan mode to expose maximum number of LEDs per rgb port (34 LEDs per port) | + \*--------------------------------------------------------------------------------------------------*/ + + unsigned char usb_buf[1025]; + + unsigned char buffarray4[][5] = + { + {0x08, 0x05, 0x01, 0x01, 0x00}, + {0x08, 0x0D, 0x01, 0x1E, 0x00}, + {0x08, 0x09, 0x01, 0x00, 0x00} + }; + + SendMultiPkt(buffarray4, sizeof(buffarray4) / sizeof(buffarray4[0]), sizeof(buffarray4)[0] / sizeof(buffarray4[0][0])); + + memset(usb_buf, 0, sizeof(usb_buf)); + + usb_buf[0] = 0x00; + usb_buf[1] = 0x08; + usb_buf[2] = 0x06; + usb_buf[3] = 0x01; + usb_buf[4] = 0x11; + usb_buf[8] = 0x0D; + usb_buf[10] = 0x07; + usb_buf[11] = 0x01; + usb_buf[12] = 0x08; + + for(unsigned int i = 13; i < 25; i = i + 2) + { + usb_buf[i] = 0x01; + usb_buf[i + 1] = 0x06; + } + + hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + hid_read(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + + unsigned char buffarray2[][5] = + { + {0x08, 0x05, 0x01, 0x01, 0x00}, + {0x08, 0x15, 0x01, 0x00, 0x00} + }; + + SendMultiPkt(buffarray2, sizeof(buffarray2) / sizeof(buffarray2[0]), sizeof(buffarray2)[0] / sizeof(buffarray2[0][0])); + + memset(usb_buf, 0, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + + usb_buf[0] = 0x00; + usb_buf[1] = 0x08; + usb_buf[2] = 0x06; + usb_buf[4] = 0xBD; + usb_buf[5] = 0x02; + usb_buf[8] = 0x12; + + hid_write(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + hid_read(dev, usb_buf, CORSAIR_COMMANDER_CORE_PACKET_SIZE); + + controller_ready = 1; +} diff --git a/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.h b/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.h new file mode 100644 index 00000000..25bb8ff4 --- /dev/null +++ b/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.h @@ -0,0 +1,65 @@ +/*---------------------------------------------------------*\ +| CorsairCommanderCoreController.h | +| | +| Definitions for Corsair Commander Core | +| Based on code by: | +| Adam Honse (calcprogrammer1@gmail.com), 8/17/2020 | +| | +| Jeff P. | +\*---------------------------------------------------------*/ + +#include "RGBController.h" +#include +#include +#include + +#pragma once + +#define CORSAIR_COMMANDER_CORE_PACKET_SIZE 1025 +#define CORSAIR_COMMANDER_CORE_PREAMBLE_OFFSET 10 +#define CORSAIR_ELITE_CAPELLIX_PUMP_LED_OFFSET 87 +#define CORSAIR_QL_FAN_ZONE_OFFSET 102 +#define CORSAIR_COMMANDER_CORE_NUM_CHANNELS 6 + +enum +{ + CORSAIR_COMMANDER_CORE_MODE_DIRECT = 0x00, +}; + +class CorsairCommanderCoreController +{ +public: + CorsairCommanderCoreController(hid_device* dev_handle, const char* path); + ~CorsairCommanderCoreController(); + + std::string GetLocationString(); + + void SetDirectColor + ( + std::vector, + std::vector + ); + + void KeepaliveThread(); + void SetFanMode(); + +private: + hid_device* dev; + std::thread* keepalive_thread; + std::atomic keepalive_thread_run; + std::atomic controller_ready; + std::string location; + std::vector lastcolors; + std::vector lastzones; + std::chrono::time_point last_commit_time; + + void SendMultiPkt + ( + unsigned char buffarray[][5], + int r, + int c + ); + + void SendCommit(); + void InitController(); +}; diff --git a/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreControllerDetect.cpp b/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreControllerDetect.cpp new file mode 100644 index 00000000..11807c9f --- /dev/null +++ b/Controllers/CorsairCommanderCoreController/CorsairCommanderCoreControllerDetect.cpp @@ -0,0 +1,41 @@ +#include "Detector.h" +#include "CorsairCommanderCoreController.h" +#include "RGBController.h" +#include "RGBController_CorsairCommanderCore.h" +#include +#include + +/*-----------------------------------------------------*\ +| Corsair vendor ID | +\*-----------------------------------------------------*/ +#define CORSAIR_VID 0x1B1C + +/*-----------------------------------------------------*\ +| Commander Core product IDs | +\*-----------------------------------------------------*/ +#define CORSAIR_H150I_COMMANDER_CORE_PID 0x0C1C + +/******************************************************************************************\ +* * +* DetectCorsairCapellixControllers * +* * +* Tests the USB address to see if a Corsair RGB Cooler controller exists there. * +* * +\******************************************************************************************/ + +void DetectCorsairCapellixHIDControllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + CorsairCommanderCoreController* controller = new CorsairCommanderCoreController(dev, info->path); + RGBController_CorsairCommanderCore* rgb_controller = new RGBController_CorsairCommanderCore(controller); + + rgb_controller->name = name; + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + +REGISTER_HID_DETECTOR_PU("Corsair Commander Core", DetectCorsairCapellixHIDControllers, CORSAIR_VID, CORSAIR_H150I_COMMANDER_CORE_PID, 0xFF42, 0x01); diff --git a/Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.cpp b/Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.cpp new file mode 100644 index 00000000..f1d4774e --- /dev/null +++ b/Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.cpp @@ -0,0 +1,125 @@ +/*-----------------------------------------*\ +| RGBController_CorsairCapellix.cpp | +| | +| Generic RGB Interface for Corsair | +| Commander Core | +| | +| Jeff P. | +\*-----------------------------------------*/ + +#include "RGBController_CorsairCommanderCore.h" + +RGBController_CorsairCommanderCore::RGBController_CorsairCommanderCore(CorsairCommanderCoreController* corsair_ptr) +{ + corsair = corsair_ptr; + + vendor = "Corsair"; + description = "Corsair Commander Core"; + type = DEVICE_TYPE_COOLER; + location = corsair->GetLocationString(); + + SetupZones(); + + 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); +} + +RGBController_CorsairCommanderCore::~RGBController_CorsairCommanderCore() +{ + delete corsair; +} + +void RGBController_CorsairCommanderCore::SetupZones() +{ + std::atomic first_run; + first_run = 0; + + if(zones.size() == 0) + { + first_run = 1; + } + + zones.resize(7); + zones[0].name = "Pump"; + zones[0].type = ZONE_TYPE_LINEAR; + zones[0].leds_min = 0; + zones[0].leds_max = 29; + + for(unsigned int i = 1; i < (CORSAIR_COMMANDER_CORE_NUM_CHANNELS + 1); i++) + { + zones[i].name = "RGB Port " + std::to_string(i); + zones[i].type = ZONE_TYPE_LINEAR; + zones[i].leds_min = 0; + zones[i].leds_max = 34; + + if(first_run) + { + zones[i].leds_count = 0; + } + } + + leds.clear(); + colors.clear(); + + for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++) + { + for (unsigned int led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++) + { + led new_led; + new_led.name = zones[zone_idx].name + " LED " + std::to_string(led_idx+1); + + leds.push_back(new_led); + } + } + + SetupColors(); +} + +void RGBController_CorsairCommanderCore::ResizeZone(int zone, int new_size) +{ + if((size_t) zone >= zones.size()) + { + return; + } + + if(((unsigned int)new_size >= zones[zone].leds_min) && ((unsigned int)new_size <= zones[zone].leds_max)) + { + zones[zone].leds_count = new_size; + + SetupZones(); + } +} + +void RGBController_CorsairCommanderCore::DeviceUpdateLEDs() +{ + DeviceUpdateMode(); +} + +void RGBController_CorsairCommanderCore::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_CorsairCommanderCore::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_CorsairCommanderCore::SetCustomMode() +{ + active_mode = 0; +} + +void RGBController_CorsairCommanderCore::DeviceUpdateMode() +{ + switch(modes[active_mode].value) + { + case CORSAIR_COMMANDER_CORE_MODE_DIRECT: + corsair->SetDirectColor(colors, zones); + break; + } +} diff --git a/Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.h b/Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.h new file mode 100644 index 00000000..460b5b6c --- /dev/null +++ b/Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.h @@ -0,0 +1,33 @@ +/*-----------------------------------------*\ +| RGBController_CorsairCapellix.h | +| | +| Generic RGB Interface for Corsair | +| Commander Core | +| | +| Jeff P. | +\*-----------------------------------------*/ + +#pragma once +#include "RGBController.h" +#include "CorsairCommanderCoreController.h" + +class RGBController_CorsairCommanderCore : public RGBController +{ +public: + RGBController_CorsairCommanderCore(CorsairCommanderCoreController* corsair_ptr); + ~RGBController_CorsairCommanderCore(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void SetCustomMode(); + void DeviceUpdateMode(); + +private: + CorsairCommanderCoreController* corsair; + std::vector fanleds{0}; +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index 21bfc191..ecc73ba8 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -68,6 +68,7 @@ INCLUDEPATH += Controllers/AsusAuraSMBusController/ \ Controllers/AsusAuraUSBController/ \ Controllers/CoolerMasterController/ \ + Controllers/CorsairCommanderCoreController/ \ Controllers/CorsairDominatorPlatinumController/ \ Controllers/CorsairHydroController/ \ Controllers/CorsairHydroPlatinumController/ \ @@ -200,6 +201,8 @@ HEADERS += Controllers/CoolerMasterController/RGBController_CMSmallARGBController.h \ Controllers/CoolerMasterController/RGBController_CMR6000Controller.h \ Controllers/CoolerMasterController/RGBController_CMMKController.h \ + Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.h \ + Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.h \ Controllers/CorsairDominatorPlatinumController/CorsairDominatorPlatinumController.h \ Controllers/CorsairDominatorPlatinumController/RGBController_CorsairDominatorPlatinum.h \ Controllers/CorsairHydroController/CorsairHydroController.h \ @@ -480,6 +483,9 @@ SOURCES += Controllers/CoolerMasterController/RGBController_CMSmallARGBController.cpp \ Controllers/CoolerMasterController/RGBController_CMR6000Controller.cpp \ Controllers/CoolerMasterController/RGBController_CMMKController.cpp \ + Controllers/CorsairCommanderCoreController/CorsairCommanderCoreController.cpp \ + Controllers/CorsairCommanderCoreController/CorsairCommanderCoreControllerDetect.cpp \ + Controllers/CorsairCommanderCoreController/RGBController_CorsairCommanderCore.cpp \ Controllers/CorsairDominatorPlatinumController/CorsairDominatorPlatinumController.cpp \ Controllers/CorsairDominatorPlatinumController/CorsairDominatorPlatinumControllerDetect.cpp \ Controllers/CorsairDominatorPlatinumController/RGBController_CorsairDominatorPlatinum.cpp \