mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2025-12-27 01:07:49 -05:00
+ Adding Harpoon Wired and Slipstream PID to CorsairPeripheralV2Devices.h + Adding device layout + Registering detectors + Resolves #3834
396 lines
13 KiB
C++
396 lines
13 KiB
C++
/*---------------------------------------------------------------------*\
|
|
| CorsairPeripheralV2Controller.cpp |
|
|
| |
|
|
| Base class for the 08 based Corsair protocol |
|
|
| |
|
|
| Chris M (Dr_No) 07 Aug 2022 |
|
|
| |
|
|
\*---------------------------------------------------------------------*/
|
|
|
|
#include "CorsairPeripheralV2Controller.h"
|
|
|
|
using namespace std::chrono_literals;
|
|
|
|
CorsairPeripheralV2Controller::CorsairPeripheralV2Controller(hid_device* dev_handle, const char* path, std::string /*name*/)
|
|
{
|
|
const uint8_t sz = HID_MAX_STR;
|
|
wchar_t tmp[sz];
|
|
|
|
dev = dev_handle;
|
|
location = path;
|
|
|
|
hid_get_manufacturer_string(dev, tmp, sz);
|
|
std::wstring wName = std::wstring(tmp);
|
|
device_name = std::string(wName.begin(), wName.end());
|
|
|
|
hid_get_product_string(dev, tmp, sz);
|
|
wName = std::wstring(tmp);
|
|
device_name.append(" ").append(std::string(wName.begin(), wName.end()));
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Get PID |
|
|
| If the PID is in the know wireless receivers list |
|
|
| switch the write_cmd to talk to the device and retry |
|
|
\*---------------------------------------------------------*/
|
|
unsigned int pid = GetAddress(0x12);
|
|
|
|
switch(pid)
|
|
{
|
|
case CORSAIR_SLIPSTREAM_WIRELESS_PID1:
|
|
case CORSAIR_SLIPSTREAM_WIRELESS_PID2:
|
|
write_cmd = CORSAIR_V2_WRITE_WIRELESS_ID;
|
|
pid = GetAddress(0x12);
|
|
break;
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| If the hid_pid passed in from the detector does not match |
|
|
| the pid reported by the device then it is likey |
|
|
| behind a wireless receiver. |
|
|
\*---------------------------------------------------------*/
|
|
LOG_DEBUG("[%s] Setting write CMD to %02X for %s mode for PID %04X", device_name.c_str(),
|
|
write_cmd, (write_cmd == CORSAIR_V2_WRITE_WIRELESS_ID) ? "wireless" : "wired", pid);
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Get VID |
|
|
| NB: this can be achieved with GetAddress(0x11) but we |
|
|
| also need to set the packet length capabilities for |
|
|
| the device being set up. |
|
|
\*---------------------------------------------------------*/
|
|
uint8_t buffer[CORSAIR_V2_PACKET_SIZE];
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_GET;
|
|
buffer[3] = 0x11;
|
|
hid_write(dev, buffer, CORSAIR_V2_WRITE_SIZE);
|
|
uint16_t result = hid_read_timeout(dev, buffer, CORSAIR_V2_PACKET_SIZE, CORSAIR_V2_TIMEOUT);
|
|
result++;
|
|
pkt_sze = result;
|
|
LOG_DEBUG("[%s] Packet length set to %d", device_name.c_str(), pkt_sze);
|
|
|
|
/*---------------------------------------------------------*\
|
|
| NB: If the device is not found in the device list |
|
|
| then wireless mode may not work reliably |
|
|
\*---------------------------------------------------------*/
|
|
bool not_found = true;
|
|
|
|
for(uint16_t i = 0; i < CORSAIR_V2_DEVICE_COUNT; i++)
|
|
{
|
|
if(corsair_v2_device_list[i]->pid == pid)
|
|
{
|
|
/*---------------------------------------------------------*\
|
|
| Set device ID |
|
|
\*---------------------------------------------------------*/
|
|
not_found = false;
|
|
device_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(not_found)
|
|
{
|
|
LOG_ERROR("[%s] device capabilities not found. Please creata a new device request.",
|
|
device_name.c_str());
|
|
}
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Check lighting control endpoints |
|
|
| If lighting control endpoint 2 is unavailable |
|
|
| then use endpoint 1. |
|
|
\*---------------------------------------------------------*/
|
|
result = StartTransaction(0);
|
|
if(result > 0)
|
|
{
|
|
light_ctrl = CORSAIR_V2_LIGHT_CTRL1;
|
|
StartTransaction(0);
|
|
}
|
|
StopTransaction(0);
|
|
LOG_DEBUG("[%s] Lighting Endpoint set to %02X", device_name.c_str(), light_ctrl);
|
|
}
|
|
|
|
CorsairPeripheralV2Controller::~CorsairPeripheralV2Controller()
|
|
{
|
|
hid_close(dev);
|
|
}
|
|
|
|
const corsair_v2_device* CorsairPeripheralV2Controller::GetDeviceData()
|
|
{
|
|
return corsair_v2_device_list[device_index];
|
|
}
|
|
|
|
std::string CorsairPeripheralV2Controller::GetDeviceLocation()
|
|
{
|
|
return("HID: " + location);
|
|
}
|
|
|
|
std::string CorsairPeripheralV2Controller::GetErrorString(uint8_t err)
|
|
{
|
|
switch(err)
|
|
{
|
|
case 1:
|
|
return "Invalid Value";
|
|
case 3:
|
|
return "Failed";
|
|
case 5:
|
|
return "Unsupported";
|
|
default:
|
|
return "Protocol Error (Unknown)";
|
|
}
|
|
}
|
|
|
|
std::string CorsairPeripheralV2Controller::GetFirmwareString()
|
|
{
|
|
return "";
|
|
}
|
|
|
|
std::string CorsairPeripheralV2Controller::GetName()
|
|
{
|
|
return device_name;
|
|
}
|
|
|
|
std::string CorsairPeripheralV2Controller::GetSerialString()
|
|
{
|
|
const uint8_t sz = HID_MAX_STR;
|
|
wchar_t tmp[sz];
|
|
|
|
int ret = hid_get_serial_number_string(dev, tmp, sz);
|
|
|
|
if(ret != 0)
|
|
{
|
|
LOG_DEBUG("[%s] Get HID Serial string failed", device_name.c_str());
|
|
return("");
|
|
}
|
|
|
|
std::wstring w_tmp = std::wstring(tmp);
|
|
std::string serial = std::string(w_tmp.begin(), w_tmp.end());
|
|
|
|
return serial;
|
|
}
|
|
|
|
void CorsairPeripheralV2Controller::SetRenderMode(corsair_v2_device_mode mode)
|
|
{
|
|
uint8_t buffer[CORSAIR_V2_WRITE_SIZE];
|
|
|
|
memset(buffer, 0, CORSAIR_V2_WRITE_SIZE);
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Set Mode |
|
|
\*---------------------------------------------------------*/
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_SET;
|
|
buffer[3] = CORSAIR_V2_VALUE_MODE;
|
|
buffer[5] = mode;
|
|
|
|
hid_write(dev, buffer, CORSAIR_V2_WRITE_SIZE);
|
|
hid_read_timeout(dev, buffer, CORSAIR_V2_WRITE_SIZE, CORSAIR_V2_TIMEOUT);
|
|
}
|
|
|
|
void CorsairPeripheralV2Controller::LightingControl(uint8_t opt1)
|
|
{
|
|
uint8_t buffer[CORSAIR_V2_WRITE_SIZE];
|
|
|
|
memset(buffer, 0, CORSAIR_V2_WRITE_SIZE);
|
|
|
|
/*---------------------------------------------------------*\
|
|
| The Corsair command is the same for each initialisation |
|
|
| packet and the registers and options differ for |
|
|
| each peripheral supported by the protocol |
|
|
\*---------------------------------------------------------*/
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_GET;
|
|
buffer[3] = opt1;
|
|
buffer[5] = 0x00;
|
|
|
|
hid_write(dev, buffer, CORSAIR_V2_WRITE_SIZE);
|
|
hid_read_timeout(dev, buffer, CORSAIR_V2_WRITE_SIZE, CORSAIR_V2_TIMEOUT);
|
|
}
|
|
|
|
unsigned int CorsairPeripheralV2Controller::GetKeyboardLayout()
|
|
{
|
|
return GetAddress(0x41);
|
|
}
|
|
|
|
unsigned int CorsairPeripheralV2Controller::GetAddress(uint8_t address)
|
|
{
|
|
uint8_t buffer[CORSAIR_V2_WRITE_SIZE];
|
|
uint8_t read[CORSAIR_V2_WRITE_SIZE];
|
|
|
|
memset(buffer, 0, CORSAIR_V2_WRITE_SIZE);
|
|
memset(read, 0, CORSAIR_V2_WRITE_SIZE);
|
|
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_GET;
|
|
buffer[3] = address;
|
|
|
|
hid_write(dev, buffer, CORSAIR_V2_WRITE_SIZE);
|
|
hid_read_timeout(dev, read, CORSAIR_V2_WRITE_SIZE, CORSAIR_V2_TIMEOUT);
|
|
|
|
unsigned int temp = (unsigned int)(read[6] << 24 | read[5] << 16 | read[4] << 8 | read[3]);
|
|
LOG_DEBUG("[%s] GetAddress %02X - %02X %02X - %02X %02X %02X %02X %02X %02X %02X %02X", device_name.c_str(),
|
|
address, read[0], read[1], read[2], read[3], read[4], read[5], read[6], read[7], read[8], read[9]);
|
|
|
|
uint8_t result = read[2];
|
|
if(result > 0)
|
|
{
|
|
LOG_DEBUG("[%s] An error occurred! Get Address %02X failed - %d %s", device_name.c_str(),
|
|
address, result, GetErrorString(result).c_str());
|
|
return -1;
|
|
}
|
|
return temp;
|
|
}
|
|
|
|
unsigned char CorsairPeripheralV2Controller::StartTransaction(uint8_t opt1)
|
|
{
|
|
uint8_t buffer[CORSAIR_V2_WRITE_SIZE];
|
|
|
|
memset(buffer, 0, CORSAIR_V2_WRITE_SIZE);
|
|
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_START_TX;
|
|
buffer[3] = opt1;
|
|
buffer[4] = light_ctrl;
|
|
|
|
hid_write(dev, buffer, CORSAIR_V2_WRITE_SIZE);
|
|
hid_read_timeout(dev, buffer, CORSAIR_V2_WRITE_SIZE, CORSAIR_V2_TIMEOUT);
|
|
|
|
return buffer[2];
|
|
}
|
|
|
|
void CorsairPeripheralV2Controller::StopTransaction(uint8_t opt1)
|
|
{
|
|
uint8_t buffer[CORSAIR_V2_WRITE_SIZE];
|
|
|
|
memset(buffer, 0, CORSAIR_V2_WRITE_SIZE);
|
|
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_STOP_TX;
|
|
buffer[3] = 0x01;
|
|
buffer[4] = opt1;
|
|
|
|
hid_write(dev, buffer, CORSAIR_V2_WRITE_SIZE);
|
|
hid_read_timeout(dev, buffer, CORSAIR_V2_WRITE_SIZE, CORSAIR_V2_TIMEOUT);
|
|
}
|
|
|
|
void CorsairPeripheralV2Controller::ClearPacketBuffer()
|
|
{
|
|
uint8_t result = 0;
|
|
uint8_t buffer[CORSAIR_V2_PACKET_SIZE];
|
|
|
|
do
|
|
{
|
|
result = hid_read_timeout(dev, buffer, pkt_sze, CORSAIR_V2_TIMEOUT_SHORT);
|
|
}
|
|
while(result > 0);
|
|
}
|
|
|
|
void CorsairPeripheralV2Controller::SetLEDs(uint8_t *data, uint16_t data_size)
|
|
{
|
|
const uint8_t offset1 = 8;
|
|
const uint8_t offset2 = 4;
|
|
uint16_t remaining = data_size;
|
|
|
|
uint8_t buffer[CORSAIR_V2_PACKET_SIZE];
|
|
memset(buffer, 0, CORSAIR_V2_PACKET_SIZE);
|
|
|
|
ClearPacketBuffer();
|
|
StartTransaction(0);
|
|
/*---------------------------------------------------------*\
|
|
| Set the data header in packet 1 with the data length |
|
|
| signaling how many packets to expect to the device |
|
|
\*---------------------------------------------------------*/
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_BLK_W1;
|
|
buffer[4] = data_size & 0xFF;
|
|
buffer[5] = data_size >> 8;
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Check if the data needs more than 1 packet |
|
|
\*---------------------------------------------------------*/
|
|
uint16_t copy_bytes = pkt_sze - offset1;
|
|
if(remaining < copy_bytes)
|
|
{
|
|
copy_bytes = remaining;
|
|
}
|
|
|
|
memcpy(&buffer[offset1], &data[0], copy_bytes);
|
|
|
|
hid_write(dev, buffer, pkt_sze);
|
|
hid_read_timeout(dev, buffer, pkt_sze, CORSAIR_V2_TIMEOUT_SHORT);
|
|
|
|
remaining -= copy_bytes;
|
|
buffer[2] = CORSAIR_V2_CMD_BLK_WN;
|
|
copy_bytes = pkt_sze - offset2;
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Send the remaining packets |
|
|
\*---------------------------------------------------------*/
|
|
while(remaining)
|
|
{
|
|
uint16_t index = data_size - remaining;
|
|
if(remaining < copy_bytes)
|
|
{
|
|
memset(&buffer[offset2], 0, copy_bytes);
|
|
copy_bytes = remaining;
|
|
}
|
|
|
|
memcpy(&buffer[offset2], &data[index], copy_bytes);
|
|
|
|
hid_write(dev, buffer, pkt_sze);
|
|
hid_read_timeout(dev, buffer, pkt_sze, CORSAIR_V2_TIMEOUT_SHORT);
|
|
|
|
remaining -= copy_bytes;
|
|
}
|
|
|
|
StopTransaction(0);
|
|
}
|
|
|
|
void CorsairPeripheralV2Controller::UpdateHWMode(uint16_t mode, corsair_v2_color /*color_mode*/, uint8_t /*speed*/,
|
|
uint8_t /*direction*/, uint8_t /*brightness*/, std::vector<RGBColor> /*colors*/)
|
|
{
|
|
/*---------------------------------------------------------*\
|
|
| If we are switching to `Direct` mode |
|
|
| set device in software mode |
|
|
\*---------------------------------------------------------*/
|
|
if(mode == CORSAIR_V2_MODE_DIRECT)
|
|
{
|
|
SetRenderMode(CORSAIR_V2_MODE_SW);
|
|
return;
|
|
}
|
|
|
|
/*
|
|
SetRenderMode(CORSAIR_V2_MODE_HW);
|
|
|
|
uint8_t buffer[CORSAIR_V2_WRITE_SIZE];
|
|
memset(buffer, 0, CORSAIR_V2_WRITE_SIZE);
|
|
*/
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Set the data header in packet 1 with the data length |
|
|
| signaling how many packets to expect to the device |
|
|
\*---------------------------------------------------------*/
|
|
|
|
/*
|
|
buffer[1] = write_cmd;
|
|
buffer[2] = CORSAIR_V2_CMD_BLK_W1;
|
|
buffer[3] = CORSAIR_V2_MODE_HW;
|
|
buffer[4] = 0x30;
|
|
buffer[8] = mode & 0xFF;
|
|
buffer[9] = mode >> 8;
|
|
|
|
buffer[10] = CORSAIR_V2_COLOR_SPECIFIC;
|
|
buffer[11] = speed;
|
|
|
|
buffer[14] = colors.size();
|
|
|
|
for(size_t i = 0; i < colors.size(); ++i)
|
|
{
|
|
uint8_t offset = 15 + (i * 4);
|
|
|
|
buffer[offset] = brightness;
|
|
buffer[offset + 1] = RGBGetBValue(colors[i]);
|
|
buffer[offset + 2] = RGBGetGValue(colors[i]);
|
|
buffer[offset + 3] = RGBGetRValue(colors[i]);
|
|
}
|
|
*/
|
|
|
|
}
|