The Corsair User Forums  

Go Back   The Corsair User Forums > Corsair Product Discussion > Corsair Link

Reply
 
Thread Tools Search this Thread Rating: Thread Rating: 252 votes, 5.00 average. Display Modes
  #31  
Old 09-09-2013, 02:43 PM
RAM GUY's Avatar
RAM GUY RAM GUY is offline
Corsair Product Guru
 
Join Date: Apr 2001
Location: Fremont, CA
Posts: 118,268
POST ID # = 673706
RAM GUY Reputation: 10
Default

zen1,
Its no problem; for some it has not worked as well as it has for most. But we do understand your frustration and I do apologize. Thank you for taking the time to Voice your opinion.
__________________
Support accounts and tickets can be created at https://support.corsair.com.
Reply With Quote


  #32  
Old 09-09-2013, 11:37 PM
Thatualle1970's Avatar
Thatualle1970 Thatualle1970 is offline
Registered User
Thatualle1970's PC Specs
 
Join Date: Sep 2013
Location: Dorchester, ON
Posts: 17
POST ID # = 673781
Thatualle1970 Reputation: 13
Default

Quote:
Originally Posted by CFSworks View Post
Hey all!
Hey CFSworks; great job so far....
Some additional information to keep this thread moving in the positive direction.

Corsair Link protocol overview

As mentioned, the USB device uses a simple 64-byte HID "raw" report; the rawhid source code can be a useful starting point to establish low-level communication if a device isn't "just available" (e.g., on Windows).

http://www.pjrc.com/teensy/rawhid.html

The ReportID is always zero and is length-prefixed with a number of SMBus-like packets within the HID packet. Each packet has an index (which should be from 20~255), SMBus sub-packet type followed by any write data, if the sub-packet is writing data. Block types also have a length, and it appears the "quick" and "byte" modes are unsupported (only CmdByte, CmdWord and CmdBlock appear to be used).

H80i/H100i Register set:

