Hi All,
I modified the hidtest utility within the hidapi package (http://www.signal11.us/oss/hidapi/) to read and write the fan mode and RPM registers within the Corsair H80i (& H100i) coolers under Ubuntu 12.04.
/*******************************************************
Windows HID simplification
Alan Ott
Signal 11 Software
8/22/2009
Copyright 2009, All Rights Reserved.
This contents of this file may be used by anyone
for any reason without any conditions and may be
used as a starting point for your own applications
which use HIDAPI.
********************************************************/
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
#include "hidapi.h"
// Headers needed for sleeping.
#ifdef _WIN32
#include <windows.h>
#else
#include <unistd.h>
#endif
int hid_read_wrapper (hid_device *handle, unsigned char *buf)
{
// Read requested state. hid_read() has been set to be
// non-blocking by the call to hid_set_nonblocking() above.
// This loop demonstrates the non-blocking nature of hid_read().
int res = 0;
while (res == 0) {
res = hid_read(handle, buf, sizeof(buf));
if (res == 0)
// printf("waiting...\n");
if (res < 0)
printf("Unable to read()\n");
#ifdef WIN32
Sleep(500);
#else
usleep(500*1000);
#endif
}
//printf("Data read:\n ");
//// Print out the returned buffer.
//for (int i = 0; i < res; i++)
// printf("%02hhx ", buf);
//printf("\n");
//return res;
}
int main(int argc, char* argv[])
{
int res;
unsigned int commandId = 0x81;
unsigned char buf[256];
#define MAX_STR 255
wchar_t wstr[MAX_STR];
hid_device *handle;
int i;
#ifdef WIN32
UNREFERENCED_PARAMETER(argc);
UNREFERENCED_PARAMETER(argv);
#endif
struct hid_device_info *devs, *cur_dev;
if (hid_init())
return -1;
devs = hid_enumerate(0x0, 0x0);
cur_dev = devs;
while (cur_dev) {
printf("Device Found\n type: %04hx %04hx\n path: %s\n serial_number: %ls", cur_dev->vendor_id, cur_dev->product_id, cur_dev->path, cur_dev->serial_number);
printf("\n");
printf(" Manufacturer: %ls\n", cur_dev->manufacturer_string);
printf(" Product: %ls\n", cur_dev->product_string);
printf(" Release: %hx\n", cur_dev->release_number);
printf(" Interface: %d\n", cur_dev->interface_number);
printf("\n");
cur_dev = cur_dev->next;
}
hid_free_enumeration(devs);
// Set up the command buffer.
memset(buf,0x00,sizeof(buf));
buf[0] = 0x01;
buf[1] = 0x81;
// Open the device using the VID, PID,
// and optionally the Serial number.
// open Corsair H80i or H100i cooler
handle = hid_open(0x1b1c, 0x0c04, NULL);
if (!handle) {
printf("Error: Unable to open Corsair H80i or H100i CPU Cooler\n");
return 1;
}
// Read the Manufacturer String
wstr[0] = 0x0000;
res = hid_get_manufacturer_string(handle, wstr, MAX_STR);
if (res < 0)
printf("Unable to read manufacturer string\n");
printf("Manufacturer String: %ls\n", wstr);
// Read the Product String
wstr[0] = 0x0000;
res = hid_get_product_string(handle, wstr, MAX_STR);
if (res < 0)
printf("Unable to read product string\n");
printf("Product String: %ls\n", wstr);
// Set the hid_read() function to be non-blocking.
hid_set_nonblocking(handle, 1);
memset(buf,0,sizeof(buf));
// Read Device ID: 0x3b = H80i. 0x3c = H100i
buf[0] = 0x03; // Length
buf[1] = commandId++; // Command ID
buf[2] = 0x07; // Command Opcode
buf[3] = 0x00; // Command data...
buf[4] = 0x00;
res = hid_write(handle, buf, 17);
if (res < 0) {
printf("Error: Unable to write() %ls\n", hid_error(handle));
}
hid_read_wrapper(handle, buf);
if (res < 0) {
printf("Error: Unable to read() %ls\n", hid_error(handle));
}
printf("Device ID: %02hhx\n", buf[2]);
int deviceId = buf[2];
if ((deviceId != 0x3b) && (deviceId != 0x3c)) {
printf("Device ID: %02hhx mismatch. Not Corsair H80i or H100i CPU Cooler\n", buf[2]);
hid_close(handle);
hid_exit();
}
memset(buf,0x00,sizeof(buf));
// Read number-of-fans
buf[0] = 0x03; // Length
buf[1] = commandId++; // Command ID
buf[2] = 0x07; // Command Opcode
buf[3] = 0x11; // Command data...
buf[4] = 0x00;
res = hid_write(handle, buf, 5);
if (res < 0) {
printf("Error: Unable to write() %ls\n", hid_error(handle));
}
hid_read_wrapper(handle, buf);
if (res < 0) {
printf("Error: Unable to read() %ls\n", hid_error(handle));
}
printf("number-of-fans: %02hhx\n", buf[2]);
memset(buf,0x00,sizeof(buf));
// Read number-of-LEDs
buf[0] = 0x03; // Length
buf[1] = commandId++; // Command ID
buf[2] = 0x07; // Command Opcode
buf[3] = 0x05; // Command data...
buf[4] = 0x00;
res = hid_write(handle, buf, 5);
if (res < 0) {
printf("Error: Unable to write() %ls\n", hid_error(handle));
}
hid_read_wrapper(handle, buf);
if (res < 0) {
printf("Error: Unable to read() %ls\n", hid_error(handle));
}
printf("number-of-LEDs: %02hhx\n", buf[2]);
int fanMode = 0;
for (int i = 0; i < 5; i++) {
#ifdef WIN32
Sleep(500);
#else
usleep(500*1000);
#endif
memset(buf,0x00,sizeof(buf));
// Read fan Mode
buf[0] = 0x07; // Length
buf[1] = commandId++; // Command ID
buf[2] = 0x06; // Command Opcode
buf[3] = 0x10; // Command data...
buf[4] = i; // select fan
buf[5] = commandId++; // Command ID
buf[6] = 0x07; // Command Opcode
buf[7] = 0x12; // Command data...
res = hid_write(handle, buf, 11);
if (res < 0) {
printf("Error: Unable to write() %ls\n", hid_error(handle));
}
//printf("read fan Mode ");
res = hid_read_wrapper(handle, buf);
if (res < 0) {
printf("Error: Unable to read() %ls\n", hid_error(handle));
}
fanMode = buf[4];
memset(buf,0x00,sizeof(buf));
// Read fan RPM
buf[0] = 0x07; // Length
buf[1] = commandId++; // Command ID
buf[2] = 0x06; // Command Opcode
buf[3] = 0x10; // Command data...
buf[4] = i; // select fan
buf[5] = commandId++; // Command ID
buf[6] = 0x09; // Command Opcode
buf[7] = 0x16; // Command data...
res = hid_write(handle, buf, 11);
if (res < 0) {
printf("Error: Unable to write() %ls\n", hid_error(handle));
}
//printf("read fan RPM ");
res = hid_read_wrapper(handle, buf);
printf("Fan %d mode %02hhx RPM: %02hhx %02hhx\n", i, fanMode, buf[4], buf[5]);
if (i < 5) {
#ifdef WIN32
Sleep(500);
#else
usleep(500*1000);
#endif
memset(buf,0x00,sizeof(buf));
// setting fan mode to Default (0x06) or Performance (0x0c)
fanMode = 0x0c;
buf[0] = 0x0b; // Length
buf[1] = commandId++; // Command ID
buf[2] = 0x06; // Command Opcode
buf[3] = 0x10; // Command data...
buf[4] = i; // select fan
buf[5] = commandId++; // Command ID
buf[6] = 0x06; // Command Opcode
buf[7] = 0x12; // Command data...
buf[8] = fanMode;
buf[9] = commandId++; // Command ID
buf[10] = 0x07; // Command Opcode
buf[11] = 0x12; // Command data...
res = hid_write(handle, buf, 17);
if (res < 0) {
printf("Error: Unable to write() %ls\n", hid_error(handle));
}
//printf("read fan mode to confirm ");
res = hid_read_wrapper(handle, buf);
if (res < 0) {
printf("Error: Unable to read() %ls\n", hid_error(handle));
}
printf("Fan %d mode is %02hhx should be: %02hhx\n", i, buf[6], fanMode);
}
}
hid_close(handle);
/* Free static HIDAPI objects. */
hid_exit();
#ifdef WIN32
system("pause");
#endif
return 0;
}