Skip to content

Commit efb19ab

Browse files
midgetspyCalcProgrammer1
authored andcommitted
Add support for CoolerMaster RGB Controller
Commits squashed and amended for code style/brightness control by Adam Honse <calcprogrammer1@gmail.com>
1 parent 85631bf commit efb19ab

File tree

6 files changed

+845
-0
lines changed

6 files changed

+845
-0
lines changed
Lines changed: 367 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,367 @@
1+
/*-------------------------------------------------------------------*\
2+
| CMRGBController.cpp |
3+
| |
4+
| Driver for Coolermaster RGB USB Controller |
5+
| |
6+
| Nic W (midgetspy) 13th Apr 2021 |
7+
| |
8+
\*-------------------------------------------------------------------*/
9+
10+
#include "RGBController_CMRGBController.h"
11+
#include "CMRGBController.h"
12+
#include <cstring>
13+
14+
CMRGBController::CMRGBController(hid_device* dev_handle, char* path)
15+
{
16+
const int szTemp = 256;
17+
wchar_t tmpName[szTemp];
18+
19+
dev = dev_handle;
20+
location = path;
21+
22+
hid_get_manufacturer_string(dev, tmpName, szTemp);
23+
std::wstring wName = std::wstring(tmpName);
24+
device_name = std::string(wName.begin(), wName.end());
25+
26+
hid_get_product_string(dev, tmpName, szTemp);
27+
wName = std::wstring(tmpName);
28+
device_name.append(" ").append(std::string(wName.begin(), wName.end()));
29+
30+
hid_get_serial_number_string(dev, tmpName, szTemp);
31+
wName = std::wstring(tmpName);
32+
serial = std::string(wName.begin(), wName.end());
33+
34+
ReadCurrentMode();
35+
}
36+
37+
void CMRGBController::SendFlowControl(unsigned char byte_flag)
38+
{
39+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
40+
unsigned char buffer[buffer_size] = { 0x00, CM_RGBC_OPCODE_OP_FLOW_CONTROL }; //Packets on Windows need a 0x00 if they don't use ReportIDs
41+
42+
buffer[0x02] = byte_flag;
43+
44+
hid_write(dev, buffer, buffer_size);
45+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
46+
}
47+
48+
void CMRGBController::SendApply()
49+
{
50+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
51+
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
52+
53+
hid_write(dev, buffer, buffer_size);
54+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
55+
}
56+
57+
void CMRGBController::SendReadMode()
58+
{
59+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
60+
unsigned char buffer[buffer_size] = { };
61+
62+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
63+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_MODE;
64+
65+
hid_write(dev, buffer, buffer_size);
66+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
67+
68+
current_mode = buffer[CM_RGBC_PACKET_OFFSET_MODE];
69+
}
70+
71+
void CMRGBController::SendSetMode(unsigned char mode)
72+
{
73+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
74+
unsigned char buffer[buffer_size] = { };
75+
76+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
77+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_MODE;
78+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
79+
80+
hid_write(dev, buffer, buffer_size);
81+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
82+
}
83+
84+
void CMRGBController::SendSetCustomColors(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4)
85+
{
86+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
87+
unsigned char buffer[buffer_size] = { };
88+
89+
current_port1_color = color_1;
90+
current_port2_color = color_2;
91+
current_port3_color = color_3;
92+
current_port4_color = color_4;
93+
94+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
95+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_LED_INFO;
96+
97+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1] = RGBGetRValue(color_1);
98+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 1] = RGBGetGValue(color_1);
99+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 2] = RGBGetBValue(color_1);
100+
101+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2] = RGBGetRValue(color_2);
102+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 1] = RGBGetGValue(color_2);
103+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 2] = RGBGetBValue(color_2);
104+
105+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3] = RGBGetRValue(color_3);
106+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 1] = RGBGetGValue(color_3);
107+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 2] = RGBGetBValue(color_3);
108+
109+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4] = RGBGetRValue(color_4);
110+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 1] = RGBGetGValue(color_4);
111+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 2] = RGBGetBValue(color_4);
112+
113+
hid_write(dev, buffer, buffer_size);
114+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
115+
}
116+
117+
void CMRGBController::SendReadCustomColors()
118+
{
119+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
120+
unsigned char buffer[buffer_size] = { };
121+
122+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
123+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_LED_INFO;
124+
125+
hid_write(dev, buffer, buffer_size);
126+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
127+
128+
current_port1_color = ToRGBColor(
129+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1],
130+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 1],
131+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 2]);
132+
current_port2_color = ToRGBColor(
133+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2],
134+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 1],
135+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 2]);
136+
current_port3_color = ToRGBColor(
137+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3],
138+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 1],
139+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 2]);
140+
current_port4_color = ToRGBColor(
141+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4],
142+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 1],
143+
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 2]);
144+
}
145+
146+
void CMRGBController::SendSetConfig(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2, bool simplified=false, bool multilayer=false)
147+
{
148+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
149+
unsigned char buffer[buffer_size] = { };
150+
151+
current_mode = mode;
152+
current_speed = speed;
153+
current_brightness = brightness;
154+
current_mode_color_1 = color_1;
155+
current_mode_color_2 = color_2;
156+
157+
/*---------------------------------------------*\
158+
| Handle special cases |
159+
\*---------------------------------------------*/
160+
switch(mode)
161+
{
162+
case CM_RGBC_MODE_COLOR_CYCLE:
163+
brightness = 0xDF;
164+
color_1 = 0xFFFFFF;
165+
color_2 = 0x000000;
166+
break;
167+
168+
case CM_RGBC_MODE_OFF:
169+
brightness = 0x03;
170+
break;
171+
}
172+
173+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
174+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = simplified ? CM_RGBC_OPCODE_TYPE_CONFIG_SIMPLIFIED : CM_RGBC_OPCODE_TYPE_CONFIG_FULL;
175+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
176+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_SPEED] = speed;
177+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_BRIGHTNESS] = brightness;
178+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1] = RGBGetRValue(color_1);
179+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1 + 1] = RGBGetGValue(color_1);
180+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1 + 2] = RGBGetBValue(color_1);
181+
182+
/*---------------------------------------------*\
183+
| Magic values, meaning unknown |
184+
\*---------------------------------------------*/
185+
buffer[REPORT_ID_OFFSET + 0x06] = (mode == CM_RGBC_MODE_BREATHING) ? 0x20 : 0x00;
186+
buffer[REPORT_ID_OFFSET + 0x07] = (mode == CM_RGBC_MODE_STAR) ? 0x19 : 0xFF;
187+
buffer[REPORT_ID_OFFSET + 0x08] = 0xFF;
188+
189+
if(!simplified)
190+
{
191+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTILAYER] = multilayer ? 0x01 : 0x00;
192+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2] = RGBGetRValue(color_2);
193+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2 + 1] = RGBGetGValue(color_2);
194+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2 + 2] = RGBGetBValue(color_2);
195+
196+
for(int i = REPORT_ID_OFFSET + 16; i < CM_RGBC_PACKET_SIZE; i++)
197+
{
198+
buffer[i] = 0xFF;
199+
}
200+
}
201+
202+
hid_write(dev, buffer, buffer_size);
203+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
204+
}
205+
206+
void CMRGBController::SendReadConfig(unsigned char mode)
207+
{
208+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
209+
unsigned char buffer[buffer_size] = { };
210+
211+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
212+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_CONFIG_FULL;
213+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
214+
215+
hid_write(dev, buffer, buffer_size);
216+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
217+
218+
current_mode = mode;
219+
current_speed = buffer[CM_RGBC_PACKET_OFFSET_SPEED];
220+
current_brightness = buffer[CM_RGBC_PACKET_OFFSET_BRIGHTNESS];
221+
222+
current_mode_color_1 = ToRGBColor(
223+
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1],
224+
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1 + 1],
225+
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1 + 2]);
226+
current_mode_color_2 = ToRGBColor(
227+
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2],
228+
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2 + 1],
229+
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2 + 2]);
230+
}
231+
232+
void CMRGBController::SendCustomColorStart()
233+
{
234+
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
235+
unsigned char buffer[buffer_size] = { };
236+
237+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
238+
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_UNKNOWN_30;
239+
240+
hid_write(dev, buffer, buffer_size);
241+
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
242+
}
243+
244+
void CMRGBController::ReadCurrentMode()
245+
{
246+
SendFlowControl(CM_RGBC_OPCODE_FLOW_01);
247+
248+
SendReadMode();
249+
}
250+
251+
void CMRGBController::ReadModeConfig(unsigned char mode)
252+
{
253+
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
254+
255+
SendReadConfig(mode);
256+
257+
if(mode == CM_RGBC_MODE_MULTIPLE)
258+
{
259+
SendReadCustomColors();
260+
}
261+
}
262+
263+
void CMRGBController::SetMode(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2)
264+
{
265+
SendFlowControl(CM_RGBC_OPCODE_FLOW_01);
266+
267+
SendSetConfig(mode, speed, brightness, color_1, color_2, false);
268+
269+
SendSetMode(mode);
270+
271+
SendApply();
272+
273+
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
274+
}
275+
276+
void CMRGBController::SetLedsDirect(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4)
277+
{
278+
SendFlowControl(CM_RGBC_OPCODE_FLOW_80);
279+
280+
SendCustomColorStart();
281+
282+
SendSetCustomColors(color_1, color_2, color_3, color_4);
283+
284+
SendSetMode(CM_RGBC_MODE_MULTIPLE);
285+
286+
SendCustomColorStart();
287+
288+
SendSetConfig(CM_RGBC_MODE_MULTIPLE, 0x00, 0xFF, color_1, 0x000000, false);
289+
290+
SendApply();
291+
292+
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
293+
}
294+
295+
std::string CMRGBController::GetDeviceName()
296+
{
297+
return(device_name);
298+
}
299+
300+
std::string CMRGBController::GetSerial()
301+
{
302+
return(serial);
303+
}
304+
305+
std::string CMRGBController::GetLocation()
306+
{
307+
return("HID: " + location);
308+
}
309+
310+
unsigned char CMRGBController::GetMode()
311+
{
312+
return(current_mode);
313+
}
314+
315+
unsigned char CMRGBController::GetSpeed()
316+
{
317+
return(current_speed);
318+
}
319+
320+
unsigned char CMRGBController::GetBrightness()
321+
{
322+
return(current_brightness);
323+
}
324+
325+
RGBColor CMRGBController::GetModeColor(int color_number)
326+
{
327+
switch(color_number)
328+
{
329+
case 0:
330+
return(current_mode_color_1);
331+
332+
case 1:
333+
return(current_mode_color_2);
334+
335+
default:
336+
return(ToRGBColor(0, 0, 0));
337+
}
338+
}
339+
340+
RGBColor CMRGBController::GetPortColor(int port_number)
341+
{
342+
switch(port_number)
343+
{
344+
case 0:
345+
return(current_port1_color);
346+
347+
case 1:
348+
return(current_port2_color);
349+
350+
case 2:
351+
return(current_port3_color);
352+
353+
case 3:
354+
return(current_port4_color);
355+
356+
default:
357+
return(ToRGBColor(0, 0, 0));
358+
}
359+
}
360+
361+
CMRGBController::~CMRGBController()
362+
{
363+
if(dev)
364+
{
365+
hid_close(dev);
366+
}
367+
}

0 commit comments

Comments
 (0)