__Number__R/W__Length__ Description
00 R 1 byte Device ID - (H80 0x37, Cooling node 0x38, Lighting node 0x39, H100 0x3A, 80i 0x3B, 100i 0x3c -- this field as well as the version are common on all C-Link devices; but the rest aren't
01 R 2 bytes Firmware Version in BCD (for example 1.0.5 is 0x1005, or 0x05, 0x10 in little endianess)
02 R 8 bytes Product name, zero-terminated - only present on the H80i and H100i
03 R 1 Status, 0 okay, 0xFF bad
04 RW 1 byte Select current LED
05 R 1 byte Number of LEDs
06 RW 1 byte LED mode - 0x00 for static color, 0x40 for 2-color cycle, 0x80 for 4-color, 0xC0 for temperature mode; low nibble defines cycle speed or the temperature channel to use (0 internal sensor, 7 manual)
07 R 3 bytes LED current color, RGB color of the selected LED
08 RW 2 bytes In temperature controlled mode (0xC0) this defines the colour to use to with the below gradients
09 RW 6 bytes LED temperature-mode temperatures: 3 temperatures; used when cycle mode is 0xc0
0a RW 9 bytes LED temperature-mode colors: RGBx3 colors, corresponding to temperatures in register above
0b RW 12 bytes LED cycle colors: RGBx4 colors (only first color used if cycle mode set to 00, first two if 4b, ignored if c0)
0c RW 1 byte Select active temperature sensor
0d R 1 byte Number of temperature sensors
0e R 2 bytes Temperature as measured by selected sensor
0f RW 2 bytes Temperature limit (when the temperature goes over this, status is set to 0xff)
10 RW 1 byte Select current fan; for H100i, 0-3 are the fans, 4 is pump
11 R 1 byte Number of fans
12 RW 1 byte Fan mode; 02=fixed PWM, 04=fixed RPM, 06=default, 08=quiet, 0a=balanced, 0c=performance, 0e=custom; high bit is one when fan is detected, low bit is one when the fan is 4-pin, bits 6~4 define the temperautre channel to use in "curve" modes, 0 internal and 7 manual
13 RW 1 byte Fan fixed PWM, 0-255, only used if fan mode is 02
14 RW 2 bytes Fan fixed RPM; when fan mode is 04, controller will target this RPM
15 RW 2 bytes Report external temperature to fan controller - used for controlling fans via external sensors
16 R 2 bytes Current fan RPM
17 R 2 bytes Maximum RPM recorded since power-on
18 RW 2 bytes Fan under speed threshold
19 RW 10 bytes Fan RPM table, for custom (0e) mode: array of 5 RPMs
1a RW 10 bytes Fan temp table, for custom (0e) mode: array of 5 temperatures

Note: All data is little-endian.
Temperatures are reported in units of 1/256th of a degree Celsius.
Reply With Quote


1 members found this post helpful.
  #33  
Old 09-25-2013, 04:03 PM
Thatualle1970's Avatar
Thatualle1970 Thatualle1970 is offline
Registered User
Thatualle1970's PC Specs
 
Join Date: Sep 2013
Location: Dorchester, ON
Posts: 17
POST ID # = 675996
Thatualle1970 Reputation: 13
Default The other devices...

For the people who are still interested...

H80/H100/Cooling Node Register set:
RegisterHexLengthReadDescription
Device ID002ROH80 0x37; Cooling node 0x38; H100 0x3A
Firmware Version012RO#.#.## that is 0x1011 is version 1.0.17
System Status022ROStatus 0 okay 0xFF bad
Status Led042 Each bit = led; 0 = Extreme, 1 = Perf, 2 = Quiet, 3 = CLink Dude
Temps078RWCurrent temp for four channels (signed fixed point)
RPM Current0B10ROCurrent fan speed
RPM Max1010ROMeasured fan maximum
Input Temp1A10RWTemperature when in one of the curve modes
Fan Control20 30 40 50 602RWBit 7 Fan detected; Bit 6~4 Temp Input; Bit 3~1 Fan Mode; Bit 0 Fan Pins (1 is 4-Pin)
 (each channel)  Temp Input: 0 Coolant Temp 1 Temp 0 2 Temp 1 3 Temp 2 4 MCU Temp 7 ManualFan
    Mode: 0 Off 1 PWM 2 RPM 3 Set Point 4 Quiet 5 Performance 6 Extreme 7 User Curve
Fan Target PWM21 31 41 51 612RWCurrent fan speed as a percentage * 2.55 (e.g. 255 == 100%)
Fan Target RPM22 32 42 52 622RWCurrent RPM target
Fan User Curve RPM23 33 43 53 6310RWUser curve profile
Fan User Curve Temp28 38 48 58 6810RWUser curve profile

Note: Fields which only expect a single byte (e.g., PWM) must be zero-padded.

LED Node Register set:
RegisterHexLength*ReadDescription
Device ID001RO0x3A for LED Node
Firmware Version012ROBCD 0x0910 is version 1.0.9
SystemStatus031ROGood is 0; bad is 0xFF
User Mode042x1RW0x10 Pulse Mode; 0x01 through 0x0F Built-In Colours; 0x00 C-Link Mode
RGB Out062x3ROCurrent calculated LED output
Temps0C2x2RWInput temperatures
Cycle Mode10 301RWBit 6~7: 00 - Static; 01 - Two Cycle; 10 - Four Cycle; 11 - Temperature
    Bit 0~2 Cycle Speed in powers of 2 x 1/8th Second
Cold Warm Hot11 313x5RWTemp (two bytes) and RGB (three bytes) for each threshold
Cycle Colours20 404x4RWRGB (with one byte padding) for each cycle step

Note: Lengths may be shown as number of sets x length of each set. For example, there are three sets (one for cold, warm and hot respectively) with five bytes of data for temperature settings. The hex address will be offset byt the BYTE position being written.

LED Nodes, Cooling Nodes and the original H80 and H100 all have seuqential registers, meaning that writing more data than the first register will hold will "spill over" into the next register, allowing large block reads and writes.
Reply With Quote


  #34  
Old 09-25-2013, 04:03 PM
Thatualle1970's Avatar
Thatualle1970 Thatualle1970 is offline
Registered User
Thatualle1970's PC Specs
 
Join Date: Sep 2013
Location: Dorchester, ON
Posts: 17
POST ID # = 675996
Thatualle1970 Reputation: 13
Default The other devices...

For the people who are still interested...

H80/H100/Cooling Node Register set:
RegisterHexLengthReadDescription
Device ID002ROH80 0x37; Cooling node 0x38; H100 0x3A
Firmware Version012RO#.#.## that is 0x1011 is version 1.0.17
System Status022ROStatus 0 okay 0xFF bad
Status Led042 Each bit = led; 0 = Extreme, 1 = Perf, 2 = Quiet, 3 = CLink Dude
Temps078RWCurrent temp for four channels (signed fixed point)
RPM Current0B10ROCurrent fan speed
RPM Max1010ROMeasured fan maximum
Input Temp1A10RWTemperature when in one of the curve modes
Fan Control20 30 40 50 602RWBit 7 Fan detected; Bit 6~4 Temp Input; Bit 3~1 Fan Mode; Bit 0 Fan Pins (1 is 4-Pin)
 (each channel)  Temp Input: 0 Coolant Temp 1 Temp 0 2 Temp 1 3 Temp 2 4 MCU Temp 7 ManualFan
    Mode: 0 Off 1 PWM 2 RPM 3 Set Point 4 Quiet 5 Performance 6 Extreme 7 User Curve
Fan Target PWM21 31 41 51 612RWCurrent fan speed as a percentage * 2.55 (e.g. 255 == 100%)
Fan Target RPM22 32 42 52 622RWCurrent RPM target
Fan User Curve RPM23 33 43 53 6310RWUser curve profile
Fan User Curve Temp28 38 48 58 6810RWUser curve profile

Note: Fields which only expect a single byte (e.g., PWM) must be zero-padded.

LED Node Register set:
RegisterHexLength*ReadDescription
Device ID001RO0x3A for LED Node
Firmware Version012ROBCD 0x0910 is version 1.0.9
SystemStatus031ROGood is 0; bad is 0xFF
User Mode042x1RW0x10 Pulse Mode; 0x01 through 0x0F Built-In Colours; 0x00 C-Link Mode
RGB Out062x3ROCurrent calculated LED output
Temps0C2x2RWInput temperatures
Cycle Mode10 301RWBit 6~7: 00 - Static; 01 - Two Cycle; 10 - Four Cycle; 11 - Temperature
    Bit 0~2 Cycle Speed in powers of 2 x 1/8th Second
Cold Warm Hot11 313x5RWTemp (two bytes) and RGB (three bytes) for each threshold
Cycle Colours20 404x4RWRGB (with one byte padding) for each cycle step

Note: Lengths may be shown as number of sets x length of each set. For example, there are three sets (one for cold, warm and hot respectively) with five bytes of data for temperature settings. The hex address will be offset byt the BYTE position being written.

LED Nodes, Cooling Nodes and the original H80 and H100 all have seuqential registers, meaning that writing more data than the first register will hold will "spill over" into the next register, allowing large block reads and writes.
Reply With Quote


1 members found this post helpful.
  #35  
Old 10-02-2013, 07:06 PM
bobpombrio bobpombrio is offline
Registered User
bobpombrio's PC Specs
 
Join Date: Oct 2013
Posts: 5
POST ID # = 676948
bobpombrio Reputation: 10
Default Some more info please about the USB ID

Can some one tell me the USB vendor ID and the USB product ID for the H100i? Like you I am not happy with the Link software and I'd like to write my own. I see all of this great work has been done that explains the protocol and I'd like to take advantage of it.
Reply With Quote


  #36  
Old 10-04-2013, 10:49 AM
Thatualle1970's Avatar
Thatualle1970 Thatualle1970 is offline
Registered User
Thatualle1970's PC Specs
 
Join Date: Sep 2013
Location: Dorchester, ON
Posts: 17
POST ID # = 677168
Thatualle1970 Reputation: 13
Default

Quote:
Originally Posted by bobpombrio View Post
Can some one tell me the USB vendor ID and the USB product ID for the H100i? Like you I am not happy with the Link software and I'd like to write my own. I see all of this great work has been done that explains the protocol and I'd like to take advantage of it.
PID is always 0x1B1C
VID is 0x0C04 for H80i and H100i
VID is 0x0C02 for the USB Commander

They use the same basic protocol, except the Commander's don't have the extra length byte at the very beginning. Here's what I have working so far (C# code, this depends on HidLibrary which you can get from NuGet):

Code:
public List<Int32> ListPorts() {
    int packetIndex = 1; // skip the report id field (always zero)
    byte[] packet = new byte[65]; // size of the packet plus report id
    if (newProtocol) packet[packetIndex++] = 2; // newProtocol = (pid == 0xC04)
    packet[packetIndex++] = (byte)index; // write the index
    if (index < 255) index++; else index = 20; // and cycle it
    packet[packetIndex++] = 0x4F; // command to get the port status

    // perform the io
    device.Write(packet, 500);
    var inpacket = device.Read(500);

    // and collect our list of active channels
    List<Int32> ports = new List<Int32>();
    for (int portIndex = 0; portIndex < 8; portIndex++) {
        // any port set to 0xFF is not present, anything else is 'live'
        if (inpacket.Data[3 + portIndex] != 0xFF)
            ports.Add(portIndex);
    }

    return ports;
}
Code:
// reportid, length, index, command, register, len
// 0         1       2      3        4         5   <- block
// 0         1       2      3        4             <- byte/word
//           ^-- omitted with old USB Commander (0xC02)

// reportid, index, command/status, data...
// 0         1      2               3
//           ^-- omitted with USB Commander
public byte[] ReadData(int reg, int len = 1) {
    int i = (newProtocol) ? 2 : 1; // fill in the length when we're done
    byte[] packet = new byte[65]; // our standard packet length
    int command = (Port << 4) | 1; // port fills the high nibble, 1 is 'read'

    if (len == 1) command |= 6; // read byte
    else if (len == 2) command |= 8; // read short
    else command |= 10; // read any length

    packet[i++] = (byte)index; // obligatory index field
    if (index < 255) index++; else index = 20; // and cycle
    packet[i++] = (byte)command; // command byte
    packet[i++] = (byte)reg; // the register we'd like to read
    if (len > 2) packet[i++] = (byte)len; // arbitrary length require the length

    if (newProtocol) packet[1] = (byte)(index - 1); // add in our total length

    // do the io
    device.Write(packet, 500);
    var inpacket = device.Read(500);

    if (inpacket != null && inpacket.Status == HidDeviceData.ReadStatus.Success) {
        // ignore bad packets (handle the null from the caller side)
        if (inpacket.Data[1] != packet[(newProtocol) ? 2 : 1]) return null;
        if ((inpacket.Data[2] & 240) != 0) return null;

        // grab our returned data from within the packet
        byte[] data = new byte[len];
        Buffer.BlockCopy(inpacket.Data, 3, data, 0, len);
        return data;
    }
    else return null;
}
Code:
// reportid, length, index, command, register, len, data...
// 0         1       2      3        4         5,   6... <- block
// 0         1       2      3        4              5... <- byte/word
//           ^-- omitted with USB Commander (0xC02)
public bool WriteData(int reg, byte[] data) {
    int i = (newProtocol) ? 2 : 1; // fill in the length when we're done
    byte[] packet = new byte[65]; // our standard packet length
    int command = (Port << 4); // port fills the high nibble, no low bit for write

    if (data.Length == 1) command |= 6; // byte
    else if (data.Length == 2) command |= 8; // short
    else command |= 10; // arbitrary length

    packet[i++] = (byte)index; // index and cycle
    if (index < 255) index++; else index = 20;
    packet[i++] = (byte)command; // command field
    packet[i++] = (byte)reg; // register we're writing too
    if (data.Length > 2) packet[i++] = (byte)(data.Length); // length, if req'd
    Buffer.BlockCopy(data, 0, packet, i, data.Length); // data we're writing
    i += data.Length; // position in the packet

    if (newProtocol) packet[1] = (byte)(index - 1); // prefix packet length

    device.Write(packet, 500); // do the io
    var inpacket = device.Read(500);

    // return true if the write was successful
    return (inpacket != null && inpacket.Status == HidDeviceData.ReadStatus.Success);
}
From here you need to just enumerate everything and push that info up to some sort of UI. It's important that you not try to talk to the same device using multiple threads, that breaks things, so either stick to single threading, single threading per USB device, or use locks to ensure that the write-read sequence is always unbroken.

Apologies for the messy code.

The code is very "C" like and should be easy enough to port to Linux (unless mono can be made to work), but that's beyond my realm of expertise...
Reply With Quote


1 members found this post helpful.
  #37  
Old 10-04-2013, 11:44 AM
bobpombrio bobpombrio is offline
Registered User
bobpombrio's PC Specs
 
Join Date: Oct 2013
Posts: 5
POST ID # = 677174
bobpombrio Reputation: 10
Happy Sweet

This is extremely sweet. I'm doing a Windows implementation as well. In (wait for it) (waaiiiittttt) C# as well.

Thanks!!
Reply With Quote


  #38  
Old 10-04-2013, 01:36 PM
Thatualle1970's Avatar
Thatualle1970 Thatualle1970 is offline
Registered User
Thatualle1970's PC Specs
 
Join Date: Sep 2013
Location: Dorchester, ON
Posts: 17
POST ID # = 677186
Thatualle1970 Reputation: 13
Default

Quote:
Originally Posted by bobpombrio View Post
This is extremely sweet. I'm doing a Windows implementation as well. In (wait for it) (waaiiiittttt) C# as well.

Thanks!!
You're welcome, and good luck!

Regrading C#, if it had direct-to-x86 compilation it would be the perfect language to write in, but having to pass through the CLR all the time makes it imperfect for low latency communication. Ultimately, you'd be better off writing a C/C++ layer that handles the basic communication loop and pass that up to higher code.

For example, in C# in Windows using HidLibrary, I get around 12ms per packet, whereas rewriting the low level code in ANSI C using direct Win32 calls and plugging it into LUA, I was able to easily hit 1ms per packet (the limit Windows/USB2.0 will allow).
Reply With Quote


  #39  
Old 10-04-2013, 08:25 PM
bobpombrio bobpombrio is offline
Registered User
bobpombrio's PC Specs
 
Join Date: Oct 2013
Posts: 5
POST ID # = 677240
bobpombrio Reputation: 10
Default

Your correct. I've done a fair amount of low level C and assembly over the years but I'm starting to play with C sharp. I haven't done much of anything yet with is thing, motivation seems to be a factor and getting a response from the 100i yet seems to be another. I recently did a large project for the army in c# on a hand-held unit that dealt with a couple low level devices so I should be able to figure this out. Unless you want some collaboration on yours.... :)
Reply With Quote


  #40  
Old 11-10-2013, 10:30 PM
dwmccauley dwmccauley is offline
Registered User
 
Join Date: Nov 2013
Posts: 1
POST ID # = 682198
dwmccauley Reputation: 10
Default hidapi.hidtest

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 ");
I'M A SPAMMER. PLEASE REPORT ME. Print out the returned buffer.
//for (int i = 0; i < res; i++)
// printf("%02hhx ", buf[i]);
//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;
}
Reply With Quote


  #41  
