Files
OpenRGB/Controllers/CoolerMasterController/CMRGBController.cpp
Nic Wolfe efb19ab6c6 Add support for CoolerMaster RGB Controller
Commits squashed and amended for code style/brightness control by Adam Honse <calcprogrammer1@gmail.com>
2021-07-07 22:55:24 -05:00

368 lines
13 KiB
C++

/*-------------------------------------------------------------------*\
| CMRGBController.cpp |
| |
| Driver for Coolermaster RGB USB Controller |
| |
| Nic W (midgetspy) 13th Apr 2021 |
| |
\*-------------------------------------------------------------------*/
#include "RGBController_CMRGBController.h"
#include "CMRGBController.h"
#include <cstring>
CMRGBController::CMRGBController(hid_device* dev_handle, char* path)
{
const int szTemp = 256;
wchar_t tmpName[szTemp];
dev = dev_handle;
location = path;
hid_get_manufacturer_string(dev, tmpName, szTemp);
std::wstring wName = std::wstring(tmpName);
device_name = std::string(wName.begin(), wName.end());
hid_get_product_string(dev, tmpName, szTemp);
wName = std::wstring(tmpName);
device_name.append(" ").append(std::string(wName.begin(), wName.end()));
hid_get_serial_number_string(dev, tmpName, szTemp);
wName = std::wstring(tmpName);
serial = std::string(wName.begin(), wName.end());
ReadCurrentMode();
}
void CMRGBController::SendFlowControl(unsigned char byte_flag)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { 0x00, CM_RGBC_OPCODE_OP_FLOW_CONTROL }; //Packets on Windows need a 0x00 if they don't use ReportIDs
buffer[0x02] = byte_flag;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendApply()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { 0x00, CM_RGBC_OPCODE_OP_UNKNOWN_50, CM_RGBC_OPCODE_TYPE_UNKNOWN_55 }; //Packets on Windows need a 0x00 if they don't use ReportIDs
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendReadMode()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_MODE;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
current_mode = buffer[CM_RGBC_PACKET_OFFSET_MODE];
}
void CMRGBController::SendSetMode(unsigned char mode)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_MODE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendSetCustomColors(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
current_port1_color = color_1;
current_port2_color = color_2;
current_port3_color = color_3;
current_port4_color = color_4;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_LED_INFO;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1] = RGBGetRValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 1] = RGBGetGValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 2] = RGBGetBValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2] = RGBGetRValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 1] = RGBGetGValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 2] = RGBGetBValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3] = RGBGetRValue(color_3);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 1] = RGBGetGValue(color_3);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 2] = RGBGetBValue(color_3);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4] = RGBGetRValue(color_4);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 1] = RGBGetGValue(color_4);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 2] = RGBGetBValue(color_4);
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendReadCustomColors()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_LED_INFO;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
current_port1_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 2]);
current_port2_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 2]);
current_port3_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 2]);
current_port4_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 2]);
}
void CMRGBController::SendSetConfig(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2, bool simplified=false, bool multilayer=false)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
current_mode = mode;
current_speed = speed;
current_brightness = brightness;
current_mode_color_1 = color_1;
current_mode_color_2 = color_2;
/*---------------------------------------------*\
| Handle special cases |
\*---------------------------------------------*/
switch(mode)
{
case CM_RGBC_MODE_COLOR_CYCLE:
brightness = 0xDF;
color_1 = 0xFFFFFF;
color_2 = 0x000000;
break;
case CM_RGBC_MODE_OFF:
brightness = 0x03;
break;
}
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = simplified ? CM_RGBC_OPCODE_TYPE_CONFIG_SIMPLIFIED : CM_RGBC_OPCODE_TYPE_CONFIG_FULL;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_SPEED] = speed;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_BRIGHTNESS] = brightness;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1] = RGBGetRValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1 + 1] = RGBGetGValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1 + 2] = RGBGetBValue(color_1);
/*---------------------------------------------*\
| Magic values, meaning unknown |
\*---------------------------------------------*/
buffer[REPORT_ID_OFFSET + 0x06] = (mode == CM_RGBC_MODE_BREATHING) ? 0x20 : 0x00;
buffer[REPORT_ID_OFFSET + 0x07] = (mode == CM_RGBC_MODE_STAR) ? 0x19 : 0xFF;
buffer[REPORT_ID_OFFSET + 0x08] = 0xFF;
if(!simplified)
{
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTILAYER] = multilayer ? 0x01 : 0x00;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2] = RGBGetRValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2 + 1] = RGBGetGValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2 + 2] = RGBGetBValue(color_2);
for(int i = REPORT_ID_OFFSET + 16; i < CM_RGBC_PACKET_SIZE; i++)
{
buffer[i] = 0xFF;
}
}
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendReadConfig(unsigned char mode)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_CONFIG_FULL;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
current_mode = mode;
current_speed = buffer[CM_RGBC_PACKET_OFFSET_SPEED];
current_brightness = buffer[CM_RGBC_PACKET_OFFSET_BRIGHTNESS];
current_mode_color_1 = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1 + 1],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1 + 2]);
current_mode_color_2 = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2 + 1],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2 + 2]);
}
void CMRGBController::SendCustomColorStart()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_UNKNOWN_30;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::ReadCurrentMode()
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_01);
SendReadMode();
}
void CMRGBController::ReadModeConfig(unsigned char mode)
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
SendReadConfig(mode);
if(mode == CM_RGBC_MODE_MULTIPLE)
{
SendReadCustomColors();
}
}
void CMRGBController::SetMode(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2)
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_01);
SendSetConfig(mode, speed, brightness, color_1, color_2, false);
SendSetMode(mode);
SendApply();
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
}
void CMRGBController::SetLedsDirect(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4)
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_80);
SendCustomColorStart();
SendSetCustomColors(color_1, color_2, color_3, color_4);
SendSetMode(CM_RGBC_MODE_MULTIPLE);
SendCustomColorStart();
SendSetConfig(CM_RGBC_MODE_MULTIPLE, 0x00, 0xFF, color_1, 0x000000, false);
SendApply();
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
}
std::string CMRGBController::GetDeviceName()
{
return(device_name);
}
std::string CMRGBController::GetSerial()
{
return(serial);
}
std::string CMRGBController::GetLocation()
{
return("HID: " + location);
}
unsigned char CMRGBController::GetMode()
{
return(current_mode);
}
unsigned char CMRGBController::GetSpeed()
{
return(current_speed);
}
unsigned char CMRGBController::GetBrightness()
{
return(current_brightness);
}
RGBColor CMRGBController::GetModeColor(int color_number)
{
switch(color_number)
{
case 0:
return(current_mode_color_1);
case 1:
return(current_mode_color_2);
default:
return(ToRGBColor(0, 0, 0));
}
}
RGBColor CMRGBController::GetPortColor(int port_number)
{
switch(port_number)
{
case 0:
return(current_port1_color);
case 1:
return(current_port2_color);
case 2:
return(current_port3_color);
case 3:
return(current_port4_color);
default:
return(ToRGBColor(0, 0, 0));
}
}
CMRGBController::~CMRGBController()
{
if(dev)
{
hid_close(dev);
}
}