From d99be3e0e66bda519653b1226d471a4901d87586 Mon Sep 17 00:00:00 2001 From: morg Date: Tue, 30 Sep 2025 12:20:39 +0200 Subject: [PATCH] Add support for QuadCast 2S. Closes #5113 --- .../HyperXMicrophoneV2Controller.cpp | 88 +++++++++++ .../HyperXMicrophoneV2Controller.h | 42 +++++ .../HyperXMicrophoneV2ControllerDetect.cpp | 35 +++++ .../RGBController_HyperXMicrophoneV2.cpp | 145 ++++++++++++++++++ .../RGBController_HyperXMicrophoneV2.h | 42 +++++ 5 files changed, 352 insertions(+) create mode 100644 Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp create mode 100644 Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.h create mode 100644 Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2ControllerDetect.cpp create mode 100644 Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.cpp create mode 100644 Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.h diff --git a/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp new file mode 100644 index 000000000..7d5f7756d --- /dev/null +++ b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.cpp @@ -0,0 +1,88 @@ +/*---------------------------------------------------------*\ +| HyperXMicrophoneV2Controller.cpp | +| | +| Driver for HyperX QuadCast 2S microphone | +| | +| Morgan Guimard (morg) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "HyperXMicrophoneV2Controller.h" +#include "StringUtils.h" + +using namespace std::chrono_literals; + +HyperXMicrophoneV2Controller::HyperXMicrophoneV2Controller(hid_device* dev_handle, std::string path, std::string dev_name) +{ + dev = dev_handle; + location = path; + name = dev_name; +} + +HyperXMicrophoneV2Controller::~HyperXMicrophoneV2Controller() +{ + if(dev) + { + hid_close(dev); + } +} + +std::string HyperXMicrophoneV2Controller::GetDeviceLocation() +{ + return(location); +} + +std::string HyperXMicrophoneV2Controller::GetNameString() +{ + return(name); +} + +std::string HyperXMicrophoneV2Controller::GetSerialString() +{ + wchar_t serial_string[128]; + int ret = hid_get_serial_number_string(dev, serial_string, 128); + + if(ret != 0) + { + return(""); + } + + return(StringUtils::wstring_to_string(serial_string)); +} + +void HyperXMicrophoneV2Controller::SendDirect(std::vector colors) +{ + lock.lock(); + + uint8_t buf[HYPERX_QUADCAST_2S_PACKET_SIZE]; + + unsigned int total_leds_sent = 0; + + for(unsigned int i = 0; i < 7; i++) + { + memset(buf, 0, HYPERX_QUADCAST_2S_PACKET_SIZE); + + buf[0] = HYPERX_QUADCAST_2S_REPORT_ID; + buf[1] = i < 6 ? 0x02 : 0x01; + buf[2] = i; + + unsigned int c = 0; + + while (c < HYPERX_QUADCAST_2S_LEDS_PER_PACKET && total_leds_sent < HYPERX_QUADCAST_2S_TOTAL_LEDS) + { + buf[4 + (3 * c)] = RGBGetRValue(colors[total_leds_sent]); + buf[5 + (3 * c)] = RGBGetGValue(colors[total_leds_sent]); + buf[6 + (3 * c)] = RGBGetBValue(colors[total_leds_sent]); + + c++; + total_leds_sent++; + } + + hid_write(dev, buf, HYPERX_QUADCAST_2S_PACKET_SIZE); + } + + lock.unlock(); +} diff --git a/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.h b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.h new file mode 100644 index 000000000..e65ddfb53 --- /dev/null +++ b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2Controller.h @@ -0,0 +1,42 @@ +/*---------------------------------------------------------*\ +| HyperXMicrophoneV2Controller.cpp | +| | +| Driver for HyperX QuadCast 2S microphone | +| | +| Morgan Guimard (morg) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include "RGBController.h" + +#define HYPERX_QUADCAST_2S_PACKET_SIZE 64 +#define HYPERX_QUADCAST_2S_REPORT_ID 0x44 +#define HYPERX_QUADCAST_2S_LEDS_PER_PACKET 20 +#define HYPERX_QUADCAST_2S_MATRIX_WIDTH 12 +#define HYPERX_QUADCAST_2S_MATRIX_HEIGHT 9 +#define HYPERX_QUADCAST_2S_TOTAL_LEDS 108 + +class HyperXMicrophoneV2Controller +{ +public: + HyperXMicrophoneV2Controller(hid_device* dev, std::string path, std::string dev_name); + ~HyperXMicrophoneV2Controller(); + + std::string GetDeviceLocation(); + std::string GetNameString(); + std::string GetSerialString(); + + void SendDirect(std::vector color_data); + +private: + hid_device* dev; + std::string location; + std::string name; + std::mutex lock; +}; diff --git a/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2ControllerDetect.cpp b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2ControllerDetect.cpp new file mode 100644 index 000000000..440625c8a --- /dev/null +++ b/Controllers/HyperXMicrophoneV2Controller/HyperXMicrophoneV2ControllerDetect.cpp @@ -0,0 +1,35 @@ +/*---------------------------------------------------------*\ +| HyperXMicrophoneV2ControllerDetect.cpp | +| | +| Detector for HyperX QuadCast 2s microphone | +| | +| Morgan Guimard (morg) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "Detector.h" +#include "HyperXMicrophoneV2Controller.h" +#include "RGBController_HyperXMicrophoneV2.h" + +/*-----------------------------------------------------*\ +| HyperX microphone vendor and product IDs | +\*-----------------------------------------------------*/ +#define HYPERX_HP_VID 0x03F0 +#define HYPERX_QUADCAST_2S_PID 0x02B5 + +void DetectHyperXMicrophoneV2Controllers(hid_device_info* info, const std::string& name) +{ + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + HyperXMicrophoneV2Controller* controller = new HyperXMicrophoneV2Controller(dev, info->path, name); + RGBController_HyperXMicrophoneV2 *rgb_controller = new RGBController_HyperXMicrophoneV2(controller); + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + +REGISTER_HID_DETECTOR_IPU("HyperX QuadCast 2S", DetectHyperXMicrophoneV2Controllers, HYPERX_HP_VID, HYPERX_QUADCAST_2S_PID, 1, 0xFF13, 0xFF00); diff --git a/Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.cpp b/Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.cpp new file mode 100644 index 000000000..971d524c6 --- /dev/null +++ b/Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.cpp @@ -0,0 +1,145 @@ +/*---------------------------------------------------------*\ +| RGBController_HyperXMicrophoneV2.cpp | +| | +| RGBController for HyperX QuadCast 2S microphone | +| | +| Morgan Guimard (morg) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +/**------------------------------------------------------------------*\ + @name HyperX Quadcast 2S + @type USB + @save :x: + @direct :white_check_mark: + @effects :x: + @detectors DetectHyperXMicrophoneV2Controllers + @comment +\*-------------------------------------------------------------------*/ + +#include "RGBController_HyperXMicrophoneV2.h" +#include + +using namespace std::chrono_literals; + +RGBController_HyperXMicrophoneV2::RGBController_HyperXMicrophoneV2(HyperXMicrophoneV2Controller* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetNameString(); + vendor = "HyperX"; + type = DEVICE_TYPE_MICROPHONE; + description = "HyperX Microphone Device"; + location = controller->GetDeviceLocation(); + serial = controller->GetSerialString(); + + mode Direct; + Direct.name = "Direct"; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + Direct.colors_min = HYPERX_QUADCAST_2S_TOTAL_LEDS; + Direct.colors_max = HYPERX_QUADCAST_2S_TOTAL_LEDS; + + modes.push_back(Direct); + + SetupZones(); + + keepalive_thread_run = 1; + keepalive_thread = new std::thread(&RGBController_HyperXMicrophoneV2::KeepaliveThread, this); +}; + +RGBController_HyperXMicrophoneV2::~RGBController_HyperXMicrophoneV2() +{ + keepalive_thread_run = 0; + keepalive_thread->join(); + delete keepalive_thread; + + delete controller; +} + +void RGBController_HyperXMicrophoneV2::SetupZones() +{ + zone Mic; + + Mic.name = "Microphone"; + Mic.type = ZONE_TYPE_MATRIX; + Mic.leds_min = HYPERX_QUADCAST_2S_TOTAL_LEDS; + Mic.leds_max = HYPERX_QUADCAST_2S_TOTAL_LEDS; + Mic.leds_count = HYPERX_QUADCAST_2S_TOTAL_LEDS; + Mic.matrix_map = new matrix_map_type; + Mic.matrix_map->width = HYPERX_QUADCAST_2S_MATRIX_WIDTH; + Mic.matrix_map->height = HYPERX_QUADCAST_2S_MATRIX_HEIGHT; + Mic.matrix_map->map = new unsigned int[HYPERX_QUADCAST_2S_TOTAL_LEDS]; + + unsigned int led_mapping[HYPERX_QUADCAST_2S_TOTAL_LEDS] = + { + /* front */ /* rear */ + 26, 27, 44, 45, 62, 63, 80, 81, 98, 99, 8, 9, + 25, 28, 43, 46, 61, 64, 79, 82, 97, 100, 7, 10, + 24, 29, 42, 47, 60, 65, 78, 83, 96, 101, 6, 11, + 23, 30, 41, 48, 59, 66, 77, 84, 95, 102, 5, 12, + 22, 31, 40, 49, 58, 67, 76, 85, 94, 103, 4, 13, + 21, 32, 39, 50, 57, 68, 75, 86, 93, 104, 3, 14, + 20, 33, 38, 51, 56, 69, 74, 87, 92, 105, 2, 15, + 19, 34, 37, 52, 55, 70, 73, 88, 91, 106, 1, 16, + 18, 35, 36, 53, 54, 71, 72, 89, 90, 107, 0, 17 + }; + + for(unsigned int i = 0; i < HYPERX_QUADCAST_2S_TOTAL_LEDS; i ++) + { + led l; + l.name = "LED " + std::to_string(i); + l.value = led_mapping[i]; + leds.push_back(l); + + Mic.matrix_map->map[i] = led_mapping[i]; + } + + zones.push_back(Mic); + + SetupColors(); +} + +void RGBController_HyperXMicrophoneV2::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_HyperXMicrophoneV2::DeviceUpdateLEDs() +{ + last_update_time = std::chrono::steady_clock::now(); + controller->SendDirect(colors); +} +void RGBController_HyperXMicrophoneV2::UpdateZoneLEDs(int /*zone*/) +{ + DeviceUpdateLEDs(); +} +void RGBController_HyperXMicrophoneV2::UpdateSingleLED(int /*led*/) +{ + DeviceUpdateLEDs(); +} +void RGBController_HyperXMicrophoneV2::DeviceUpdateMode() +{ + DeviceUpdateLEDs(); +} + +void RGBController_HyperXMicrophoneV2::DeviceSaveMode() +{ + /* Unsuported */ +} + +void RGBController_HyperXMicrophoneV2::KeepaliveThread() +{ + while(keepalive_thread_run.load()) + { + if((std::chrono::steady_clock::now() - last_update_time) > std::chrono::milliseconds(50)) + { + UpdateLEDs(); + } + std::this_thread::sleep_for(15ms); + } +} diff --git a/Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.h b/Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.h new file mode 100644 index 000000000..954aad035 --- /dev/null +++ b/Controllers/HyperXMicrophoneV2Controller/RGBController_HyperXMicrophoneV2.h @@ -0,0 +1,42 @@ +/*---------------------------------------------------------*\ +| RGBController_HyperXMicrophoneV2.h | +| | +| RGBController for HyperX QuadCast 2S microphone | +| | +| Morgan Guimard (morg) | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "RGBController.h" +#include "HyperXMicrophoneV2Controller.h" + +class RGBController_HyperXMicrophoneV2 : public RGBController +{ +public: + RGBController_HyperXMicrophoneV2(HyperXMicrophoneV2Controller* controller_ptr); + ~RGBController_HyperXMicrophoneV2(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + void DeviceSaveMode(); + + void KeepaliveThread(); + +private: + HyperXMicrophoneV2Controller* controller; + std::thread* keepalive_thread; + std::atomic keepalive_thread_run; + std::chrono::time_point last_update_time; +};