Old 11-14-2013, 06:33 PM
GrahamB's Avatar
GrahamB GrahamB is offline
Registered User
GrahamB's PC Specs
 
Join Date: Aug 2013
Location: Leighton Buzzard, England
Posts: 98
POST ID # = 682725
GrahamB Reputation: 10
Default

There is a great difference between the description of a protocol, and software to implement it.
From my POV Corsair should publish the protocol details, let people write their own code based on this, and maybe other hardware vendors will support it. Would do us all good including Corsair.
__________________
I have nothing to do with Corsair, apart from buying my Case, Memory, Cooler, PSU and Link from them.
Reply With Quote


  #42  
Old 11-30-2013, 12:29 AM
Thatualle1970's Avatar
Thatualle1970 Thatualle1970 is offline
Registered User
Thatualle1970's PC Specs
 
Join Date: Sep 2013
Location: Dorchester, ON
Posts: 17
POST ID # = 685117
Thatualle1970 Reputation: 13
Default

Quote:
Originally Posted by GrahamB View Post
There is a great difference between the description of a protocol, and software to implement it.
From my POV Corsair should publish the protocol details, let people write their own code based on this, and maybe other hardware vendors will support it. Would do us all good including Corsair.
What part of the protocols are we missing? Confirmation from Corsair that we're right? They've already said they won't do that.
Reply With Quote


  #43  
