feat: Roccat Kova support

This commit is contained in:
Gustavo Parreira 2022-12-03 07:45:42 +00:00 committed by Adam Honse
parent 790abdd9c0
commit 7892713683
6 changed files with 428 additions and 0 deletions

View file

@ -0,0 +1,144 @@
/*-----------------------------------------*\
| RGBController_RoccatKova.cpp |
| |
| RGB Controller for Roccat Kova |
| |
| Gustash 01/12/2022 |
\*-----------------------------------------*/
#include "RGBController_RoccatKova.h"
/**------------------------------------------------------------------*\
@name Roccat Kova
@category Mouse
@type USB
@save :robot:
@direct :x:
@effects :white_check_mark:
@detectors RoccatControllerDetect
@comment Color Flow mode is only supported starting at the first
preset color in the mouse's memory, and color offsets for each LED
are not supported. You'd need to use Swarm if you intend to use that
specific feature.
*/
RGBController_RoccatKova::RGBController_RoccatKova(RoccatKovaController* controller_ptr)
{
controller = controller_ptr;
type = DEVICE_TYPE_MOUSE;
name = "Roccat Kova";
vendor = "Roccat";
description = "Controller compatible with the Roccat Kova gaming mouse";
serial = controller->GetSerial();
location = controller->GetLocation();
version = controller->GetFirmwareVersion();
mode Static;
Static.name = "Static";
Static.value = ROCCAT_KOVA_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE;
Static.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Static);
mode ColorFlow;
ColorFlow.name = "Color Flow";
ColorFlow.value = ROCCAT_KOVA_MODE_COLOR_FLOW;
ColorFlow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
ColorFlow.color_mode = MODE_COLORS_RANDOM;
ColorFlow.speed_min = ROCCAT_KOVA_SPEED_MIN;
ColorFlow.speed_max = ROCCAT_KOVA_SPEED_MAX;
modes.push_back(ColorFlow);
mode Flashing;
Flashing.name = "Flashing";
Flashing.value = ROCCAT_KOVA_MODE_FLASHING;
Flashing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Flashing.color_mode = MODE_COLORS_PER_LED;
Flashing.speed_min = ROCCAT_KOVA_SPEED_MIN;
Flashing.speed_max = ROCCAT_KOVA_SPEED_MAX;
modes.push_back(Flashing);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ROCCAT_KOVA_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_AUTOMATIC_SAVE;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.speed_min = ROCCAT_KOVA_SPEED_MIN;
Breathing.speed_max = ROCCAT_KOVA_SPEED_MAX;
modes.push_back(Breathing);
mode Off;
Off.name = "Off";
Off.value = 0x00;
Off.flags = MODE_FLAG_AUTOMATIC_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
SetupZones();
}
RGBController_RoccatKova::~RGBController_RoccatKova()
{
delete controller;
}
void RGBController_RoccatKova::SetupZones()
{
zone Mouse;
Mouse.name = "Mouse";
Mouse.type = ZONE_TYPE_LINEAR;
Mouse.leds_count = ROCCAT_KOVA_LED_COUNT;
Mouse.leds_min = ROCCAT_KOVA_LED_COUNT;
Mouse.leds_max = ROCCAT_KOVA_LED_COUNT;
Mouse.matrix_map = NULL;
zones.push_back(Mouse);
led WheelLED;
WheelLED.name = "Wheel LED";
WheelLED.value = ROCCAT_KOVA_WHEEL_IDX;
leds.push_back(WheelLED);
led StripeLED;
StripeLED.name = "Stripe LED";
StripeLED.value = ROCCAT_KOVA_PIPE_IDX;
leds.push_back(StripeLED);
SetupColors();
}
void RGBController_RoccatKova::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_RoccatKova::DeviceUpdateLEDs()
{
DeviceUpdateMode();
}
void RGBController_RoccatKova::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateMode();
}
void RGBController_RoccatKova::UpdateSingleLED(int /*led*/)
{
DeviceUpdateMode();
}
void RGBController_RoccatKova::DeviceUpdateMode()
{
mode &active = modes[active_mode];
int mode = active.value;
bool is_color_flow = active.color_mode == MODE_COLORS_RANDOM;
if(active.value == ROCCAT_KOVA_MODE_COLOR_FLOW)
{
mode = ROCCAT_KOVA_MODE_STATIC;
is_color_flow = true;
}
controller->SetColor(colors[0], colors[1], mode, active.speed, is_color_flow);
}

