diff --git a/README.md b/README.md index 0162a06..5faa7dc 100644 --- a/README.md +++ b/README.md @@ -6,8 +6,8 @@ talking. This differs from a simple loopback via PulseAudio as you won't have an ## Supported Headsets Sidetone: -- Corsair Void -- Corsair Void Pro +- Corsair Void (Wireless & Wired) +- Corsair Void Pro (Wireless & Wired) - Logitech G930 - Logitech G633 - Logitech G533 diff --git a/src/device_registry.c b/src/device_registry.c index e2fdb8c..e8dda07 100644 --- a/src/device_registry.c +++ b/src/device_registry.c @@ -2,6 +2,7 @@ #include "devices/corsair_void.h" #include "devices/corsair_voidpro.h" +#include "devices/corsair_voidpro_wireless.h" #include "devices/logitech_g430.h" #include "devices/logitech_g533.h" #include "devices/logitech_g633.h" @@ -11,7 +12,7 @@ #include -#define NUMDEVICES 7 +#define NUMDEVICES 8 // array of pointers to device static struct device *(devicelist[NUMDEVICES]); @@ -19,11 +20,12 @@ void init_devices() { void_init(&devicelist[0]); voidpro_init(&devicelist[1]); - g430_init(&devicelist[2]); - g533_init(&devicelist[3]); - g633_init(&devicelist[4]); - g930_init(&devicelist[5]); - arctis7_init(&devicelist[6]); + voidpro_wireless_init(&devicelist[2]); + g430_init(&devicelist[3]); + g533_init(&devicelist[4]); + g633_init(&devicelist[5]); + g930_init(&devicelist[6]); + arctis7_init(&devicelist[7]); } int get_device(struct device* device_found, uint16_t idVendor, uint16_t idProduct) diff --git a/src/devices/CMakeLists.txt b/src/devices/CMakeLists.txt index 17fabcf..5a7e579 100644 --- a/src/devices/CMakeLists.txt +++ b/src/devices/CMakeLists.txt @@ -1,10 +1,12 @@ -set(SOURCE_FILES ${SOURCE_FILES} - ${CMAKE_CURRENT_SOURCE_DIR}/corsair_void.c - ${CMAKE_CURRENT_SOURCE_DIR}/corsair_void.h - ${CMAKE_CURRENT_SOURCE_DIR}/corsair_voidpro.c - ${CMAKE_CURRENT_SOURCE_DIR}/corsair_voidpro.h +set(SOURCE_FILES ${SOURCE_FILES} + ${CMAKE_CURRENT_SOURCE_DIR}/corsair_void.c + ${CMAKE_CURRENT_SOURCE_DIR}/corsair_void.h + ${CMAKE_CURRENT_SOURCE_DIR}/corsair_voidpro.c + ${CMAKE_CURRENT_SOURCE_DIR}/corsair_voidpro.h + ${CMAKE_CURRENT_SOURCE_DIR}/corsair_voidpro_wireless.c + ${CMAKE_CURRENT_SOURCE_DIR}/corsair_voidpro_wireless.h ${CMAKE_CURRENT_SOURCE_DIR}/logitech_g930.c - ${CMAKE_CURRENT_SOURCE_DIR}/logitech_g930.h + ${CMAKE_CURRENT_SOURCE_DIR}/logitech_g930.h ${CMAKE_CURRENT_SOURCE_DIR}/logitech_g430.c ${CMAKE_CURRENT_SOURCE_DIR}/logitech_g430.h ${CMAKE_CURRENT_SOURCE_DIR}/logitech_g533.c diff --git a/src/devices/corsair_voidpro_wireless.c b/src/devices/corsair_voidpro_wireless.c new file mode 100644 index 0000000..b8f4e2c --- /dev/null +++ b/src/devices/corsair_voidpro_wireless.c @@ -0,0 +1,92 @@ +#include "../device.h" +#include "../utility.h" + +#include +#include + +enum voidpro_wireless_battery_flags { + VOIDPRO_WIRELESS_BATTERY_MICUP = 128 +}; + +static struct device device_voidpro_wireless; + +static int voidpro_wireless_send_sidetone(hid_device *device_handle, uint8_t num); +static int voidpro_wireless_request_battery(hid_device *device_handle); +static int voidpro_wireless_notification_sound(hid_device *hid_device, uint8_t soundid); + +void voidpro_wireless_init(struct device** device) +{ + device_voidpro_wireless.idVendor = VENDOR_CORSAIR; + device_voidpro_wireless.idProduct = 0x0a1a; + + strcpy(device_voidpro_wireless.device_name, "Corsair Void Pro Wireless"); + + device_voidpro_wireless.capabilities = CAP_SIDETONE | CAP_BATTERY_STATUS | CAP_NOTIFICATION_SOUND; + device_voidpro_wireless.send_sidetone = &voidpro_wireless_send_sidetone; + device_voidpro_wireless.request_battery = &voidpro_wireless_request_battery; + device_voidpro_wireless.notifcation_sound = &voidpro_wireless_notification_sound; + + *device = &device_voidpro_wireless; +} + +static int voidpro_wireless_send_sidetone(hid_device *device_handle, uint8_t num) +{ + // the range of the voidpro seems to be from 200 to 255 + num = map(num, 0, 128, 200, 255); + + unsigned char data[12] = {0xFF, 0x0B, 0, 0xFF, 0x04, 0x0E, 0xFF, 0x05, 0x01, 0x04, 0x00, num}; + + return hid_send_feature_report(device_handle, data, 12); +} + +static int voidpro_wireless_request_battery(hid_device *device_handle) +{ + // Packet Description + // Answer of battery status + // Index 0 1 2 3 4 + // Data 100 0 Loaded% 177 5 when loading, 0 when loading and off, 1 otherwise + // + // Loaded% has bitflag VOIDPRO_BATTERY_MICUP set when mic is in upper position + + int r = 0; + + // request battery status + unsigned char data_request[2] = {0xC9, 0x64}; + + r = hid_write(device_handle, data_request, 2); + + if (r < 0) return r; + + // read battery status + unsigned char data_read[5]; + + r = hid_read(device_handle, data_read, 5); + + if (r < 0) return r; + + if (data_read[4] == 0 || data_read[4] == 4 || data_read[4] == 5) + { + return BATTERY_LOADING; + } + else if (data_read[4] == 1) + { + // Discard VOIDPRO_BATTERY_MICUP when it's set + // see https://github.com/Sapd/HeadsetControl/issues/13 + if (data_read[2] & VOIDPRO_WIRELESS_BATTERY_MICUP) + return data_read[2] &~ VOIDPRO_WIRELESS_BATTERY_MICUP; + else + return (int)data_read[2]; // battery status from 0 - 100 + } + else + { + return -100; + } +} + +static int voidpro_wireless_notification_sound(hid_device* device_handle, uint8_t soundid) +{ + // soundid can be 0 or 1 + unsigned char data[5] = {0xCA, 0x02, soundid}; + + return hid_write(device_handle, data, 3); +} diff --git a/src/devices/corsair_voidpro_wireless.h b/src/devices/corsair_voidpro_wireless.h new file mode 100644 index 0000000..7d3ff0f --- /dev/null +++ b/src/devices/corsair_voidpro_wireless.h @@ -0,0 +1,3 @@ +#pragma once + +void voidpro_wireless_init(struct device** device);