1 /*
2 * This file is part of OpenCorsairLink.
3 * Copyright (C) 2017-2019 Sean Nelson <audiohacked@gmail.com>
4
5 * OpenCorsairLink is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 2 of the License, or
8 * any later version.
9
10 * OpenCorsairLink is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14
15 * You should have received a copy of the GNU General Public License
16 * along with OpenCorsairLink. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "device.h"
20 #include "driver.h"
21 #include "lowlevel/coolit.h"
22 #include "print.h"
23 #include "protocol/coolit.h"
24
25 #include <errno.h>
26 #include <libusb.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31
32 int
corsairlink_coolit_fan_count(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)33 corsairlink_coolit_fan_count(
34 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
35 {
36 int rr;
37 uint8_t response[64];
38 uint8_t commands[64];
39 memset( response, 0, sizeof( response ) );
40 memset( commands, 0, sizeof( commands ) );
41
42 uint8_t ii = 0;
43
44 commands[++ii] = CommandId++;
45 commands[++ii] = ReadOneByte;
46 commands[++ii] = FAN_Count;
47
48 commands[0] = ii;
49
50 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
51 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
52
53 ctrl->fan_count = response[2] - 1; // we subtract 1 because count includes pump
54
55 return rr;
56 }
57
58 int
corsairlink_coolit_fan_print_mode(uint8_t mode,uint16_t data,char * modestr,uint8_t modestr_size)59 corsairlink_coolit_fan_print_mode(
60 uint8_t mode, uint16_t data, char* modestr, uint8_t modestr_size )
61 {
62 int rr = 0;
63 uint8_t isConnected = mode & 0x80;
64 uint8_t is4pin = mode & 0x01;
65 uint8_t real_mode = mode & 0x0E;
66
67 if ( !isConnected )
68 snprintf( modestr, modestr_size, "Not connected or failed" );
69 else if ( real_mode == COOLIT_Performance )
70 snprintf( modestr, modestr_size, "Performance Mode (%s)", is4pin ? "4PIN" : "3PIN" );
71 else if ( real_mode == COOLIT_Balanced )
72 snprintf( modestr, modestr_size, "Balanced Mode (%s)", is4pin ? "4PIN" : "3PIN" );
73 else if ( real_mode == COOLIT_Quiet )
74 snprintf( modestr, modestr_size, "Quiet Mode (%s)", is4pin ? "4PIN" : "3PIN" );
75 else if ( real_mode == COOLIT_Default )
76 snprintf( modestr, modestr_size, "Default Mode (%s)", is4pin ? "4PIN" : "3PIN" );
77 else if ( real_mode == COOLIT_FixedPWM )
78 snprintf(
79 modestr, modestr_size, "Fixed PWM Mode (%s) set to %d%%", is4pin ? "4PIN" : "3PIN",
80 ( data + 1 ) * 100 / 256 );
81 else if ( real_mode == COOLIT_FixedRPM )
82 snprintf(
83 modestr, modestr_size, "Fixed RPM Mode (%s) set to %d", is4pin ? "4PIN" : "3PIN",
84 data );
85 else if ( real_mode == COOLIT_Custom )
86 snprintf( modestr, modestr_size, "Custom Curve Mode (%s)", is4pin ? "4PIN" : "3PIN" );
87 return rr;
88 }
89
90 int
corsairlink_coolit_fan_mode_read(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)91 corsairlink_coolit_fan_mode_read(
92 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
93 {
94 int rr;
95 uint8_t response[64];
96 uint8_t commands[64];
97 memset( response, 0, sizeof( response ) );
98 memset( commands, 0, sizeof( commands ) );
99
100 uint8_t ii = 0;
101 commands[++ii] = CommandId++;
102 commands[++ii] = WriteOneByte;
103 commands[++ii] = FAN_Select;
104 commands[++ii] = ctrl->channel;
105
106 commands[++ii] = CommandId++;
107 commands[++ii] = ReadOneByte;
108 commands[++ii] = FAN_Mode;
109
110 commands[0] = ii;
111
112 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
113 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
114
115 ctrl->mode = response[4];
116
117 return rr;
118 }
119
120 int
corsairlink_coolit_fan_mode_read_rpm(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)121 corsairlink_coolit_fan_mode_read_rpm(
122 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
123 {
124 int rr;
125 uint8_t response[64];
126 uint8_t commands[64];
127 memset( response, 0, sizeof( response ) );
128 memset( commands, 0, sizeof( commands ) );
129
130 uint8_t ii = 0;
131 commands[++ii] = CommandId++;
132 commands[++ii] = WriteOneByte;
133 commands[++ii] = FAN_Select;
134 commands[++ii] = ctrl->channel;
135
136 commands[++ii] = CommandId++;
137 commands[++ii] = ReadOneByte;
138 commands[++ii] = FAN_Mode;
139
140 commands[0] = ii;
141
142 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
143 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
144
145 ctrl->mode = response[4];
146
147 ii = 0;
148 memset( response, 0, sizeof( response ) );
149 memset( commands, 0, sizeof( commands ) );
150
151 commands[++ii] = CommandId++;
152 commands[++ii] = ReadTwoBytes;
153 commands[++ii] = FAN_FixedRPM;
154 commands[0] = ii;
155 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
156 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
157 ctrl->speed_rpm = ( response[3] << 8 ) + response[2];
158
159 return rr;
160 }
161
162 int
corsairlink_coolit_fan_mode_read_pwm(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)163 corsairlink_coolit_fan_mode_read_pwm(
164 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
165 {
166 int rr;
167 uint8_t response[64];
168 uint8_t commands[64];
169 memset( response, 0, sizeof( response ) );
170 memset( commands, 0, sizeof( commands ) );
171
172 uint8_t ii = 0;
173 commands[++ii] = CommandId++;
174 commands[++ii] = WriteOneByte;
175 commands[++ii] = FAN_Select;
176 commands[++ii] = ctrl->channel;
177
178 commands[++ii] = CommandId++;
179 commands[++ii] = ReadOneByte;
180 commands[++ii] = FAN_Mode;
181
182 commands[0] = ii;
183
184 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
185 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
186
187 ctrl->mode = response[4];
188
189 ii = 0;
190 memset( response, 0, sizeof( response ) );
191 memset( commands, 0, sizeof( commands ) );
192
193 commands[++ii] = CommandId++;
194 commands[++ii] = ReadOneByte;
195 commands[++ii] = FAN_FixedPWM;
196 commands[0] = ii;
197 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
198 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
199 ctrl->speed_pwm = response[2];
200
201 return rr;
202 }
203
204 int
corsairlink_coolit_fan_mode_performance(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)205 corsairlink_coolit_fan_mode_performance(
206 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
207 {
208 int rr;
209 uint8_t response[64];
210 uint8_t commands[64];
211 memset( response, 0, sizeof( response ) );
212 memset( commands, 0, sizeof( commands ) );
213
214 uint8_t ii = 0;
215 commands[++ii] = CommandId++;
216 commands[++ii] = WriteOneByte;
217 commands[++ii] = FAN_Select;
218 commands[++ii] = ctrl->channel;
219
220 commands[++ii] = CommandId++;
221 commands[++ii] = WriteOneByte;
222 commands[++ii] = FAN_Mode;
223
224 commands[++ii] = COOLIT_Performance;
225
226 commands[0] = ii;
227
228 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
229 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
230
231 return rr;
232 }
233
234 int
corsairlink_coolit_fan_mode_balanced(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)235 corsairlink_coolit_fan_mode_balanced(
236 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
237 {
238 int rr;
239 uint8_t response[64];
240 uint8_t commands[64];
241 memset( response, 0, sizeof( response ) );
242 memset( commands, 0, sizeof( commands ) );
243
244 uint8_t ii = 0;
245 commands[++ii] = CommandId++;
246 commands[++ii] = WriteOneByte;
247 commands[++ii] = FAN_Select;
248 commands[++ii] = ctrl->channel;
249
250 commands[++ii] = CommandId++;
251 commands[++ii] = WriteOneByte;
252 commands[++ii] = FAN_Mode;
253
254 commands[++ii] = COOLIT_Balanced;
255
256 commands[0] = ii;
257
258 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
259 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
260
261 return rr;
262 }
263
264 int
corsairlink_coolit_fan_mode_quiet(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)265 corsairlink_coolit_fan_mode_quiet(
266 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
267 {
268 int rr;
269 uint8_t response[64];
270 uint8_t commands[64];
271 memset( response, 0, sizeof( response ) );
272 memset( commands, 0, sizeof( commands ) );
273
274 uint8_t ii = 0;
275 commands[++ii] = CommandId++;
276 commands[++ii] = WriteOneByte;
277 commands[++ii] = FAN_Select;
278 commands[++ii] = ctrl->channel;
279
280 commands[++ii] = CommandId++;
281 commands[++ii] = WriteOneByte;
282 commands[++ii] = FAN_Mode;
283
284 commands[++ii] = COOLIT_Quiet;
285
286 commands[0] = ii;
287
288 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
289 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
290
291 return rr;
292 }
293
294 int
corsairlink_coolit_fan_mode_default(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)295 corsairlink_coolit_fan_mode_default(
296 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
297 {
298 int rr;
299 uint8_t response[64];
300 uint8_t commands[64];
301 memset( response, 0, sizeof( response ) );
302 memset( commands, 0, sizeof( commands ) );
303
304 uint8_t ii = 0;
305 commands[++ii] = CommandId++;
306 commands[++ii] = WriteOneByte;
307 commands[++ii] = FAN_Select;
308 commands[++ii] = ctrl->channel;
309
310 commands[++ii] = CommandId++;
311 commands[++ii] = WriteOneByte;
312 commands[++ii] = FAN_Mode;
313
314 commands[++ii] = COOLIT_Default;
315
316 commands[0] = ii;
317
318 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
319 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
320
321 return rr;
322 }
323
324 int
corsairlink_coolit_fan_mode_rpm(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)325 corsairlink_coolit_fan_mode_rpm(
326 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
327 {
328 int rr;
329 uint8_t response[64];
330 uint8_t commands[64];
331 memset( response, 0, sizeof( response ) );
332 memset( commands, 0, sizeof( commands ) );
333
334 uint8_t ii = 0;
335 commands[++ii] = CommandId++;
336 commands[++ii] = WriteOneByte;
337 commands[++ii] = FAN_Select;
338 commands[++ii] = ctrl->channel;
339
340 commands[++ii] = CommandId++;
341 commands[++ii] = WriteOneByte;
342 commands[++ii] = FAN_Mode;
343
344 commands[++ii] = COOLIT_FixedRPM;
345 commands[++ii] = CommandId++;
346 commands[++ii] = WriteTwoBytes;
347 commands[++ii] = FAN_FixedRPM;
348 commands[++ii] = ctrl->speed_rpm & 0xFF;
349 commands[++ii] = ( ctrl->speed_rpm >> 8 ) & 0xFF;
350
351 commands[0] = ii;
352
353 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
354 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
355
356 return rr;
357 }
358
359 int
corsairlink_coolit_fan_mode_pwm(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)360 corsairlink_coolit_fan_mode_pwm(
361 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
362 {
363 int rr;
364 uint8_t response[64];
365 uint8_t commands[64];
366 memset( response, 0, sizeof( response ) );
367 memset( commands, 0, sizeof( commands ) );
368
369 uint8_t ii = 0;
370 commands[++ii] = CommandId++;
371 commands[++ii] = WriteOneByte;
372 commands[++ii] = FAN_Select;
373 commands[++ii] = ctrl->channel;
374
375 commands[++ii] = CommandId++;
376 commands[++ii] = WriteOneByte;
377 commands[++ii] = FAN_Mode;
378
379 commands[++ii] = COOLIT_FixedPWM;
380 commands[++ii] = CommandId++;
381 commands[++ii] = WriteOneByte;
382 commands[++ii] = FAN_FixedPWM;
383 commands[++ii] = ctrl->speed_pwm & 0xFF;
384
385 commands[0] = ii;
386
387 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
388 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
389
390 return rr;
391 }
392
393 int
corsairlink_coolit_fan_mode_custom(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)394 corsairlink_coolit_fan_mode_custom(
395 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
396 {
397 int rr;
398 uint8_t response[64];
399 uint8_t commands[64];
400 memset( response, 0, sizeof( response ) );
401 memset( commands, 0, sizeof( commands ) );
402
403 uint8_t ii = 0;
404 commands[++ii] = CommandId++;
405 commands[++ii] = WriteOneByte;
406 commands[++ii] = FAN_Select;
407 commands[++ii] = ctrl->channel;
408
409 commands[++ii] = CommandId++;
410 commands[++ii] = WriteOneByte;
411 commands[++ii] = FAN_Mode;
412
413 commands[++ii] = COOLIT_Custom;
414
415 commands[0] = ii;
416
417 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
418 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
419
420 return rr;
421 }
422
423 int
corsairlink_coolit_fan_curve(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)424 corsairlink_coolit_fan_curve(
425 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
426 {
427 int rr;
428 uint8_t response[64];
429 uint8_t commands[64];
430 memset( response, 0, sizeof( response ) );
431 memset( commands, 0, sizeof( commands ) );
432
433 // commands[0] = FanCurve;
434 // commands[1] = UnknownFanCurve;
435
436 uint8_t ii = 0;
437
438 commands[++ii] = CommandId++;
439 commands[++ii] = WriteThreeBytes;
440 commands[++ii] = FAN_TempTable;
441 commands[++ii] = 0x0A;
442
443 commands[++ii] = ctrl->table[0].temperature;
444 commands[++ii] = 0x00;
445 commands[++ii] = ctrl->table[1].temperature;
446 commands[++ii] = 0x00;
447 commands[++ii] = ctrl->table[2].temperature;
448 commands[++ii] = 0x00;
449 commands[++ii] = ctrl->table[3].temperature;
450 commands[++ii] = 0x00;
451 commands[++ii] = ctrl->table[4].temperature;
452 commands[++ii] = 0x00;
453
454 commands[++ii] = CommandId++;
455 commands[++ii] = WriteThreeBytes;
456 commands[++ii] = FAN_RPMTable;
457 commands[++ii] = 0x0A;
458
459 commands[++ii] = ctrl->table[0].speed;
460 commands[++ii] = 0x00;
461 commands[++ii] = ctrl->table[1].speed;
462 commands[++ii] = 0x00;
463 commands[++ii] = ctrl->table[2].speed;
464 commands[++ii] = 0x00;
465 commands[++ii] = ctrl->table[3].speed;
466 commands[++ii] = 0x00;
467 commands[++ii] = ctrl->table[4].speed;
468 commands[++ii] = 0x00;
469
470 commands[0] = ii;
471 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
472 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
473
474 return rr;
475 }
476
477 int
corsairlink_coolit_fan_speed(struct corsair_device_info * dev,struct libusb_device_handle * handle,struct fan_control * ctrl)478 corsairlink_coolit_fan_speed(
479 struct corsair_device_info* dev, struct libusb_device_handle* handle, struct fan_control* ctrl )
480 {
481 int rr;
482 uint8_t response[64];
483 uint8_t commands[64];
484 memset( response, 0, sizeof( response ) );
485 memset( commands, 0, sizeof( commands ) );
486
487 uint8_t ii = 0;
488
489 commands[++ii] = CommandId++;
490 commands[++ii] = WriteOneByte;
491 commands[++ii] = FAN_Select;
492 commands[++ii] = ctrl->channel;
493
494 commands[++ii] = CommandId++;
495 commands[++ii] = ReadTwoBytes;
496 commands[++ii] = FAN_ReadRPM;
497
498 commands[++ii] = CommandId++;
499 commands[++ii] = ReadTwoBytes;
500 commands[++ii] = FAN_MaxRecordedRPM;
501
502 commands[0] = ii;
503
504 rr = dev->driver->write( handle, dev->write_endpoint, commands, 64 );
505 rr = dev->driver->read( handle, dev->read_endpoint, response, 64 );
506
507 msg_debug2( "Speed: %02X %02X\n", response[5], response[4] );
508 msg_debug2( "Max Speed: %02X %02X\n", response[9], response[8] );
509 ctrl->speed_rpm = ( response[5] << 8 ) + response[4];
510 ctrl->max_speed = ( response[9] << 8 ) + response[8];
511
512 return rr;
513 }
514