diff --git a/src/aio.c b/src/aio.c index fcb1c8f..2db9d0c 100644 --- a/src/aio.c +++ b/src/aio.c @@ -1,44 +1,70 @@ #include "aio.h" #include "log.h" +#include #include +static const uint16_t usb_timeout = 1000; static const uint8_t buf_size = 32; // needs 32 bc of overflow issue on these aios? // 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[32]; aio_post(aio, &req, 1, resp, n) +#define POST_AND_GET_RESP(cmd, n) uint8_t req = cmd; uint8_t resp[buf_size]; aio_post(dev, &req, 1, resp, n) -static void aio_post(libusb_device_handle *dev, uint8_t *req, const int req_len, uint8_t *resp, const int resp_len) { - libusb_bulk_transfer(dev, 0x01, req, req_len, NULL, 1000); - libusb_bulk_transfer(dev, 0x81, resp, resp_len, NULL, 1000); +// posts 2 bytes of cmd to aio, puts n bytes of response inside resp buffer +#define POST_AND_GET_RESP2(cmd1, cmd2, n) uint8_t req[2] = {cmd1, cmd2}; uint8_t resp[buf_size]; aio_post(dev, req, 2, resp, n) + +static void aio_usb_claim(libusb_device_handle* dev) { + int ret = libusb_claim_interface(dev, 0); + if (ret != 0) { + applog(LOG_ERR, "failed to claim AIO device: %s", libusb_error_name(ret)); + return; + } + ret = libusb_control_transfer(dev,(LIBUSB_ENDPOINT_OUT | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE),0x02,0x02,0, NULL, 0, usb_timeout); + if (ret < 0) + applog(LOG_ERR, "AIO clear-to-send failed: %s", libusb_error_name(ret)); } -static float aio_get_water_temp(libusb_device_handle* aio) { +static void aio_usb_release(libusb_device_handle* dev) { + libusb_release_interface(dev, 0); +} + +static void aio_post(libusb_device_handle *dev, uint8_t *req, const int req_len, uint8_t *resp, const int resp_len) { + libusb_bulk_transfer(dev, 0x01, req, req_len, NULL, usb_timeout); + libusb_bulk_transfer(dev, 0x81, resp, resp_len, NULL, usb_timeout); +} + +static float aio_get_water_temp(libusb_device_handle* dev) { POST_AND_GET_RESP(0xa9, 6); return (float)resp[3] + (float)resp[4] / 10.0f; } -static uint16_t aio_get_pump_speed(libusb_device_handle* aio) { +static uint16_t aio_get_pump_speed(libusb_device_handle* dev) { POST_AND_GET_RESP(0x31, 5); return resp[3] << 8 | resp[4]; } -static enum aio_pump_mode_t aio_get_pump_mode(libusb_device_handle* aio) { +static enum aio_pump_mode_t aio_get_pump_mode(libusb_device_handle* dev) { POST_AND_GET_RESP(0x33, 4); return (enum aio_pump_mode_t)resp[3]; } -static void aio_get_fan_speed(libusb_device_handle* aio, uint16_t *speeds) { - uint8_t req[2] = {0x41}; // 2nd element is the fan id. - uint8_t resp[buf_size]; - +static void aio_get_fan_speed(libusb_device_handle* dev, uint16_t *speeds) { for (uint8_t i = 0; i < 2; i++) { - req[1] = i; - aio_post(aio, req, sizeof(req), resp, 6); + POST_AND_GET_RESP2(0x41, i, 6); speeds[i] = resp[4] << 8 | resp[5]; } } +static char* aio_get_firmware_version(libusb_device_handle* dev, char* buf) { + POST_AND_GET_RESP(0xaa, buf_size); + sprintf(buf, "%d.%d.%d.%d", resp[3], resp[4], resp[5], resp[6]); + return buf; +} + +static void aio_set_pump_mode(libusb_device_handle* dev, const enum aio_pump_mode_t mode) { + POST_AND_GET_RESP2(0x32, mode, 6); +} + void aio_detect(struct aio_t *aio) { libusb_init(NULL); aio->handle = libusb_open_device_with_vid_pid(NULL, AIO_USB_VID, AIO_USB_PID); @@ -51,25 +77,34 @@ void aio_detect(struct aio_t *aio) { if (libusb_kernel_driver_active(aio->handle, 0)) libusb_detach_kernel_driver(aio->handle, 0); - const int ret = libusb_claim_interface(aio->handle, 0); - if (ret == 0) - applog(LOG_INF, "found Corsair AIO device at %04x:%04x", AIO_USB_VID, AIO_USB_PID); - else - applog(LOG_ERR, "failed to claim AIO device"); + aio_usb_claim(aio->handle); + aio_set_pump_mode(aio->handle, QUIET); // needed for init ig? + aio_usb_release(aio->handle); + applog(LOG_INF, "found Corsair AIO device at %04x:%04x, fw %s", AIO_USB_VID, AIO_USB_PID, aio_get_firmware_version(aio->handle, (char[16]){0})); } void aio_update(struct aio_t *aio) { if (aio->handle == NULL) return; + + aio_usb_claim(aio->handle); + aio->water_temp = aio_get_water_temp(aio->handle); aio->pump_speed = aio_get_pump_speed(aio->handle); aio->mode = aio_get_pump_mode(aio->handle); aio_get_fan_speed(aio->handle, aio->fan_speed); + + if (aio->water_temp > 36.0f && aio->mode != BALANCED) + aio_set_pump_mode(aio->handle, BALANCED); + + if (aio->water_temp < 34.0f && aio->mode != QUIET) + aio_set_pump_mode(aio->handle, QUIET); + + aio_usb_release(aio->handle); } void aio_close(const struct aio_t *aio) { - libusb_release_interface(aio->handle, 0); - libusb_attach_kernel_driver(aio->handle, 0); /* reattach so liquidctl still works */ + libusb_attach_kernel_driver(aio->handle, 0); // reattach so liquidctl still works libusb_close(aio->handle); libusb_exit(NULL); applog(LOG_INF, "AIO device closed");