View file

@ -0,0 +1,32 @@
/*-----------------------------------------*\
| RGBController_RoccatKova.h |
| |
| RGB Controller for Roccat Kova |
| |
| Gustash 01/12/2022 |
\*-----------------------------------------*/
#pragma once
#include "RGBController.h"
#include "RoccatKovaController.h"
class RGBController_RoccatKova : public RGBController
{
public:
RGBController_RoccatKova(RoccatKovaController *controller_ptr);
~RGBController_RoccatKova();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
RoccatKovaController *controller;
};

View file

@ -10,11 +10,13 @@
#include "RoccatBurstController.h"
#include "RoccatKoneAimoController.h"
#include "RoccatVulcanAimoController.h"
#include "RoccatKovaController.h"
#include "RGBController.h"
#include "RGBController_RoccatBurst.h"
#include "RGBController_RoccatHordeAimo.h"
#include "RGBController_RoccatKoneAimo.h"
#include "RGBController_RoccatVulcanAimo.h"
#include "RGBController_RoccatKova.h"
#include <hidapi/hidapi.h>
#include <unordered_set>
@ -26,6 +28,7 @@
#define ROCCAT_HORDE_AIMO_PID 0x303E
#define ROCCAT_BURST_CORE_PID 0x2DE6
#define ROCCAT_BURST_PRO_PID 0x2DE1
#define ROCCAT_KOVA_PID 0x2CEE
void DetectRoccatMouseControllers(hid_device_info* info, const std::string& name)
{
@ -157,6 +160,19 @@ void DetectRoccatBurstProControllers(hid_device_info* info, const std::string& n
}
}
void DetectRoccatKovaControllers(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
RoccatKovaController * controller = new RoccatKovaController(dev, info->path);
RGBController_RoccatKova * rgb_controller = new RGBController_RoccatKova(controller);
rgb_controller->name = name;
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_PRE_DETECTION_HOOK(ResetRoccatVulcanAimoControllersPaths);
REGISTER_HID_DETECTOR_IPU("Roccat Kone Aimo", DetectRoccatMouseControllers, ROCCAT_VID, ROCCAT_KONE_AIMO_PID, 0, 0x0B, 0 );
@ -165,3 +181,4 @@ REGISTER_HID_DETECTOR_IP ("Roccat Vulcan 120-Series Aimo", DetectRoccatVulcanAi
REGISTER_HID_DETECTOR_IPU("Roccat Horde Aimo", DetectRoccatHordeAimoKeyboardControllers, ROCCAT_VID, ROCCAT_HORDE_AIMO_PID, 1, 0x0B, 0);
REGISTER_HID_DETECTOR_IPU("Roccat Burst Core", DetectRoccatBurstCoreControllers, ROCCAT_VID, ROCCAT_BURST_CORE_PID, 3, 0xFF01, 1);
REGISTER_HID_DETECTOR_IPU("Roccat Burst Pro", DetectRoccatBurstProControllers, ROCCAT_VID, ROCCAT_BURST_PRO_PID, 3, 0xFF01, 1);
REGISTER_HID_DETECTOR_IPU("Roccat Kova", DetectRoccatKovaControllers, ROCCAT_VID, ROCCAT_KOVA_PID, 0, 0x0B, 0);

View file

@ -0,0 +1,143 @@
/*-----------------------------------------*\
| RoccatKovaController.cpp |
| |
| Controller for Roccat Kova |
| |
| Gustash 01/12/2022 |
\*-----------------------------------------*/
#include "RoccatKovaController.h"
#include "LogManager.h"
#include <hidapi/hidapi.h>
RoccatKovaController::RoccatKovaController(hid_device* dev_handle, char *path)
{
dev = dev_handle;
location = path;
SendInitialPacket();
FetchFirmwareVersion();
}
RoccatKovaController::~RoccatKovaController()
{
hid_close(dev);
}
std::string RoccatKovaController::GetLocation()
{
return ("HID: " + location);
}
std::string RoccatKovaController::GetSerial()
{
const uint8_t sz = ROCCAT_KOVA_HID_MAX_STR;
wchar_t tmp[sz];
uint8_t ret = hid_get_serial_number_string(dev, tmp, sz);
if(ret != 0)
{
LOG_DEBUG("[Roccat Kova] Get HID Serial string failed");
return "";
}
std::wstring w_tmp = std::wstring(tmp);
std::string serial = std::string(w_tmp.begin(), w_tmp.end());
return serial;
}
std::string RoccatKovaController::GetFirmwareVersion()
{
return firmware_version;
}
void RoccatKovaController::SetColor(RGBColor color_wheel,
RGBColor color_stripe,
uint8_t mode,
uint8_t speed,
bool color_flow)
{
bool is_off = mode == ROCCAT_KOVA_MODE_OFF;
uint8_t report_buf[ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE] {00};
FetchProfileData(report_buf);
report_buf[0x0] = ROCCAT_KOVA_PROFILE_REPORT_ID;
report_buf[0x1] = ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE;
report_buf[ROCCAT_KOVA_FLAGS_IDX] |= ROCCAT_KOVA_USE_CUSTOM_COLORS_MASK;
if(is_off)
{
report_buf[ROCCAT_KOVA_FLAGS_IDX] &= ~ROCCAT_KOVA_LIGHTS_ON_MASK;
}
else
{
report_buf[ROCCAT_KOVA_FLAGS_IDX] |= ROCCAT_KOVA_LIGHTS_ON_MASK;
}
/*-------------------------------------------------*\
| Set colors for each LED and reset the selected |
| preset color to ensure consistency |
\*-------------------------------------------------*/
report_buf[ROCCAT_KOVA_WHEEL_IDX] = 0x0;
report_buf[ROCCAT_KOVA_WHEEL_IDX + ROCCAT_KOVA_R_OFFSET] = RGBGetRValue(color_wheel);
report_buf[ROCCAT_KOVA_WHEEL_IDX + ROCCAT_KOVA_G_OFFSET] = RGBGetGValue(color_wheel);
report_buf[ROCCAT_KOVA_WHEEL_IDX + ROCCAT_KOVA_B_OFFSET] = RGBGetBValue(color_wheel);
report_buf[ROCCAT_KOVA_PIPE_IDX] = 0x0;
report_buf[ROCCAT_KOVA_PIPE_IDX + ROCCAT_KOVA_R_OFFSET] = RGBGetRValue(color_stripe);
report_buf[ROCCAT_KOVA_PIPE_IDX + ROCCAT_KOVA_G_OFFSET] = RGBGetGValue(color_stripe);
report_buf[ROCCAT_KOVA_PIPE_IDX + ROCCAT_KOVA_B_OFFSET] = RGBGetBValue(color_stripe);
report_buf[ROCCAT_KOVA_COLOR_FLOW_IDX] = color_flow;
if(!is_off)
{
report_buf[ROCCAT_KOVA_MODE_IDX] = mode;
}
report_buf[ROCCAT_KOVA_EFFECT_SPEED_IDX] = speed;
uint16_t checksum = GenerateChecksum(report_buf, sizeof(report_buf) - 2);
report_buf[ROCCAT_KOVA_CHECKSUM_IDX] = checksum & 0xFF;
report_buf[ROCCAT_KOVA_CHECKSUM_IDX + 1] = checksum >> 8;
hid_send_feature_report(dev, report_buf, ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE);
}
void RoccatKovaController::SendInitialPacket()
{
uint8_t buf[ROCCAT_KOVA_INIT_WRITE_PACKET_SIZE] {00};
buf[0x00] = ROCCAT_KOVA_INIT_REPORT_ID;
buf[0x01] = 0x00;
buf[0x02] = 0x80;
hid_send_feature_report(dev, buf, ROCCAT_KOVA_INIT_WRITE_PACKET_SIZE);
}
void RoccatKovaController::FetchFirmwareVersion()
{
uint8_t buf[ROCCAT_KOVA_VERSION_READ_PACKET_SIZE] {00};
buf[0x0] = ROCCAT_KOVA_VERSION_REPORT_ID;
hid_get_feature_report(dev, buf, ROCCAT_KOVA_VERSION_READ_PACKET_SIZE);
uint8_t version = buf[ROCCAT_KOVA_FIRMWARE_VERSION_IDX];
char version_str[5] {00};
sprintf(version_str, "%.2f", version / 100.);
firmware_version = version_str;
}
void RoccatKovaController::FetchProfileData(uint8_t *buf)
{
buf[0x00] = ROCCAT_KOVA_PROFILE_REPORT_ID;
hid_get_feature_report(dev, buf, ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE);
}
uint16_t RoccatKovaController::GenerateChecksum(uint8_t *buf, size_t length)
{
uint16_t checksum = 0x0;
for (uint8_t idx = 0; idx < length; idx++)
{
checksum += buf[idx];
}
return checksum;
}

View file

@ -0,0 +1,88 @@
/*-----------------------------------------*\
| RoccatKovaController.h |
| |
| Controller for Roccat Kova |
| |
| Gustash 01/12/2022 |
\*-----------------------------------------*/
#pragma once
#include "RGBController.h"
#include <hidapi/hidapi.h>
#define ROCCAT_KOVA_HID_MAX_STR 255
#define ROCCAT_KOVA_LED_COUNT 2
#define ROCCAT_KOVA_SPEED_MIN 1
#define ROCCAT_KOVA_SPEED_MAX 3
#define ROCCAT_KOVA_INIT_REPORT_ID 4
#define ROCCAT_KOVA_INIT_WRITE_PACKET_SIZE 3
#define ROCCAT_KOVA_PROFILE_REPORT_ID 6
#define ROCCAT_KOVA_PROFILE_WRITE_PACKET_SIZE 28
#define ROCCAT_KOVA_VERSION_REPORT_ID 9
#define ROCCAT_KOVA_VERSION_READ_PACKET_SIZE 8
/*#define NUM_OF_DPI_SWITCHES 5*/
enum
{
ROCCAT_KOVA_FIRMWARE_VERSION_IDX = 2,
/*ROCCAT_KOVA_SELECTED_PROFILE_IDX = 2,*/
/*ROCCAT_KOVA_UNKNOWN_3_IDX = 3,*/
/*ROCCAT_KOVA_UNKNOWN_4_IDX = 4,*/
/*ROCCAT_KOVA_ORIENTATION_IDX = 5,*/
/*ROCCAT_KOVA_DPI_SWITCHER_IDX = 6,*/
/*ROCCAT_KOVA_DPI_SPEED_IDX = 7,*/
/*ROCCAT_KOVA_SELECTED_DPI_IDX = 12,*/
/*ROCCAT_KOVA_POLLING_RATE_IDX = 13,*/
ROCCAT_KOVA_FLAGS_IDX = 14,
ROCCAT_KOVA_COLOR_FLOW_IDX = 15,
ROCCAT_KOVA_MODE_IDX = 16,
ROCCAT_KOVA_EFFECT_SPEED_IDX = 17,
ROCCAT_KOVA_PIPE_IDX = 18,
ROCCAT_KOVA_WHEEL_IDX = 22,
ROCCAT_KOVA_CHECKSUM_IDX = 26,
};
#define ROCCAT_KOVA_R_OFFSET 1
#define ROCCAT_KOVA_G_OFFSET 2
#define ROCCAT_KOVA_B_OFFSET 3
#define ROCCAT_KOVA_USE_CUSTOM_COLORS_MASK 0b00110000
#define ROCCAT_KOVA_LIGHTS_ON_MASK 0b00000011
enum
{
ROCCAT_KOVA_MODE_OFF = 0x00,
ROCCAT_KOVA_MODE_STATIC = 0x01,
ROCCAT_KOVA_MODE_FLASHING = 0x02,
ROCCAT_KOVA_MODE_BREATHING = 0x03,
ROCCAT_KOVA_MODE_COLOR_FLOW = 0xFF,
};
class RoccatKovaController
{
public:
RoccatKovaController(hid_device* dev_handle, char *path);
~RoccatKovaController();
std::string GetLocation();
std::string GetSerial();
std::string GetFirmwareVersion();
void SetColor(RGBColor color_wheel,
RGBColor color_stripe,
uint8_t mode,
uint8_t speed,
bool color_flow);
private:
hid_device* dev;
std::string location;
std::string firmware_version;
void SendInitialPacket();
void FetchProfileData(uint8_t *buf);
void FetchFirmwareVersion();
uint16_t GenerateChecksum(uint8_t *buf, size_t length);
};