From a247e8ecf6215b83f534b108b1b091352d53885d Mon Sep 17 00:00:00 2001 From: Drath Date: Sat, 23 May 2026 18:08:36 +0000 Subject: [PATCH] add aio reading --- CMakeLists.txt | 7 ++++- include/aio.h | 27 ++++++++++++++++ src/aio.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 include/aio.h create mode 100644 src/aio.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 047d6ca..2325bcb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,10 +36,15 @@ target_compile_options(linuxSmartie ) find_package(ZLIB QUIET) - if(ZLIB_FOUND) target_link_libraries(linuxSmartie PRIVATE ZLIB::ZLIB) target_compile_definitions(linuxSmartie PRIVATE ENABLE_ZLIB) else() message(STATUS "no zlib found, disabling saving logs to gz") endif() + +find_package(PkgConfig REQUIRED) +pkg_check_modules(LIBUSB REQUIRED libusb-1.0) + +target_link_libraries(linuxSmartie PRIVATE ${LIBUSB_LIBRARIES}) +target_include_directories(linuxSmartie PRIVATE ${LIBUSB_INCLUDE_DIRS}) diff --git a/include/aio.h b/include/aio.h new file mode 100644 index 0000000..1f4ecdc --- /dev/null +++ b/include/aio.h @@ -0,0 +1,27 @@ +#ifndef LINUXSMARTIE_AIO_H +#define LINUXSMARTIE_AIO_H + +#include + +#define CORSAIR_VID 0x1b1c +#define AIO_PID 0x0c13 + +enum aio_pump_mode_t : uint8_t { + QUIET, + BALANCED, + EXTREME +}; + +struct aio_t{ + libusb_device_handle* handle; + enum aio_pump_mode_t mode; + float water_temp; + uint16_t pump_speed; + uint16_t fan_speed[2]; +}; + +void aio_detect(struct aio_t *aio); +void aio_update(struct aio_t *aio); +void aio_close(const struct aio_t *aio); + +#endif diff --git a/src/aio.c b/src/aio.c new file mode 100644 index 0000000..0e0de36 --- /dev/null +++ b/src/aio.c @@ -0,0 +1,85 @@ +#include "aio.h" +#include "log.h" + +#include + +static const uint8_t buf_size = 32; // needs 32 bc of overflow issue on these aios? + +static int aio_post(libusb_device_handle *dev, uint8_t *req, const int req_len, uint8_t *resp, const int resp_len) { + int transferred; + int r = libusb_bulk_transfer(dev, 0x01, req, req_len, &transferred, 1000); + usleep(5 * 1000); /* 5ms — give the device time to prepare the response */ + if (r < 0) + return r; + + r = libusb_bulk_transfer(dev, 0x81, resp, resp_len, &transferred, 1000); + return r; +} + +float aio_get_water_temp(libusb_device_handle* aio) { + uint8_t req = 0xa9; + uint8_t resp[buf_size]; + aio_post(aio, &req, sizeof(req), resp, 6); + return (float)resp[3] + (float)resp[4] / 10.0f; +} + +uint16_t aio_get_pump_speed(libusb_device_handle* aio) { + uint8_t req = 0x31; + uint8_t resp[buf_size]; + aio_post(aio, &req, sizeof(req), resp, 5); + return resp[3] << 8 | resp[4]; +} + +enum aio_pump_mode_t aio_get_pump_mode(libusb_device_handle* aio) { + uint8_t req = 0x33; + uint8_t resp[buf_size]; + aio_post(aio, &req, sizeof(req), resp, 4); + return (enum aio_pump_mode_t)resp[3]; +} + +void aio_get_fan_speed(libusb_device_handle* aio, uint16_t *speeds) { + uint8_t req[2] = {0x41}; + uint8_t resp[buf_size]; + + for (uint8_t i = 0; i < 2; i++) { + req[1] = i; + aio_post(aio, req, sizeof(req), resp, 6); + speeds[i] = resp[4] << 8 | resp[5]; + } +} + +void aio_detect(struct aio_t *aio) { + libusb_init(NULL); + aio->handle = libusb_open_device_with_vid_pid(NULL, CORSAIR_VID, AIO_PID); + if (aio->handle == NULL) { + applog(LOG_ERR, "Can't open AIO USB device %x:%x", CORSAIR_VID, AIO_PID); + return; + } + + /* detach kernel driver if attached */ + 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", CORSAIR_VID, AIO_PID); + else + applog(LOG_ERR, "failed to claim AIO device"); +} + +void aio_update(struct aio_t *aio) { + if (aio->handle == NULL) + return; + 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); +} + +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_close(aio->handle); + libusb_exit(NULL); + applog(LOG_INF, "AIO device closed"); +} \ No newline at end of file