From 7495fe998e133eee4f50bdbeecc8f27dd977188b Mon Sep 17 00:00:00 2001 From: morg Date: Wed, 1 Jun 2022 22:04:01 +0200 Subject: [PATCH] Add support for Roccat Burst Core. Closes #2491 --- .../RGBController_RoccatBurstCore.cpp | 181 ++++++++++++++++++ .../RGBController_RoccatBurstCore.h | 30 +++ .../RoccatBurstCoreController.cpp | 160 ++++++++++++++++ .../RoccatBurstCoreController.h | 67 +++++++ .../RoccatControllerDetect.cpp | 17 ++ OpenRGB.pro | 4 + 6 files changed, 459 insertions(+) create mode 100644 Controllers/RoccatController/RGBController_RoccatBurstCore.cpp create mode 100644 Controllers/RoccatController/RGBController_RoccatBurstCore.h create mode 100644 Controllers/RoccatController/RoccatBurstCoreController.cpp create mode 100644 Controllers/RoccatController/RoccatBurstCoreController.h diff --git a/Controllers/RoccatController/RGBController_RoccatBurstCore.cpp b/Controllers/RoccatController/RGBController_RoccatBurstCore.cpp new file mode 100644 index 00000000..1bc3e558 --- /dev/null +++ b/Controllers/RoccatController/RGBController_RoccatBurstCore.cpp @@ -0,0 +1,181 @@ +/*-----------------------------------------*\ +| RGBController_RoccatBurstCore.cpp | +| | +| Generic RGB Interface for OpenRGB | +| | +| | +| Morgan Guimard (morg) 6/01/2022 | +\*-----------------------------------------*/ + +#include "RGBController_RoccatBurstCore.h" + +/**------------------------------------------------------------------*\ + @name Roccat Burst Core + @category Mouse + @type USB + @save :warning: + @direct :white_check_mark: + @effects :white_check_mark: + @detectors DetectRoccatBurstCoreControllers + @comment +\*-------------------------------------------------------------------*/ + +RGBController_RoccatBurstCore::RGBController_RoccatBurstCore(RoccatBurstCoreController* controller_ptr) +{ + controller = controller_ptr; + + name = "Roccat Burst Core"; + vendor = "Roccat"; + type = DEVICE_TYPE_MOUSE; + description = "Roccat Burst Core Mouse"; + + mode Direct; + Direct.name = "Direct"; + Direct.value = ROCCAT_BURST_CORE_DIRECT_MODE_VALUE; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + mode Static; + Static.name = "Static"; + Static.value = ROCCAT_BURST_CORE_STATIC_MODE_VALUE; + Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS; + Static.color_mode = MODE_COLORS_MODE_SPECIFIC; + Static.brightness = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Static.brightness_min = ROCCAT_BURST_CORE_BRIGHTNESS_MIN; + Static.brightness_max = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Static.colors.resize(1); + modes.push_back(Static); + + mode Rainbow; + Rainbow.name = "Rainbow"; + Rainbow.value = ROCCAT_BURST_CORE_WAVE_MODE_VALUE; + Rainbow.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Rainbow.color_mode = MODE_COLORS_NONE; + Rainbow.brightness = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Rainbow.brightness_min = ROCCAT_BURST_CORE_BRIGHTNESS_MIN; + Rainbow.brightness_max = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Rainbow.speed = ROCCAT_BURST_CORE_SPEED_MIN; + Rainbow.speed_min = ROCCAT_BURST_CORE_SPEED_MIN; + Rainbow.speed_max = ROCCAT_BURST_CORE_SPEED_MAX; + modes.push_back(Rainbow); + + mode HeartBeat; + HeartBeat.name = "HeartBeat"; + HeartBeat.value = ROCCAT_BURST_CORE_HEARTBEAT_MODE_VALUE; + HeartBeat.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + HeartBeat.color_mode = MODE_COLORS_MODE_SPECIFIC; + HeartBeat.brightness = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + HeartBeat.brightness_min = ROCCAT_BURST_CORE_BRIGHTNESS_MIN; + HeartBeat.brightness_max = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + HeartBeat.speed = ROCCAT_BURST_CORE_SPEED_MIN; + HeartBeat.speed_min = ROCCAT_BURST_CORE_SPEED_MIN; + HeartBeat.speed_max = ROCCAT_BURST_CORE_SPEED_MAX; + HeartBeat.colors.resize(1); + modes.push_back(HeartBeat); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = ROCCAT_BURST_CORE_BREATHING_MODE_VALUE; + Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Breathing.brightness = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Breathing.brightness_min = ROCCAT_BURST_CORE_BRIGHTNESS_MIN; + Breathing.brightness_max = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Breathing.speed = ROCCAT_BURST_CORE_SPEED_MIN; + Breathing.speed_min = ROCCAT_BURST_CORE_SPEED_MIN; + Breathing.speed_max = ROCCAT_BURST_CORE_SPEED_MAX; + Breathing.colors.resize(1); + modes.push_back(Breathing); + + mode Blinking; + Blinking.name = "Blinking"; + Blinking.value = ROCCAT_BURST_CORE_BLINKING_MODE_VALUE; + Blinking.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Blinking.color_mode = MODE_COLORS_MODE_SPECIFIC; + Blinking.brightness = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Blinking.brightness_min = ROCCAT_BURST_CORE_BRIGHTNESS_MIN; + Blinking.brightness_max = ROCCAT_BURST_CORE_BRIGHTNESS_MAX; + Blinking.speed = ROCCAT_BURST_CORE_SPEED_MIN; + Blinking.speed_min = ROCCAT_BURST_CORE_SPEED_MIN; + Blinking.speed_max = ROCCAT_BURST_CORE_SPEED_MAX; + Blinking.colors.resize(1); + modes.push_back(Blinking); + + SetupZones(); +} + +RGBController_RoccatBurstCore::~RGBController_RoccatBurstCore() +{ + delete controller; +} + +void RGBController_RoccatBurstCore::SetupZones() +{ + zone new_zone; + new_zone.name = "Scroll wheel"; + new_zone.type = ZONE_TYPE_LINEAR; + new_zone.leds_min = ROCCAT_BURST_CORE_NUMBER_OF_LEDS; + new_zone.leds_max = ROCCAT_BURST_CORE_NUMBER_OF_LEDS; + new_zone.leds_count = ROCCAT_BURST_CORE_NUMBER_OF_LEDS; + new_zone.matrix_map = NULL; + zones.push_back(new_zone); + + for(unsigned int i = 0; i < ROCCAT_BURST_CORE_NUMBER_OF_LEDS; i++) + { + led new_led; + new_led.name = "LED " + std::to_string(i + 1); + leds.push_back(new_led); + } + + SetupColors(); +} + +void RGBController_RoccatBurstCore::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_RoccatBurstCore::DeviceUpdateLEDs() +{ + UpdateZoneLEDs(0); +} + +void RGBController_RoccatBurstCore::UpdateZoneLEDs(int /*zone_idx*/) +{ + const mode& active = modes[active_mode]; + + if(active.value == ROCCAT_BURST_CORE_DIRECT_MODE_VALUE) + { + controller->SendDirect(colors); + } + else + { + controller->SetMode(active.colors, active.value, active.speed, active.brightness, active.color_mode, active.flags); + } + +} + +void RGBController_RoccatBurstCore::UpdateSingleLED(int /*led_idx*/) +{ + UpdateZoneLEDs(0); +} + +void RGBController_RoccatBurstCore::SetCustomMode() +{ + active_mode = 0; +} + +void RGBController_RoccatBurstCore::DeviceUpdateMode() +{ + if(modes[active_mode].value == ROCCAT_BURST_CORE_DIRECT_MODE_VALUE) + { + controller->SetupDirectMode(); + } + else + { + DeviceUpdateLEDs(); + } +} diff --git a/Controllers/RoccatController/RGBController_RoccatBurstCore.h b/Controllers/RoccatController/RGBController_RoccatBurstCore.h new file mode 100644 index 00000000..20656c22 --- /dev/null +++ b/Controllers/RoccatController/RGBController_RoccatBurstCore.h @@ -0,0 +1,30 @@ +/*-----------------------------------------*\ +| RGBController_RoccatBurstCore.h | +| | +| Generic RGB Interface for Roccat Burst | +| Core Mouse controller | +| | +| Morgan Guimard (morg) 6/01/2022 | +\*-----------------------------------------*/ + +#pragma once +#include "RGBController.h" +#include "RoccatBurstCoreController.h" + +class RGBController_RoccatBurstCore : public RGBController +{ +public: + RGBController_RoccatBurstCore(RoccatBurstCoreController* controller_ptr); + ~RGBController_RoccatBurstCore(); + + void SetupZones(); + void ResizeZone(int zone, int new_size); + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + void SetCustomMode(); + void DeviceUpdateMode(); + +private: + RoccatBurstCoreController* controller; +}; diff --git a/Controllers/RoccatController/RoccatBurstCoreController.cpp b/Controllers/RoccatController/RoccatBurstCoreController.cpp new file mode 100644 index 00000000..1e3cbe87 --- /dev/null +++ b/Controllers/RoccatController/RoccatBurstCoreController.cpp @@ -0,0 +1,160 @@ +/*-------------------------------------------------------------------*\ +| RoccatBurstCoreController.cpp | +| | +| Driver for Roccat Horde Aimo Keyboard | +| | +| Morgan Guimard (morg) 2/24/2022 | +| | +\*-------------------------------------------------------------------*/ + +#include "RoccatBurstCoreController.h" + +#include + +RoccatBurstCoreController::RoccatBurstCoreController(hid_device* dev_handle, const hid_device_info& info) +{ + dev = dev_handle; + version = ""; + location = info.path; + + wchar_t serial_string[128]; + int ret = hid_get_serial_number_string(dev, serial_string, 128); + + if(ret != 0) + { + serial_number = ""; + } + else + { + std::wstring return_wstring = serial_string; + serial_number = std::string(return_wstring.begin(), return_wstring.end()); + } + + SetupDirectMode(); +} + +RoccatBurstCoreController::~RoccatBurstCoreController() +{ + hid_close(dev); +} + +std::string RoccatBurstCoreController::GetFirmwareVersion() +{ + return version; +} + +std::string RoccatBurstCoreController::GetSerialString() +{ + return serial_number; +} + +std::string RoccatBurstCoreController::GetDeviceLocation() +{ + return("HID: " + location); +} + +void RoccatBurstCoreController::SetupDirectMode() +{ + SwitchControl(true); +} + +void RoccatBurstCoreController::SwitchControl(bool direct) +{ + unsigned char usb_buf[ROCCAT_BURST_CORE_CONTROL_MODE_PACKET_LENGTH]; + + usb_buf[0x00] = 0x0E; + usb_buf[0x01] = 0x06; + usb_buf[0x02] = 0x01; + usb_buf[0x03] = direct ? 0x01 : 0x00; + usb_buf[0x04] = 0x00; + usb_buf[0x05] = 0xFF; + + hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_CORE_CONTROL_MODE_PACKET_LENGTH); +} + +void RoccatBurstCoreController::SendDirect(std::vector colors) +{ + unsigned char usb_buf[ROCCAT_BURST_CORE_DIRECT_MODE_PACKET_LENGTH]; + + memset(usb_buf, 0x00, ROCCAT_BURST_CORE_DIRECT_MODE_PACKET_LENGTH); + + usb_buf[0x00] = ROCCAT_BURST_CORE_DIRECT_MODE_REPORT_ID; + usb_buf[0x01] = ROCCAT_BURST_CORE_DIRECT_MODE_BYTE; + + usb_buf[0x02] = RGBGetRValue(colors[0]); + usb_buf[0x03] = RGBGetGValue(colors[0]); + usb_buf[0x04] = RGBGetBValue(colors[0]); + + hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_CORE_DIRECT_MODE_PACKET_LENGTH); +} + +void RoccatBurstCoreController::SetMode(std::vector colors, unsigned char mode_value, unsigned char speed, unsigned char brightness, unsigned int color_mode, unsigned int mode_flags) +{ + /*---------------------------------------------------------*\ + | 1. Read from flash | + \*---------------------------------------------------------*/ + unsigned char usb_buf[ROCCAT_BURST_CORE_FLASH_PACKET_LENGTH]; + memset(usb_buf, 0x00, ROCCAT_BURST_CORE_FLASH_PACKET_LENGTH); + + usb_buf[0x00] = 0x06; + + hid_get_feature_report(dev, usb_buf, ROCCAT_BURST_CORE_FLASH_PACKET_LENGTH); + + /*---------------------------------------------------------*\ + | 2. Update needed bytes | + \*---------------------------------------------------------*/ + usb_buf[0x01] = 0x3F; + usb_buf[0x03] = 0x06; + usb_buf[0x04] = 0x06; + usb_buf[0x05] = 0x1F; + + usb_buf[30] = mode_value; + usb_buf[31] = mode_flags & MODE_FLAG_HAS_SPEED ? speed : 0xFF; + usb_buf[32] = brightness; + + usb_buf[34] = 0xFF; + + if(color_mode & MODE_COLORS_MODE_SPECIFIC) + { + usb_buf[36] = 0x14; + usb_buf[37] = 0xFF; + usb_buf[38] = RGBGetRValue(colors[0]); + usb_buf[39] = RGBGetGValue(colors[0]); + usb_buf[40] = RGBGetBValue(colors[0]); + } + else if (color_mode & MODE_COLORS_NONE) + { + usb_buf[38] = 0xF4; + usb_buf[39] = 0x00; + usb_buf[40] = 0x00; + } + + unsigned int crc = CalculateCRC(&usb_buf[0]); + + usb_buf[61] = (unsigned char) crc; + usb_buf[62] = crc >> 8; + + /*---------------------------------------------------------*\ + | 3. Send to flash | + \*---------------------------------------------------------*/ + hid_send_feature_report(dev, usb_buf, ROCCAT_BURST_CORE_FLASH_PACKET_LENGTH); + + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + + /*---------------------------------------------------------*\ + | 4. Switch to built-in mode | + \*---------------------------------------------------------*/ + SwitchControl(false); +} + +unsigned int RoccatBurstCoreController::CalculateCRC(unsigned char* bytes) +{ + unsigned int crc = 0; + + for(unsigned int i = 0; i < ROCCAT_BURST_CORE_FLASH_PACKET_LENGTH - 2; i++) + { + crc += bytes[i]; + } + + return crc; +} diff --git a/Controllers/RoccatController/RoccatBurstCoreController.h b/Controllers/RoccatController/RoccatBurstCoreController.h new file mode 100644 index 00000000..20c5ff45 --- /dev/null +++ b/Controllers/RoccatController/RoccatBurstCoreController.h @@ -0,0 +1,67 @@ +/*-------------------------------------------------------------------*\ +| RoccatBurstCoreController.h | +| | +| Driver for Roccat Burst Core Mouse | +| | +| Morgan Guimard (morg) 6/01/2022 | +\*-------------------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include + +#define ROCCAT_BURST_CORE_CONTROL_MODE_PACKET_LENGTH 6 +#define ROCCAT_BURST_CORE_DIRECT_MODE_PACKET_LENGTH 11 +#define ROCCAT_BURST_CORE_FLASH_PACKET_LENGTH 63 +#define ROCCAT_BURST_CORE_FLASH_REPORT_ID 0x06 +#define ROCCAT_BURST_CORE_DIRECT_MODE_REPORT_ID 0x0D +#define ROCCAT_BURST_CORE_DIRECT_MODE_BYTE 0x0B +#define ROCCAT_BURST_CORE_NUMBER_OF_LEDS 1 + +enum +{ + ROCCAT_BURST_CORE_DIRECT_MODE_VALUE = 0x00, + ROCCAT_BURST_CORE_STATIC_MODE_VALUE = 0x01, + ROCCAT_BURST_CORE_WAVE_MODE_VALUE = 0x0A, + ROCCAT_BURST_CORE_HEARTBEAT_MODE_VALUE = 0x04, + ROCCAT_BURST_CORE_BREATHING_MODE_VALUE = 0x03, + ROCCAT_BURST_CORE_BLINKING_MODE_VALUE = 0x02 +}; + +enum +{ + ROCCAT_BURST_CORE_SPEED_MIN = 0x01, + ROCCAT_BURST_CORE_SPEED_MAX = 0x0B, + ROCCAT_BURST_CORE_BRIGHTNESS_MIN = 0x00, + ROCCAT_BURST_CORE_BRIGHTNESS_MAX = 0xFF +}; + +class RoccatBurstCoreController +{ +public: + RoccatBurstCoreController(hid_device* dev_handle, const hid_device_info& info); + ~RoccatBurstCoreController(); + + std::string GetSerialString(); + std::string GetDeviceLocation(); + std::string GetFirmwareVersion(); + + void SetupDirectMode(); + void SendDirect(std::vector colors); + void SetMode(std::vector colors, + unsigned char mode_value, + unsigned char speed, + unsigned char brightness, + unsigned int color_mode, + unsigned int mode_flags + ); +private: + hid_device* dev; + std::string location; + std::string serial_number; + std::string version; + + unsigned int CalculateCRC(unsigned char* bytes); + void SwitchControl(bool direct); +}; diff --git a/Controllers/RoccatController/RoccatControllerDetect.cpp b/Controllers/RoccatController/RoccatControllerDetect.cpp index c5e4b7d7..82b9c1f3 100644 --- a/Controllers/RoccatController/RoccatControllerDetect.cpp +++ b/Controllers/RoccatController/RoccatControllerDetect.cpp @@ -7,9 +7,11 @@ \******************************************************************************************/ #include "Detector.h" +#include "RoccatBurstCoreController.h" #include "RoccatKoneAimoController.h" #include "RoccatVulcanAimoController.h" #include "RGBController.h" +#include "RGBController_RoccatBurstCore.h" #include "RGBController_RoccatHordeAimo.h" #include "RGBController_RoccatKoneAimo.h" #include "RGBController_RoccatVulcanAimo.h" @@ -22,6 +24,7 @@ #define ROCCAT_KONE_AIMO_16K_PID 0x2E2C #define ROCCAT_VULCAN_120_AIMO_PID 0x3098 #define ROCCAT_HORDE_AIMO_PID 0x303E +#define ROCCAT_BURST_CORE_PID 0x2DE6 void DetectRoccatMouseControllers(hid_device_info* info, const std::string& name) { @@ -127,8 +130,22 @@ void DetectRoccatHordeAimoKeyboardControllers(hid_device_info* info, const std:: } } +void DetectRoccatBurstCoreControllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + RoccatBurstCoreController * controller = new RoccatBurstCoreController(dev, *info); + RGBController_RoccatBurstCore * rgb_controller = new RGBController_RoccatBurstCore(controller); + rgb_controller->name = name; + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + REGISTER_HID_DETECTOR_IPU("Roccat Kone Aimo", DetectRoccatMouseControllers, ROCCAT_VID, ROCCAT_KONE_AIMO_PID, 0, 0x0B, 0 ); REGISTER_HID_DETECTOR_IPU("Roccat Kone Aimo 16K", DetectRoccatMouseControllers, ROCCAT_VID, ROCCAT_KONE_AIMO_16K_PID, 0, 0x0B, 0 ); REGISTER_HID_DETECTOR_IP ("Roccat Vulcan 120 Aimo", DetectRoccatKeyboardControllers, ROCCAT_VID, ROCCAT_VULCAN_120_AIMO_PID, 1, 11); REGISTER_DYNAMIC_DETECTOR("Roccat Vulcan 120 Aimo Setup", ResetRoccatKeyboardControllersPaths); 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); diff --git a/OpenRGB.pro b/OpenRGB.pro index b6e6b97e..5d19d552 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -490,9 +490,11 @@ HEADERS += Controllers/RazerController/RGBController_RazerKraken.h \ Controllers/RedragonController/RedragonM711Controller.h \ Controllers/RedragonController/RGBController_RedragonM711.h \ + Controllers/RoccatController/RGBController_RoccatBurstCore.h \ Controllers/RoccatController/RGBController_RoccatHordeAimo.h \ Controllers/RoccatController/RGBController_RoccatKoneAimo.h \ Controllers/RoccatController/RGBController_RoccatVulcanAimo.h \ + Controllers/RoccatController/RoccatBurstCoreController.h \ Controllers/RoccatController/RoccatHordeAimoController.h \ Controllers/RoccatController/RoccatKoneAimoController.h \ Controllers/RoccatController/RoccatVulcanAimoController.h \ @@ -996,9 +998,11 @@ SOURCES += Controllers/RedragonController/RedragonM711Controller.cpp \ Controllers/RedragonController/RedragonControllerDetect.cpp \ Controllers/RedragonController/RGBController_RedragonM711.cpp \ + Controllers/RoccatController/RGBController_RoccatBurstCore.cpp \ Controllers/RoccatController/RGBController_RoccatHordeAimo.cpp \ Controllers/RoccatController/RGBController_RoccatKoneAimo.cpp \ Controllers/RoccatController/RGBController_RoccatVulcanAimo.cpp \ + Controllers/RoccatController/RoccatBurstCoreController.cpp \ Controllers/RoccatController/RoccatHordeAimoController.cpp \ Controllers/RoccatController/RoccatKoneAimoController.cpp \ Controllers/RoccatController/RoccatVulcanAimoController.cpp \