set fan curve functionality

This commit is contained in:
2026-06-07 17:50:46 +02:00
parent f9272f8d1c
commit f74d9bf539
2 changed files with 51 additions and 1 deletions

View File

@@ -10,6 +10,12 @@
#define AIO_COLOR_WHITE { 255, 255, 255 }
#define AIO_COLOR_OFF { 0, 0, 0 }
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
// roughly converts fan speed to duty
#define SPD2DTY(spd) MAX(0, MIN(spd * 100 / max_fan_speed, 100))
enum aio_pump_mode_t : uint8_t {
QUIET,
BALANCED,
@@ -29,7 +35,12 @@ struct rgb_t {
uint8_t b;
};
struct aio_t{
struct curve_point_t {
uint8_t temp;
uint8_t duty;
};
struct aio_t {
libusb_device_handle* handle;
enum aio_pump_mode_t pump_mode;
float water_temp;

View File

@@ -8,6 +8,9 @@
static const uint16_t usb_timeout = 250;
static const uint8_t buf_size = 32; // needs 32 bc of overflow issue on these aios?
static const uint16_t max_fan_speed = 1200;
static const uint8_t max_curve_points = 7;
// posts cmd to the aio, puts n bytes of response inside resp buffer
#define POST_AND_GET_RESP(cmd, n) uint8_t req = cmd; uint8_t resp[buf_size]; aio_post(dev, &req, 1, resp, n)
@@ -99,6 +102,33 @@ static void aio_set_color(libusb_device_handle* dev, const enum aio_color_mode_t
aio_post(dev, req, 2, resp, buf_size);
}
static void aio_set_fan_curve(libusb_device_handle* dev, const struct curve_point_t *curve, const uint8_t count) {
if (count < 1 || count > max_curve_points) {
applog(LOG_ERR, "aio: curve must have 1-%d points", max_curve_points);
return;
}
struct curve_point_t padded[max_curve_points];
for (int i = 0; i < max_curve_points; i++)
padded[i] = (i < count) ? curve[i] : curve[count - 1];
uint8_t req[16], resp[32];
req[0] = 0x40;
// setup request
for (int i = 0; i < max_curve_points; i++)
req[2 + i] = padded[i].temp;
for (int i = 0; i < max_curve_points; i++)
req[9 + i] = padded[i].duty;
// set curve for both fans
for (int i = 0; i < 2; i++) {
req[1] = i;
aio_post(dev, req, sizeof(req), resp, sizeof(resp));
}
applog(LOG_INF, "set up AIO fan curve");
}
void aio_detect(struct aio_t *aio, const float t_quiet, const float t_balanced) {
libusb_init(NULL);
aio->handle = libusb_open_device_with_vid_pid(NULL, AIO_USB_VID, AIO_USB_PID);
@@ -110,6 +140,13 @@ void aio_detect(struct aio_t *aio, const float t_quiet, const float t_balanced)
aio->t_q = t_quiet;
aio->t_b = t_balanced;
const struct curve_point_t fan_curve[] = {
{ 35, SPD2DTY(480) },
{ 39, SPD2DTY(750) },
{ 45, SPD2DTY(1000) },
{ 48, SPD2DTY(max_fan_speed) }
};
/* detaches other software that might take the device? */
if (libusb_kernel_driver_active(aio->handle, 0))
libusb_detach_kernel_driver(aio->handle, 0);
@@ -117,6 +154,8 @@ void aio_detect(struct aio_t *aio, const float t_quiet, const float t_balanced)
aio_usb_claim(aio->handle);
applog(LOG_INF, "found Corsair AIO device at %04x:%04x, fw ver: %s, B mode at %.1fC, Q mode at %.1fC", AIO_USB_VID, AIO_USB_PID, aio_get_firmware_version(aio->handle, (char[16]){0}), aio->t_b, aio->t_q);
aio_set_pump_mode(aio->handle, QUIET); // needed for init ig?
aio_set_color(aio->handle, AIO_COLOR_FIXED, 0, NULL, 0); // so it doenst complain the func is unused
aio_set_fan_curve(aio->handle, fan_curve, sizeof(fan_curve) / sizeof(fan_curve[0]));
aio_usb_release(aio->handle);
}