Old 11-30-2013, 12:44 AM
GrahamB's Avatar
GrahamB GrahamB is offline
Registered User
GrahamB's PC Specs
 
Join Date: Aug 2013
Location: Leighton Buzzard, England
Posts: 98
POST ID # = 685121
GrahamB Reputation: 10
Default

Yes, but there is a difference between a published protocol and a reverse engineered one. If published I would expect for example changes and additions to be published as well. But it seems that won't happen. Pity. They have a chance to create a protocol and communications for lighting, cooling etc. And if anyone connects non Corsair LEDs to their lighting node, so what. Corsair has decided not to sell them.
__________________
I have nothing to do with Corsair, apart from buying my Case, Memory, Cooler, PSU and Link from them.
Reply With Quote


  #44  
Old 12-01-2013, 09:01 AM
Ubeogesh Ubeogesh is offline
Registered User
Ubeogesh's PC Specs
 
Join Date: Aug 2013
Location: Belarus, Minsk
Posts: 19
POST ID # = 685277
Ubeogesh Reputation: 10
Send a message via Skype™ to Ubeogesh
Default

Wow guys, what you do here is awesome.

I'm tired of the buggy and ugly Corsair Link. Every time I want to change my H100i settings or monitor power usage on my AX760i, I have to detach and reattach the USB connector. Moreover, the product is ugly as hell (why all hardware manufacturers make super ugly GUI in their software? Perhaps, the only exception is AMD, but recent Catalyst's got more ugly; I'd rather have no GUI at all and control everything through CLI and\or configuration files then seeing THIS)

