The K70 RGB PRO V2 (1B1C:1BB3) was detected but never lit: it blanked into software render mode and then fell back to its onboard effect. Getting it working turned up five faults, three of which affect every Corsair V2 device rather than just this keyboard. Packet size is now read from the HID report descriptor before the first write instead of being inferred from a reply. These devices come in a 64 byte and a 1024 byte flavour, and sending a short packet to a 1024 byte endpoint stalls it until the device is power cycled, so the size has to be known up front rather than after two short queries have gone out. CORSAIR_V2_PACKET_SIZE was 1024 while pkt_sze reached 1025, so every read using pkt_sze overran its stack buffer by a byte. The command helpers now use pkt_sze against buffers of the corrected size. The lighting resource probe ran before the device was placed in software render mode, where the answer is meaningless, and treated any error as "use resource 1". Devices that answer invalid or unsupported for resource 1 want the alternate lighting resource, which takes RGB triplets; this keyboard is one of them. The probe now runs after the render mode switch and distinguishes a stale open handle from an unsupported resource. Direct lighting writes were sized from the keymap, which covers only the keys that exist. The hardware expects its full slot count and ignores a short write, so corsair_v2_device carries an optional hw_led_count and the buffer map is padded to it. Set to 193 for this keyboard. The keepalive thread wrote LEDs on its first pass, because last_update_time was left at the clock epoch and so always read as older than the update period. That raced detection on the same HID handle with no locking, which both corrupted the transaction and could abort the process. The clock is now started before the thread runs, device transactions are serialised behind a mutex, and the thread is stopped before Shutdown rather than after. Also fixes an uninitialised stack buffer sent to the device during setup, and widens the K70 RGB PRO matrix to 22 columns so the numpad period key has a position in the layout instead of being dropped. Verified on hardware: repeated colour changes apply and the device stays responsive across runs. Co-Authored-By: Claude Opus 5 <[email protected]>
95 lines
3.2 KiB
C++
95 lines
3.2 KiB
C++
/*---------------------------------------------------------*\
|
|
| CorsairPeripheralV2HardwareController.cpp |
|
|
| |
|
|
| Driver for Corsair V2 peripherals - hardware modes |
|
|
| |
|
|
| Chris M (Dr_No) 07 Dec 2022 |
|
|
| |
|
|
| This file is part of the OpenRGB project |
|
|
| SPDX-License-Identifier: GPL-2.0-or-later |
|
|
\*---------------------------------------------------------*/
|
|
|
|
#include "LogManager.h"
|
|
#include "CorsairPeripheralV2HardwareController.h"
|
|
|
|
CorsairPeripheralV2HWController::CorsairPeripheralV2HWController(hid_device* dev_handle, const char* path, std::string name) : CorsairPeripheralV2Controller(dev_handle, path, name)
|
|
{
|
|
SetRenderMode(CORSAIR_V2_MODE_SW);
|
|
LightingControl(0x5F);
|
|
|
|
/*---------------------------------------------------------*\
|
|
| Only now that the device is in software render mode can |
|
|
| its lighting control endpoint be probed reliably. |
|
|
\*---------------------------------------------------------*/
|
|
DetectLightingEndpoint();
|
|
}
|
|
|
|
CorsairPeripheralV2HWController::~CorsairPeripheralV2HWController()
|
|
{
|
|
|
|
}
|
|
|
|
void CorsairPeripheralV2HWController::SetLedsDirect(std::vector<RGBColor *>colors)
|
|
{
|
|
switch(light_ctrl)
|
|
{
|
|
case CORSAIR_V2_LIGHT_CTRL1:
|
|
SetLedsDirectColourBlocks(colors);
|
|
break;
|
|
case CORSAIR_V2_LIGHT_CTRL2:
|
|
SetLedsDirectTriplets(colors);
|
|
break;
|
|
default:
|
|
LOG_ERROR("[%s] Error setting Direct mode: Device supportes returned %i",
|
|
device_name.c_str(), light_ctrl);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void CorsairPeripheralV2HWController::SetLedsDirectColourBlocks(std::vector<RGBColor *>colors)
|
|
{
|
|
uint16_t count = (uint16_t)colors.size();
|
|
uint16_t green = count;
|
|
uint16_t blue = (count * 2);
|
|
uint16_t length = (count * 3);
|
|
uint8_t* buffer = new uint8_t[length];
|
|
|
|
memset(buffer, 0, length);
|
|
|
|
for(std::size_t i = 0; i < count; i++)
|
|
{
|
|
RGBColor color = *colors[i];
|
|
|
|
buffer[i] = RGBGetRValue(color);
|
|
buffer[i + green] = RGBGetGValue(color);
|
|
buffer[i + blue] = RGBGetBValue(color);
|
|
}
|
|
|
|
SetLEDs(buffer, length);
|
|
delete[] buffer;
|
|
}
|
|
|
|
void CorsairPeripheralV2HWController::SetLedsDirectTriplets(std::vector<RGBColor *>colors)
|
|
{
|
|
uint16_t count = (uint16_t)colors.size();
|
|
uint16_t length = (count * 3) + CORSAIR_V2HW_DATA_OFFSET;
|
|
uint8_t* buffer = new uint8_t[length];
|
|
|
|
memset(buffer, 0, length);
|
|
|
|
buffer[0] = CORSAIR_V2_MODE_DIRECT & 0xFF;
|
|
buffer[1] = CORSAIR_V2_MODE_DIRECT >> 8;
|
|
for(std::size_t i = 0; i < count; i++)
|
|
{
|
|
RGBColor color = *colors[i];
|
|
std::size_t idx = (i * 3) + CORSAIR_V2HW_DATA_OFFSET;
|
|
|
|
buffer[idx] = RGBGetRValue(color);
|
|
buffer[idx + 1] = RGBGetGValue(color);
|
|
buffer[idx + 2] = RGBGetBValue(color);
|
|
}
|
|
|
|
SetLEDs(buffer, length);
|
|
delete[] buffer;
|
|
}
|