From ba186cfaee6f65eded0e51c5fbf9f3907784bdbd Mon Sep 17 00:00:00 2001 From: Adam Honse Date: Mon, 27 Oct 2025 15:44:34 -0500 Subject: [PATCH] Add new controller for Razer Kraken V4 and Razer Kraken Kitty V3 Pro --- .../RazerController/RazerControllerDetect.cpp | 27 ++ Controllers/RazerController/RazerDevices.cpp | 168 ++++++++++ Controllers/RazerController/RazerDevices.h | 4 + .../RGBController_RazerKrakenV4.cpp | 130 ++++++++ .../RGBController_RazerKrakenV4.h | 41 +++ .../RazerKrakenV4Controller.cpp | 287 ++++++++++++++++++ .../RazerKrakenV4Controller.h | 118 +++++++ 7 files changed, 775 insertions(+) create mode 100644 Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.cpp create mode 100644 Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.h create mode 100644 Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.cpp create mode 100644 Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.h diff --git a/Controllers/RazerController/RazerControllerDetect.cpp b/Controllers/RazerController/RazerControllerDetect.cpp index 2eec35eca..253601f7e 100644 --- a/Controllers/RazerController/RazerControllerDetect.cpp +++ b/Controllers/RazerController/RazerControllerDetect.cpp @@ -14,12 +14,14 @@ #include "Detector.h" #include "RazerController.h" #include "RazerKrakenController.h" +#include "RazerKrakenV4Controller.h" #include "RazerHanboController.h" #include "RazerDevices.h" #include "ResourceManager.h" #include "RGBController_Razer.h" #include "RGBController_RazerAddressable.h" #include "RGBController_RazerKraken.h" +#include "RGBController_RazerKrakenV4.h" #include "RGBController_RazerHanbo.h" /******************************************************************************************\ @@ -153,6 +155,27 @@ void DetectRazerKrakenControllers(hid_device_info* info, const std::string& name } } /* DetectRazerKrakenControllers() */ +/******************************************************************************************\ +* * +* DetectRazerKrakenV4Controllers * +* * +* Tests the USB address to see if a Razer Kraken V4 controller exists there. * +* * +\******************************************************************************************/ + +void DetectRazerKrakenV4Controllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + RazerKrakenV4Controller* controller = new RazerKrakenV4Controller(dev, info->path, info->product_id, name); + + RGBController_RazerKrakenV4* rgb_controller = new RGBController_RazerKrakenV4(controller); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} /* DetectRazerKrakenV4Controllers() */ + /******************************************************************************************\ * * * DetectRazerHanboController * @@ -342,6 +365,10 @@ REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty Edition", Det REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty Black Edition", DetectRazerControllers, RAZER_VID, RAZER_KRAKEN_KITTY_BLACK_EDITION_PID, 0x01, 0x01, 0x03); REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty Black Edition V2", DetectRazerKrakenControllers, RAZER_VID, RAZER_KRAKEN_KITTY_BLACK_EDITION_V2_PID, 0x03, 0x0C, 0x01); REGISTER_HID_DETECTOR_IPU("Razer Kraken Ultimate", DetectRazerKrakenControllers, RAZER_VID, RAZER_KRAKEN_ULTIMATE_PID, 0x03, 0x0C, 0x01); +REGISTER_HID_DETECTOR_IPU("Razer Kraken V4 (Wired)", DetectRazerKrakenV4Controllers,RAZER_VID, RAZER_KRAKEN_V4_WIRED_PID, 0x05, 0xFF14, 0x01); +REGISTER_HID_DETECTOR_IPU("Razer Kraken V4 (Wireless)", DetectRazerKrakenV4Controllers,RAZER_VID, RAZER_KRAKEN_V4_WIRELESS_PID, 0x05, 0xFF14, 0x01); +REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty V3 Pro (Wired)", DetectRazerKrakenV4Controllers,RAZER_VID, RAZER_KRAKEN_KITTY_V3_PRO_WIRED_PID, 0x05, 0xFF14, 0x01); +REGISTER_HID_DETECTOR_IPU("Razer Kraken Kitty V3 Pro (Wireless)", DetectRazerKrakenV4Controllers,RAZER_VID, RAZER_KRAKEN_KITTY_V3_PRO_WIRELESS_PID, 0x05, 0xFF14, 0x01); REGISTER_HID_DETECTOR_I( "Razer Tiamat 7.1 V2", DetectRazerControllers, RAZER_VID, RAZER_TIAMAT_71_V2_PID, 0x00 ); /*-----------------------------------------------------------------------------------------------------*\ diff --git a/Controllers/RazerController/RazerDevices.cpp b/Controllers/RazerController/RazerDevices.cpp index 050a93172..50c65ff71 100644 --- a/Controllers/RazerController/RazerDevices.cpp +++ b/Controllers/RazerController/RazerDevices.cpp @@ -7701,6 +7701,170 @@ static const razer_device kraken_kitty_black_v2_device = NULL }; +/*-------------------------------------------------------------*\ +| Razer Kraken V4 Wired 1532:056B | +| | +| Zone "Headset" | +| Matrix | +| 9 LED | +\*-------------------------------------------------------------*/ +static const razer_zone kraken_v4_wired_zone = +{ + "Headset", + ZONE_TYPE_LINEAR, + 1, + 9 +}; + +static const razer_device kraken_v4_wired_device = +{ + "Razer Kraken V4 (Wired)", + RAZER_KRAKEN_V4_WIRED_PID, + DEVICE_TYPE_HEADSET, + RAZER_MATRIX_TYPE_EXTENDED, + 0x60, + 1, + 9, + { + &kraken_v4_wired_zone, + NULL, + NULL, + NULL, + NULL, + NULL + }, + NULL +}; + +/*-------------------------------------------------------------*\ +| Razer Kraken V4 Wireless 1532:056C | +| | +| Zone "Headset" | +| Matrix | +| 9 LED | +\*-------------------------------------------------------------*/ +static const razer_zone kraken_v4_wireless_zone = +{ + "Headset", + ZONE_TYPE_LINEAR, + 1, + 9 +}; + +static const razer_device kraken_v4_wireless_device = +{ + "Razer Kraken V4 (Wireless)", + RAZER_KRAKEN_V4_WIRELESS_PID, + DEVICE_TYPE_HEADSET, + RAZER_MATRIX_TYPE_EXTENDED, + 0x60, + 1, + 9, + { + &kraken_v4_wireless_zone, + NULL, + NULL, + NULL, + NULL, + NULL + }, + NULL +}; + +/*-------------------------------------------------------------*\ +| Razer Kraken Kitty V3 Pro Wired 1532:0587 | +| | +| Zone "Headset" | +| Linear | +| 9 LED | +| | +| Zone "Ears" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone kraken_kitty_v3_pro_wired_headset_zone = +{ + "Headset", + ZONE_TYPE_LINEAR, + 1, + 9 +}; + +static const razer_zone kraken_kitty_v3_pro_wired_ears_zone = +{ + "Ears", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device kraken_kitty_v3_pro_wired_device = +{ + "Razer Kraken Kitty V3 Pro (Wired)", + RAZER_KRAKEN_KITTY_V3_PRO_WIRED_PID, + DEVICE_TYPE_HEADSET, + RAZER_MATRIX_TYPE_EXTENDED, + 0x60, + 1, + 10, + { + &kraken_kitty_v3_pro_wired_headset_zone, + &kraken_kitty_v3_pro_wired_ears_zone, + NULL, + NULL, + NULL, + NULL + }, + NULL +}; + +/*-------------------------------------------------------------*\ +| Razer Kraken Kitty V3 Pro Wireless 1532:0588 | +| | +| Zone "Headset" | +| Linear | +| 9 LED | +| | +| Zone "Ears" | +| Single | +| 1 LED | +\*-------------------------------------------------------------*/ +static const razer_zone kraken_kitty_v3_pro_wireless_headset_zone = +{ + "Headset", + ZONE_TYPE_LINEAR, + 1, + 9 +}; + +static const razer_zone kraken_kitty_v3_pro_wireless_ears_zone = +{ + "Ears", + ZONE_TYPE_SINGLE, + 1, + 1 +}; + +static const razer_device kraken_kitty_v3_pro_wireless_device = +{ + "Razer Kraken Kitty V3 Pro (Wireless)", + RAZER_KRAKEN_KITTY_V3_PRO_WIRELESS_PID, + DEVICE_TYPE_HEADSET, + RAZER_MATRIX_TYPE_EXTENDED, + 0x60, + 1, + 10, + { + &kraken_kitty_v3_pro_wireless_headset_zone, + &kraken_kitty_v3_pro_wireless_ears_zone, + NULL, + NULL, + NULL, + NULL + }, + NULL +}; + /*-------------------------------------------------------------*\ | Razer Tiamat 7.1 V2 | | | @@ -8877,6 +9041,10 @@ const razer_device* razer_device_list[] = &kraken_ultimate_device, &kraken_kitty_device, &kraken_kitty_black_v2_device, + &kraken_v4_wired_device, + &kraken_v4_wireless_device, + &kraken_kitty_v3_pro_wired_device, + &kraken_kitty_v3_pro_wireless_device, &tiamat_71_v2_device, /*-----------------------------------------------------------------*\ | OTHER | diff --git a/Controllers/RazerController/RazerDevices.h b/Controllers/RazerController/RazerDevices.h index 0cd5e95ea..2ff74107b 100644 --- a/Controllers/RazerController/RazerDevices.h +++ b/Controllers/RazerController/RazerDevices.h @@ -224,6 +224,10 @@ #define RAZER_KRAKEN_ULTIMATE_PID 0x0527 #define RAZER_KRAKEN_V2_PID 0x0510 #define RAZER_KRAKEN_KITTY_BLACK_EDITION_V2_PID 0x0560 +#define RAZER_KRAKEN_V4_WIRED_PID 0x056B +#define RAZER_KRAKEN_V4_WIRELESS_PID 0x056C +#define RAZER_KRAKEN_KITTY_V3_PRO_WIRED_PID 0x0587 +#define RAZER_KRAKEN_KITTY_V3_PRO_WIRELESS_PID 0x0588 #define RAZER_TIAMAT_71_V2_PID 0x0F03 /*-----------------------------------------------------*\ diff --git a/Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.cpp b/Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.cpp new file mode 100644 index 000000000..b3eb59914 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.cpp @@ -0,0 +1,130 @@ +/*---------------------------------------------------------*\ +| RGBController_RazerKrakenV4.cpp | +| | +| RGBController for Razer 64-byte devices | +| | +| Adam Honse (CalcProgrammer1) 21 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "RGBController_RazerKrakenV4.h" +#include "RazerDevices.h" + +RGBController_RazerKrakenV4::RGBController_RazerKrakenV4(RazerKrakenV4Controller* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetName(); + vendor = "Razer"; + type = controller->GetDeviceType(); + description = "Razer Device"; + location = controller->GetDeviceLocation(); + version = controller->GetFirmwareString(); + serial = controller->GetSerialString(); + uint8_t max_brightness = controller->GetMaxBrightness(); + + mode Direct; + Direct.name = "Direct"; + Direct.value = RAZER_KRAKEN_V4_MODE_DIRECT; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + mode Wave; + Wave.name = "Wave"; + Wave.value = RAZER_KRAKEN_V4_MODE_WAVE; + Wave.flags = MODE_FLAG_HAS_BRIGHTNESS; + Wave.direction = MODE_DIRECTION_RIGHT; + Wave.color_mode = MODE_COLORS_NONE; + Wave.brightness_min = 0; + Wave.brightness_max = max_brightness; + Wave.brightness = max_brightness; + modes.push_back(Wave); + + SetupZones(); +} + +RGBController_RazerKrakenV4::~RGBController_RazerKrakenV4() +{ + delete controller; +} + +void RGBController_RazerKrakenV4::SetupZones() +{ + unsigned int device_index = controller->GetDeviceIndex(); + + /*-----------------------------------------------------*\ + | Fill in zone information based on device table | + | Kraken V4 devices are assumed to only have one row | + \*-----------------------------------------------------*/ + for(unsigned int zone_id = 0; zone_id < RAZER_MAX_ZONES; zone_id++) + { + if(device_list[device_index]->zones[zone_id] != NULL) + { + zone new_zone; + + new_zone.name = device_list[device_index]->zones[zone_id]->name; + new_zone.type = device_list[device_index]->zones[zone_id]->type; + + new_zone.leds_count = device_list[device_index]->zones[zone_id]->cols; + new_zone.leds_min = new_zone.leds_count; + new_zone.leds_max = new_zone.leds_count; + new_zone.matrix_map = NULL; + + zones.push_back(new_zone); + + for(unsigned int col_id = 0; col_id < device_list[device_index]->zones[zone_id]->cols; col_id++) + { + led* new_led = new led(); + + new_led->name = device_list[device_index]->zones[zone_id]->name; + + if(zones[zone_id].leds_count > 1) + { + new_led->name.append(" LED "); + new_led->name.append(std::to_string(col_id + 1)); + } + + leds.push_back(*new_led); + } + } + } + + SetupColors(); +} + +void RGBController_RazerKrakenV4::ResizeZone(int /*zone*/, int /*new_size*/) +{ + +} + +void RGBController_RazerKrakenV4::DeviceUpdateLEDs() +{ + if(modes[active_mode].value == RAZER_KRAKEN_V4_MODE_DIRECT) + { + controller->SetDirect(&colors[0]); + } +} + +void RGBController_RazerKrakenV4::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_RazerKrakenV4::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} + +void RGBController_RazerKrakenV4::DeviceUpdateMode() +{ + switch(modes[active_mode].value) + { + case RAZER_KRAKEN_V4_MODE_WAVE: + controller->SetModeWave(); + controller->SetBrightness(modes[active_mode].brightness); + break; + } +} diff --git a/Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.h b/Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.h new file mode 100644 index 000000000..4ad0c4801 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV4Controller/RGBController_RazerKrakenV4.h @@ -0,0 +1,41 @@ +/*---------------------------------------------------------*\ +| RGBController_RazerKrakenV4.h | +| | +| RGBController for Razer 64-byte devices | +| | +| Adam Honse (CalcProgrammer1) 21 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "RazerKrakenV4Controller.h" + +enum +{ + RAZER_KRAKEN_V4_MODE_DIRECT, + RAZER_KRAKEN_V4_MODE_WAVE, +}; + +class RGBController_RazerKrakenV4 : public RGBController +{ +public: + RGBController_RazerKrakenV4(RazerKrakenV4Controller* controller_ptr); + ~RGBController_RazerKrakenV4(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + RazerKrakenV4Controller* controller; +}; diff --git a/Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.cpp b/Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.cpp new file mode 100644 index 000000000..313364b13 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.cpp @@ -0,0 +1,287 @@ +/*---------------------------------------------------------*\ +| RazerKrakenV4Controller.cpp | +| | +| Driver for Razer devices with 64-byte report | +| | +| Adam Honse (CalcProgrammer1) 21 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "RazerKrakenV4Controller.h" +#include "RazerDevices.h" + +using namespace std::chrono_literals; + +RazerKrakenV4Controller::RazerKrakenV4Controller(hid_device* dev_handle, const char* path, unsigned short pid, std::string dev_name) +{ + dev = dev_handle; + dev_pid = pid; + location = path; + name = dev_name; + + /*-----------------------------------------------------*\ + | Loop through all known devices to look for a name | + | match | + \*-----------------------------------------------------*/ + for(unsigned int i = 0; i < RAZER_NUM_DEVICES; i++) + { + if(device_list[i]->pid == dev_pid) + { + /*---------------------------------------------*\ + | Set device ID | + \*---------------------------------------------*/ + device_index = i; + } + } + + /*-----------------------------------------------------*\ + | Determine matrix type for device | + \*-----------------------------------------------------*/ + matrix_type = device_list[device_index]->matrix_type; + + /*-----------------------------------------------------*\ + | All Kraken V4 devices use 0x02 for report and | + | response index | + \*-----------------------------------------------------*/ + report_index = 0x02; + response_index = 0x02; + + /*-----------------------------------------------------*\ + | Determine transaction ID for device | + \*-----------------------------------------------------*/ + dev_transaction_id = device_list[device_index]->transaction_id; + + /*-----------------------------------------------------*\ + | Determine wireless flag for device | + \*-----------------------------------------------------*/ + switch(dev_pid) + { + case RAZER_KRAKEN_V4_WIRELESS_PID: + case RAZER_KRAKEN_KITTY_V3_PRO_WIRELESS_PID: + dev_wireless_flag = 0x80; + break; + + default: + dev_wireless_flag = 0x00; + break; + } +} + +RazerKrakenV4Controller::~RazerKrakenV4Controller() +{ + hid_close(dev); +} + +std::string RazerKrakenV4Controller::GetName() +{ + return(name); +} + +unsigned int RazerKrakenV4Controller::GetDeviceIndex() +{ + return(device_index); +} + +device_type RazerKrakenV4Controller::GetDeviceType() +{ + return(device_list[device_index]->type); +} + +std::string RazerKrakenV4Controller::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string RazerKrakenV4Controller::GetFirmwareString() +{ + return(razer_get_firmware()); +} + +std::string RazerKrakenV4Controller::GetSerialString() +{ + return(razer_get_serial()); +} + +unsigned char RazerKrakenV4Controller::GetMaxBrightness() +{ + /*-----------------------------------------------------*\ + | Max brightness for most devices is 0xFF (255) | + | Add PIDs only for devices that use 0x64 (100) | + | or any another arbitrary value | + \*-----------------------------------------------------*/ + unsigned char max_brightness = 255; + + return(max_brightness); +} + +void RazerKrakenV4Controller::SetDirect(RGBColor* colors) +{ + struct razer_kraken_v4_report report = razer_kraken_v4_create_report(0x0F, 0x03, (5 + (3 * device_list[device_index]->cols))); + struct razer_kraken_v4_report response_report = razer_kraken_v4_create_response(); + + report.arguments[2] = 0; + report.arguments[3] = 0; + report.arguments[4] = device_list[device_index]->cols - 1; + + for(unsigned int led_idx = 0; led_idx < device_list[device_index]->cols; led_idx++) + { + report.arguments[5 + (led_idx * 3)] = RGBGetRValue(colors[led_idx]); + report.arguments[6 + (led_idx * 3)] = RGBGetGValue(colors[led_idx]); + report.arguments[7 + (led_idx * 3)] = RGBGetBValue(colors[led_idx]); + } + + razer_usb_send(&report); +} + +void RazerKrakenV4Controller::SetBrightness(unsigned char brightness) +{ + struct razer_kraken_v4_report report = razer_kraken_v4_create_report(0x00, 0x00, 0x05); + struct razer_kraken_v4_report response_report = razer_kraken_v4_create_response(); + + report.arguments[0] = RAZER_KRAKEN_V4_CMD_LIGHTING_SET_BRIGHTNESS; + report.arguments[2] = 0x01; + report.arguments[3] = brightness; + + razer_usb_send(&report); +} + +void RazerKrakenV4Controller::SetModeWave() +{ + struct razer_kraken_v4_report report = razer_kraken_v4_create_report(0x00, 0x00, 0x05); + struct razer_kraken_v4_report response_report = razer_kraken_v4_create_response(); + + report.arguments[0] = RAZER_KRAKEN_V4_CMD_LIGHTING_SET_MODE; + report.arguments[2] = 0x01; + report.arguments[3] = 0x04; + + razer_usb_send(&report); +} + +unsigned char RazerKrakenV4Controller::razer_kraken_v4_calculate_crc(razer_kraken_v4_report* report) +{ + /*-----------------------------------------------------*\ + | The second to last byte of report is a simple | + | checksum. Just xor all bytes up with overflow and | + | you are done | + \*-----------------------------------------------------*/ + unsigned char crc = 0; + unsigned char* report_ptr = (unsigned char*)report; + + for(unsigned int i = 0; i < 61; i++) + { + crc ^= report_ptr[i]; + } + + return crc; +} + +razer_kraken_v4_report RazerKrakenV4Controller::razer_kraken_v4_create_report(unsigned char command_class, unsigned char command_id, unsigned char data_size) +{ + razer_kraken_v4_report new_report; + + /*-----------------------------------------------------*\ + | Zero out the new report | + \*-----------------------------------------------------*/ + memset(&new_report, 0, sizeof(razer_kraken_v4_report)); + + /*-----------------------------------------------------*\ + | Fill in the new report with the given parameters | + \*-----------------------------------------------------*/ + new_report.report_id = report_index; + new_report.status = 0x00; + new_report.transaction_id = dev_transaction_id; + new_report.remaining_packets = 0x00; + new_report.protocol_type = 0x00; + new_report.data_size = data_size; + new_report.command_class = command_class; + new_report.command_id = command_id; + new_report.wireless_flag = dev_wireless_flag; + + return new_report; +} + +razer_kraken_v4_report RazerKrakenV4Controller::razer_kraken_v4_create_response() +{ + razer_kraken_v4_report new_report; + + /*-----------------------------------------------------*\ + | Zero out the new report | + \*-----------------------------------------------------*/ + memset(&new_report, 0, sizeof(razer_kraken_v4_report)); + + /*-----------------------------------------------------*\ + | Fill in the new report with the given parameters | + \*-----------------------------------------------------*/ + new_report.report_id = response_index; + new_report.status = 0x00; + new_report.transaction_id = dev_transaction_id; + new_report.remaining_packets = 0x00; + new_report.protocol_type = 0x00; + new_report.command_class = 0x00; + new_report.command_id = 0x00; + new_report.data_size = 0x00; + new_report.wireless_flag = dev_wireless_flag; + + return new_report; +} + +std::string RazerKrakenV4Controller::razer_get_firmware() +{ + std::string firmware_string = ""; + struct razer_kraken_v4_report report = razer_kraken_v4_create_report(0x00, 0x00, 0x04); + struct razer_kraken_v4_report response_report = razer_kraken_v4_create_response(); + + report.arguments[0] = RAZER_KRAKEN_V4_CMD_GET_FIRMWARE_INFO; + + std::this_thread::sleep_for(2ms); + razer_usb_send(&report); + std::this_thread::sleep_for(5ms); + razer_usb_receive(&response_report); + + firmware_string = "v" + std::to_string(response_report.arguments[3]) + "." + std::to_string(response_report.arguments[4]) + "." + std::to_string(response_report.arguments[5]) + "." + std::to_string(response_report.arguments[6]); + + return firmware_string; +} + +std::string RazerKrakenV4Controller::razer_get_serial() +{ + char serial_string[16]; + struct razer_kraken_v4_report report = razer_kraken_v4_create_report(0x00, 0x00, 0x04); + struct razer_kraken_v4_report response_report = razer_kraken_v4_create_response(); + + report.arguments[0] = RAZER_KRAKEN_V4_CMD_GET_SERIAL; + + std::this_thread::sleep_for(2ms); + razer_usb_send(&report); + std::this_thread::sleep_for(5ms); + razer_usb_receive(&response_report); + + memcpy(&serial_string[0], &response_report.arguments[3], 16); + serial_string[15] = '\0'; + + for(size_t i = 0; i < 15; i++) + { + if(serial_string[i] < 30 || serial_string[i] > 126) + { + serial_string[i] = ' '; + } + } + + std::string ret_string = serial_string; + return ret_string; +} + +int RazerKrakenV4Controller::razer_usb_receive(razer_kraken_v4_report* report) +{ + report->crc = razer_kraken_v4_calculate_crc(report); + + return hid_read(dev, (unsigned char *)report, sizeof(*report)); +} + +int RazerKrakenV4Controller::razer_usb_send(razer_kraken_v4_report* report) +{ + return hid_write(dev, (unsigned char *)report, sizeof(*report)); +} diff --git a/Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.h b/Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.h new file mode 100644 index 000000000..4a7995b03 --- /dev/null +++ b/Controllers/RazerController/RazerKrakenV4Controller/RazerKrakenV4Controller.h @@ -0,0 +1,118 @@ +/*---------------------------------------------------------*\ +| RazerKrakenV4Controller.h | +| | +| Driver for Razer devices with 64-byte report | +| | +| Adam Honse (CalcProgrammer1) 21 Oct 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "RGBController.h" +#include "DeviceGuardManager.h" + +/*---------------------------------------------------------*\ +| Struct packing macro for GCC and MSVC | +\*---------------------------------------------------------*/ +#ifdef __GNUC__ +#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) +#endif + +#ifdef _MSC_VER +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop)) +#endif + +PACK(struct razer_kraken_v4_report +{ + unsigned char report_id; + unsigned char status; + unsigned char transaction_id; + unsigned short remaining_packets; + unsigned char protocol_type; + unsigned char data_size; + unsigned char command_class; + unsigned char command_id; + unsigned char wireless_flag; + unsigned char arguments[52]; + unsigned char crc; + unsigned char reserved; +}); + +enum +{ + RAZER_KRAKEN_V4_CMD_GET_SERIAL = 0x00, + RAZER_KRAKEN_V4_CMD_GET_FIRMWARE_INFO = 0x02, + RAZER_KRAKEN_V4_CMD_LIGHTING_SET_MODE = 0xC0, + RAZER_KRAKEN_V4_CMD_LIGHTING_SET_BRIGHTNESS = 0xC1, +}; + +class RazerKrakenV4Controller +{ +public: + RazerKrakenV4Controller(hid_device* dev_handle, const char* path, unsigned short pid, std::string dev_name); + ~RazerKrakenV4Controller(); + + unsigned int GetDeviceIndex(); + device_type GetDeviceType(); + std::string GetDeviceLocation(); + std::string GetFirmwareString(); + std::string GetName(); + std::string GetSerialString(); + unsigned char GetMaxBrightness(); + + void SetDirect(RGBColor* colors); + void SetBrightness(unsigned char brightness); + + void SetModeWave(); + +private: + hid_device* dev; + unsigned short dev_pid; + + /*---------------------------------------------------------*\ + | Device-specific protocol settings | + \*---------------------------------------------------------*/ + unsigned char dev_transaction_id; + unsigned char dev_led_id; + unsigned char dev_wireless_flag; + + /*---------------------------------------------------------*\ + | Device information strings | + \*---------------------------------------------------------*/ + std::string firmware_version; + std::string location; + std::string name; + + /*---------------------------------------------------------*\ + | Index of device in Razer device list | + \*---------------------------------------------------------*/ + unsigned int device_index; + + /*---------------------------------------------------------*\ + | HID report index for request and response | + \*---------------------------------------------------------*/ + unsigned char report_index; + unsigned char response_index; + + /*---------------------------------------------------------*\ + | Matrix type | + \*---------------------------------------------------------*/ + unsigned char matrix_type; + + /*---------------------------------------------------------*\ + | Private functions based on OpenRazer | + \*---------------------------------------------------------*/ + unsigned char razer_kraken_v4_calculate_crc(razer_kraken_v4_report* report); + razer_kraken_v4_report razer_kraken_v4_create_report(unsigned char command_class, unsigned char command_id, unsigned char data_size); + razer_kraken_v4_report razer_kraken_v4_create_response(); + + std::string razer_get_firmware(); + std::string razer_get_serial(); + + int razer_usb_receive(razer_kraken_v4_report* report); + int razer_usb_send(razer_kraken_v4_report* report); +};