If I understand correctly, the CFSworks wants to make some Linux software for Corsair Link, but you guys Thatualle1970 and bobpombrio are doing something for Windows, right?

Unfortunately I have no idea in developing drivers and only a very (very) little knowledge of c++ and WinAPI so can't help developing.

If there is something else I can help otherwise (i.e. test something?), please PM me. I live in GMT +0300 and available (and hopefully will respond quickly) every weekend
I've got AX760i and H100i devices (AX760i connected to H100i, and H100i goes to the USB; I can also connect AX760i to its USB dongle; if something working will come from this thread, I'll be eager to buy the Link device also...). I am also a very experienced Windows software user and know a lot of stuff about it.
Reply With Quote


  #45  
Old 02-05-2014, 05:09 PM
volmok volmok is offline
Registered User
volmok's PC Specs
 
Join Date: Feb 2014
Posts: 1
POST ID # = 695978
volmok Reputation: 10
Default

Hi,

I have switched one year ago to Linux and I found that it lacks the control over my cooler (H100i).
Thanks dwmccauley's example I have created a working basic tool that allows the following:
  • View fan and pump information
  • Change fan mode
  • Set fan RPM (if fixed RPM mode is selected)

The code is attached in the file and you can use the makefile in the Debug folder.

I apologize in advance if I break any "Linux developing rules", but I am a .NET developer (yes I use Linux and develop on MS products) and I just got into C++.

V.

P.S. Let me know if you find bugs or issues with my code.
Attached Files
File Type: zip OpenCorsairLink.zip (11.6 KB, 547 views)
Reply With Quote


  #46  
Old 03-19-2014, 02:03 PM
Thatualle1970's Avatar
Thatualle1970 Thatualle1970 is offline
Registered User
Thatualle1970's PC Specs
 
Join Date: Sep 2013
Location: Dorchester, ON
Posts: 17
POST ID # = 702176
Thatualle1970 Reputation: 13
Default

Meh, to heck with it, I'll leave this up here as is. If anyone's interested in this:

You can download the source code from here and compile it with Visual C# Express:
OpenHardwareMonitor.7z

Last edited by Thatualle1970; 03-19-2014 at 02:05 PM. Reason: Missed one csproj file in the 7zip file, sorry.
Reply With Quote


2 members found this post helpful.
Reply

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 06:28 PM.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2019, vBulletin Solutions, Inc.