diff --git a/Controllers/RealtekBridgeController/RGBController_RealtekBridge.cpp b/Controllers/RealtekBridgeController/RGBController_RealtekBridge.cpp new file mode 100644 index 000000000..b9bf41732 --- /dev/null +++ b/Controllers/RealtekBridgeController/RGBController_RealtekBridge.cpp @@ -0,0 +1,303 @@ +/*---------------------------------------------------------*\ +| RGBController_RealtekBridge.cpp | +| | +| Controller for Realtek USB to SSD Bridge ICs | +| | +| Jerry Fan (JerryFan0612) 13 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "RGBController_RealtekBridge.h" + +/**------------------------------------------------------------------*\ + @name Realtek Bridge Device + @category Storage + @type USB + @save :x: + @direct :rotating_light: + @effects :white_check_mark: + @detectors RealtekBridgeControllerDetect + @comment +\*-------------------------------------------------------------------*/ + +RGBController_RealtekBridge::RGBController_RealtekBridge(RealtekBridgeController* controller_ptr) +{ + controller = controller_ptr; + name = controller_ptr->get_product_name(); + vendor = controller_ptr->get_manu_name(); + location = controller_ptr->get_dev_loc(); + serial = controller_ptr->get_sn(); + version = controller_ptr->get_fw_ver(); + description = vendor + "Storage Device"; + type = DEVICE_TYPE_STORAGE; + + SetupModes(); + SetupZones(); +} + +RGBController_RealtekBridge::~RGBController_RealtekBridge() +{ + delete controller; +} + +void RGBController_RealtekBridge::SetupModes() +{ + int brightness = controller->get_argb_brightness() >> 8; + + mode Direct; + Direct.name = "Direct"; + Direct.value = REALTEK_BRIDGE_LED_EFF_NONE; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS; + Direct.color_mode = MODE_COLORS_PER_LED; + Direct.brightness_min = 0; + Direct.brightness_max = 255; + Direct.brightness = brightness; + modes.push_back(Direct); + + mode Static; + Static.name = "Static"; + Static.value = REALTEK_BRIDGE_LED_EFF_ALWAYS; + Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS; + Static.colors_min = 1; + Static.colors_max = 1; + Static.color_mode = MODE_COLORS_MODE_SPECIFIC; + Static.colors.resize(1); + Static.brightness_min = 0; + Static.brightness_max = 255; + Static.brightness = brightness; + modes.push_back(Static); + + mode Blink; + Blink.name = "Blink"; + Blink.value = REALTEK_BRIDGE_LED_EFF_BLINK; + Blink.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Blink.speed_min = REALTEK_BRIDGE_SPEED_MIN; + Blink.speed_max = REALTEK_BRIDGE_SPEED_MAX; + Blink.speed = REALTEK_BRIDGE_SPEED_NORMAL; + Blink.colors_min = 1; + Blink.colors_max = 1; + Blink.color_mode = MODE_COLORS_MODE_SPECIFIC; + Blink.colors.resize(1); + Blink.brightness_min = 0; + Blink.brightness_max = 255; + Blink.brightness = brightness; + modes.push_back(Blink); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = REALTEK_BRIDGE_LED_EFF_BREATHE; + Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Breathing.speed_min = REALTEK_BRIDGE_SPEED_MIN; + Breathing.speed_max = REALTEK_BRIDGE_SPEED_MAX; + Breathing.speed = REALTEK_BRIDGE_SPEED_NORMAL; + Breathing.colors_min = 1; + Breathing.colors_max = 1; + Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC; + Breathing.colors.resize(1); + Breathing.brightness_min = 0; + Breathing.brightness_max = 255; + Breathing.brightness = brightness; + modes.push_back(Breathing); + + mode Spectrum; + Spectrum.name = "Spectrum"; + Spectrum.value = REALTEK_BRIDGE_LED_EFF_SPECTRUM; + Spectrum.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Spectrum.speed_min = REALTEK_BRIDGE_SPEED_MIN; + Spectrum.speed_max = REALTEK_BRIDGE_SPEED_MAX; + Spectrum.speed = REALTEK_BRIDGE_SPEED_NORMAL; + Spectrum.color_mode = MODE_COLORS_NONE; + Spectrum.brightness_min = 0; + Spectrum.brightness_max = 255; + Spectrum.brightness = brightness; + modes.push_back(Spectrum); + + mode Scroll; + Scroll.name = "Scroll"; + Scroll.value = REALTEK_BRIDGE_LED_EFF_SCROLL; + Scroll.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Scroll.speed_min = REALTEK_BRIDGE_SPEED_MIN; + Scroll.speed_max = REALTEK_BRIDGE_SPEED_MAX; + Scroll.speed = REALTEK_BRIDGE_SPEED_NORMAL; + Scroll.colors_min = 1; + Scroll.colors_max = 1; + Scroll.color_mode = MODE_COLORS_MODE_SPECIFIC; + Scroll.colors.resize(1); + Scroll.brightness_min = 0; + Scroll.brightness_max = 255; + Scroll.brightness = brightness; + modes.push_back(Scroll); + + mode RainbowScroll; + RainbowScroll.name = "Rainbow Scroll"; + RainbowScroll.value = REALTEK_BRIDGE_LED_EFF_RAINBOW_SCROLL; + RainbowScroll.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + RainbowScroll.speed_min = REALTEK_BRIDGE_SPEED_MIN; + RainbowScroll.speed_max = REALTEK_BRIDGE_SPEED_MAX; + RainbowScroll.speed = REALTEK_BRIDGE_SPEED_NORMAL; + RainbowScroll.color_mode = MODE_COLORS_NONE; + RainbowScroll.brightness_min = 0; + RainbowScroll.brightness_max = 255; + RainbowScroll.brightness = brightness; + modes.push_back(RainbowScroll); + + mode RunningWater; + RunningWater.name = "Running Water"; + RunningWater.value = REALTEK_BRIDGE_LED_EFF_RUNNING_WATER; + RunningWater.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + RunningWater.speed_min = REALTEK_BRIDGE_SPEED_MIN; + RunningWater.speed_max = REALTEK_BRIDGE_SPEED_MAX; + RunningWater.speed = REALTEK_BRIDGE_SPEED_NORMAL; + RunningWater.colors_min = 1; + RunningWater.colors_max = 1; + RunningWater.color_mode = MODE_COLORS_MODE_SPECIFIC; + RunningWater.colors.resize(1); + RunningWater.brightness_min = 0; + RunningWater.brightness_max = 255; + RunningWater.brightness = brightness; + modes.push_back(RunningWater); + + mode Sliding; + Sliding.name = "Sliding"; + Sliding.value = REALTEK_BRIDGE_LED_EFF_SLIDING; + Sliding.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Sliding.speed_min = REALTEK_BRIDGE_SPEED_MIN; + Sliding.speed_max = REALTEK_BRIDGE_SPEED_MAX; + Sliding.speed = REALTEK_BRIDGE_SPEED_NORMAL; + Sliding.color_mode = MODE_COLORS_NONE; + Sliding.brightness_min = 0; + Sliding.brightness_max = 255; + Sliding.brightness = brightness; + modes.push_back(Sliding); + + mode NewtonCradle; + NewtonCradle.name = "Newton Cradle"; + NewtonCradle.value = REALTEK_BRIDGE_LED_EFF_NEWTON_CRADLE; + NewtonCradle.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + NewtonCradle.speed_min = REALTEK_BRIDGE_SPEED_MIN; + NewtonCradle.speed_max = REALTEK_BRIDGE_SPEED_MAX; + NewtonCradle.speed = REALTEK_BRIDGE_SPEED_NORMAL; + NewtonCradle.color_mode = MODE_COLORS_NONE; + NewtonCradle.brightness_min = 0; + NewtonCradle.brightness_max = 255; + NewtonCradle.brightness = brightness; + modes.push_back(NewtonCradle); + + mode Meteor; + Meteor.name = "Meteor"; + Meteor.value = REALTEK_BRIDGE_LED_EFF_METEOR; + Meteor.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED; + Meteor.speed_min = REALTEK_BRIDGE_SPEED_MIN; + Meteor.speed_max = REALTEK_BRIDGE_SPEED_MAX; + Meteor.speed = REALTEK_BRIDGE_SPEED_NORMAL; + Meteor.colors_min = 1; + Meteor.colors_max = 1; + Meteor.color_mode = MODE_COLORS_MODE_SPECIFIC; + Meteor.colors.resize(1); + Meteor.brightness_min = 0; + Meteor.brightness_max = 255; + Meteor.brightness = brightness; + modes.push_back(Meteor); +} + +void RGBController_RealtekBridge::SetupZones() +{ + zone argb_zone; + + argb_zone.name = "strip"; + argb_zone.type = ZONE_TYPE_LINEAR; + argb_zone.leds_min = controller->get_argb_num(); + argb_zone.leds_max = controller->get_argb_num(); + argb_zone.leds_count = controller->get_argb_num(); + argb_zone.matrix_map = NULL; + + zones.push_back(argb_zone); + + for(unsigned int led_idx = 0; led_idx < argb_zone.leds_count; led_idx++) + { + led StripLED; + StripLED.name = "led "; + StripLED.name.append(std::to_string(led_idx + 1)); + leds.push_back(StripLED); + } + + SetupColors(); +} + +void RGBController_RealtekBridge::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_RealtekBridge::DeviceUpdateLEDs() +{ + UpdateZoneLEDs(0); +} + +void RGBController_RealtekBridge::UpdateZoneLEDs(int /*zone*/) +{ + unsigned short brightness = 0xFF; + mode& curr_mode = modes[active_mode]; + + if(curr_mode.color_mode == MODE_COLORS_PER_LED && + curr_mode.value == REALTEK_BRIDGE_LED_EFF_NONE) //direct mode + { + if(curr_mode.flags & MODE_FLAG_HAS_BRIGHTNESS) + { + brightness = curr_mode.brightness; + } + controller->set_argb_direct(colors, brightness); + } + else + { + UpdateSingleLED(0); + } +} + +void RGBController_RealtekBridge::UpdateSingleLED(int /*led*/) +{ + unsigned char speed = REALTEK_BRIDGE_SPEED_NORMAL; + unsigned char dir = 0; + unsigned short brightness = 0xFF; + mode& curr_mode = modes[active_mode]; + std::vector rtk_colors = curr_mode.colors; + + if(curr_mode.flags & MODE_FLAG_HAS_SPEED) + { + speed = curr_mode.speed; + } + if(curr_mode.flags & MODE_FLAG_HAS_BRIGHTNESS) + { + brightness = curr_mode.brightness; + } + if(curr_mode.flags & MODE_FLAG_HAS_DIRECTION_LR) + { + if(curr_mode.direction == MODE_DIRECTION_RIGHT) + { + dir = 1; + } + } + + if(curr_mode.color_mode == MODE_COLORS_PER_LED) + { + rtk_colors = colors; + } + else if(curr_mode.color_mode == MODE_COLORS_NONE) + { + rtk_colors.clear(); + } + + controller->set_argb_effect(curr_mode.value, rtk_colors, speed, brightness); +} + +void RGBController_RealtekBridge::DeviceUpdateMode() +{ + if(modes[active_mode].value != REALTEK_BRIDGE_LED_EFF_NONE) + { + DeviceUpdateLEDs(); + } +} diff --git a/Controllers/RealtekBridgeController/RGBController_RealtekBridge.h b/Controllers/RealtekBridgeController/RGBController_RealtekBridge.h new file mode 100644 index 000000000..7ac73443f --- /dev/null +++ b/Controllers/RealtekBridgeController/RGBController_RealtekBridge.h @@ -0,0 +1,34 @@ +/*---------------------------------------------------------*\ +| RGBController_RealtekBridge.h | +| | +| Controller for Realtek USB to SSD Bridge ICs | +| | +| Jerry Fan (JerryFan0612) 13 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "RealtekBridgeController.h" + +class RGBController_RealtekBridge : public RGBController +{ +public: + RGBController_RealtekBridge(RealtekBridgeController* controller_ptr); + ~RGBController_RealtekBridge(); + + void SetupModes(); + + void SetupZones(); + void ResizeZone(int zone, int new_size); + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + void DeviceUpdateMode(); + +private: + RealtekBridgeController* controller; +}; diff --git a/Controllers/RealtekBridgeController/RealtekBridgeController.cpp b/Controllers/RealtekBridgeController/RealtekBridgeController.cpp new file mode 100644 index 000000000..16839f10b --- /dev/null +++ b/Controllers/RealtekBridgeController/RealtekBridgeController.cpp @@ -0,0 +1,802 @@ +/*---------------------------------------------------------*\ +| RealtekBridgeController.cpp | +| | +| Controller for Realtek USB to SSD Bridge ICs | +| | +| Jerry Fan (JerryFan0612) 13 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "RealtekBridgeController.h" +#include "hsv.h" +#include +#include + +static const unsigned char hid_set_packet[] = +{ + 0x56, 0x53, 0x42, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0xE3, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char hid_get_packet[] = +{ + 0x56, 0x53, 0x42, 0x43, 0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10, 0xE2, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; +static const unsigned char hid_end_packet[] = +{ + 0x58, 0x53, 0x42, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +RealtekBridgeController::RealtekBridgeController(hid_device* dev, hid_device_info* info) +{ + hdev = dev; + hidinfo = info; + brctl_data = (unsigned char*)calloc(REALTEK_BRIDGE_CTL_DATA_SIZE, 1); + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + + set_write_unlock(); + get_brctl_hdr(); + get_brctl_data(); + set_appctl(true); +} + +RealtekBridgeController::~RealtekBridgeController() +{ + if(hdev) + { + set_appctl(false); + hid_close(hdev); + hdev = NULL; + } + memset(brctl_hdr, 0, REALTEK_BRIDGE_CTL_HDR_SIZE); + free(brctl_data); +} + +int RealtekBridgeController::usb_hid_ioctl(unsigned char* usb_buf, unsigned char* data, int data_len, + unsigned int offset, unsigned char is_in) +{ + int id; + int ret = 0; + int buf_len = usb_hid_get_report(data_len, &id); + + if(!is_in && data_len) + { + usb_buf[0x04] = data[0]; + } + memcpy(&usb_buf[0x08], &data_len, sizeof(data_len)); + memcpy(&usb_buf[0x1B], &data_len, sizeof(data_len)); + ret = hid_send_feature_report(hdev, usb_buf, sizeof(hid_get_packet)); + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, data, data_len); + usb_buf[0x00] = id; + if(is_in) + { + ret = hid_get_feature_report(hdev, usb_buf, buf_len); + memcpy(data, usb_buf + offset, data_len); + } + else + { + ret = hid_send_feature_report(hdev, usb_buf, buf_len); + } + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_end_packet, sizeof(hid_end_packet)); + ret = hid_get_feature_report(hdev, usb_buf, sizeof(hid_end_packet)); + free(usb_buf); + return (ret > 0) ? 0 : ret; +} + +int RealtekBridgeController::usb_hid_get_report(int data_len, int* id) +{ + int retlen = 0; + + if(data_len <= REALTEK_BRIDGE_HID_DATALEN_CH2) + { + *id = REALTEK_BRIDGE_HID_ID_DATA_CH2; + retlen = REALTEK_BRIDGE_HID_DATALEN_CH2; + } + else if(data_len <= REALTEK_BRIDGE_HID_DATALEN_CH3) + { + *id = REALTEK_BRIDGE_HID_ID_DATA_CH3; + retlen = REALTEK_BRIDGE_HID_DATALEN_CH3; + } + else if(data_len <= REALTEK_BRIDGE_HID_DATALEN_CH4) + { + *id = REALTEK_BRIDGE_HID_ID_DATA_CH4; + retlen = REALTEK_BRIDGE_HID_DATALEN_CH4; + } + else if(data_len <= REALTEK_BRIDGE_HID_DATALEN_CH5) + { + *id = REALTEK_BRIDGE_HID_ID_DATA_CH5; + retlen = REALTEK_BRIDGE_HID_DATALEN_CH5; + } + else + { + *id = REALTEK_BRIDGE_HID_ID_DATA_CH1; + retlen = REALTEK_BRIDGE_HID_DATALEN_CH1; + } + return retlen; +} + +int RealtekBridgeController::set_write_unlock() +{ + int ret = 0; + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + int data_len = 96; + unsigned int addr = 0xAC004000; + unsigned char* data = (unsigned char*)calloc(data_len, 1); + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_get_packet, sizeof(hid_get_packet)); + usb_buf[0x13] = 0x92; + memcpy(&usb_buf[0x17], &addr, sizeof(addr)); + ret = usb_hid_ioctl(usb_buf, data, data_len, 0, true); + free(data); + return ret; +} + +int RealtekBridgeController::get_brctl_hdr() +{ + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_get_packet, sizeof(hid_get_packet)); + usb_buf[0x13] = 0xCC; + usb_buf[0x14] = 0x02; + return usb_hid_ioctl(usb_buf, brctl_hdr, REALTEK_BRIDGE_CTL_HDR_SIZE, 0, true); +} + +int RealtekBridgeController::set_brctl_hdr() +{ + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_set_packet, sizeof(hid_set_packet)); + usb_buf[0x13] = 0x4C; + usb_buf[0x14] = 0x02; + return usb_hid_ioctl(usb_buf, brctl_hdr, REALTEK_BRIDGE_CTL_HDR_SIZE, 0, false); +} + +int RealtekBridgeController::get_brctl_data() +{ + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + int offset = REALTEK_BRIDGE_CTL_HDR_SIZE; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_get_packet, sizeof(hid_get_packet)); + usb_buf[0x13] = 0xCC; + usb_buf[0x14] = 0x02; + memcpy(&usb_buf[0x17], &offset, sizeof(offset)); + return usb_hid_ioctl(usb_buf, brctl_data, REALTEK_BRIDGE_CTL_DATA_SIZE, 0, true); +} + +int RealtekBridgeController::set_brctl_data() +{ + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + int offset = REALTEK_BRIDGE_CTL_HDR_SIZE; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_set_packet, sizeof(hid_set_packet)); + usb_buf[0x13] = 0x4C; + usb_buf[0x14] = 0x02; + memcpy(&usb_buf[0x17], &offset, sizeof(offset)); + return usb_hid_ioctl(usb_buf, brctl_data, REALTEK_BRIDGE_CTL_DATA_SIZE, 0, false); +} + +unsigned char RealtekBridgeController::get_support_openrgb() +{ + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + unsigned char is_support = 0; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_get_packet, sizeof(hid_get_packet)); + usb_buf[0x13] = 0xCC; + usb_buf[0x14] = 0x04; + usb_buf[0x15] = REALTEK_BRIDGE_SYNC_METHOD_OPENRGB; + if(usb_hid_ioctl(usb_buf, &is_support, sizeof(is_support), 0, true)) + { + is_support = 0; + } + return is_support; +} + +std::string RealtekBridgeController::get_manu_name() +{ + return StringUtils::wchar_to_char(hidinfo->manufacturer_string); +} + +std::string RealtekBridgeController::get_product_name() +{ + return StringUtils::wchar_to_char(hidinfo->product_string); +} + +std::string RealtekBridgeController::get_sn() +{ + return StringUtils::wchar_to_char(hidinfo->serial_number); +} + +std::string RealtekBridgeController::get_dev_loc() +{ + return hidinfo->path; +} + +std::string RealtekBridgeController::get_fw_ver() +{ + struct RealtekBridgeControllerFWVersion fw_ver; + std::string ver = ""; + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_get_packet, sizeof(hid_get_packet)); + usb_buf[0x13] = 0xA5; + if(!usb_hid_ioctl(usb_buf, (unsigned char*)&fw_ver, sizeof(fw_ver), 0, true)) + { + ver += std::to_string(fw_ver.fw_major_ver) + "." + + std::to_string(fw_ver.fw_minor_ver) + "." + + std::to_string(fw_ver.fw_extra_ver) + "." + + std::to_string(fw_ver.fw_build_date); + } + return ver; +} + +int RealtekBridgeController::get_argb_num() +{ + int num_rgb = 0; + memcpy(&num_rgb, &brctl_hdr[24], sizeof(num_rgb)); + + return num_rgb; +} + +int RealtekBridgeController::get_argb_brightness() +{ + int bright = 0; + memcpy(&bright, &brctl_hdr[28], 2); + + return bright; +} + +int RealtekBridgeController::set_argb_brightness(unsigned short bright) +{ + memcpy(&brctl_hdr[28], &bright, sizeof(bright)); + set_brctl_hdr(); + return 0; +} + +int RealtekBridgeController::set_appctl(unsigned char ctl_sts) +{ + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_set_packet, sizeof(hid_set_packet)); + usb_buf[0x13] = 0x4C; + usb_buf[0x14] = 0x01; + usb_buf[0x15] = ctl_sts; + return usb_hid_ioctl(usb_buf, &ctl_sts, sizeof(ctl_sts), 0, false); +} + +int RealtekBridgeController::set_direct(unsigned char* color, int color_num) +{ + int buf_len = REALTEK_BRIDGE_HID_DATALEN_CH1; + int data_len = color_num * REALTEK_BRIDGE_COLOR_DEPTH; + unsigned char* usb_buf = (unsigned char*)calloc(buf_len, 1);// will release in usb_hid_ioctl function + + memset(usb_buf, 0x00, buf_len); + memcpy(usb_buf, hid_set_packet, sizeof(hid_set_packet)); + usb_buf[0x13] = 0x4C; + usb_buf[0x14] = 0x03; + usb_buf[0x15] = REALTEK_BRIDGE_SYNC_METHOD_OPENRGB; + memcpy(&usb_buf[0x17], &color_num, sizeof(color_num)); + return usb_hid_ioctl(usb_buf, color, data_len, 0, false); +} + +int RealtekBridgeController::eff_set_always_on(RGBColor rgb) +{ + int i; + int j; + int row = 1; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 1; + brctl_data[i * single_size + 1] = row; + + for(j = 0; j < row; j++) + { + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_blink(RGBColor rgb, int cycle) +{ + int i; + int j; + int row = 2; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 2; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 1; + + for(j = 0; j < row; j++) + { + if((j & 0x1) == 0) + { + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_breathe(RGBColor rgb, int cycle) +{ + int i; + int j; + int row = 2; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 4; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 2; + + for(j = 0; j < row; j++) + { + if((j & 0x1) == 0) + { + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_spectrum(int cycle) +{ + int i; + int j; + int row = 6; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + static const RGBColor rainbow_table[6] = {0x0000FF, 0x0050FF, 0x0080FF, 0x00FF00, 0xFF0000, 0xFF0080}; + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 4; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 3; + + for(j = 0; j < row; j++) + { + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rainbow_table[j]); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rainbow_table[j]); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rainbow_table[j]); + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_scroll(RGBColor rgb, int cycle) +{ + int i; + int j; + int start_idx = -1; + int row = get_argb_num() * 2 - 2; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 2; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 4; + + if(start_idx == -1) + { + start_idx = i; + } + j = i - start_idx; + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + if(i != start_idx) + { + j = row - (i - start_idx); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_rainbow_scroll(int cycle) +{ + int i; + int j; + int start_idx = -1; + int row = get_argb_num() * 2 - 2; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + RGBColor slide_table[REALTEK_BRIDGE_MAX_ARGB_NUM] = {0}; + hsv_t hsv_color; + + hsv_color.saturation = 255; + hsv_color.value = 255; + for(i = 0; i < get_argb_num(); i++) + { + hsv_color.hue = (i % get_argb_num()) * (360 / get_argb_num()); + slide_table[i] = hsv2rgb(&hsv_color); + } + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 2; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 0x85; + + if(start_idx == -1) + { + start_idx = i; + } + j = i - start_idx; + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(slide_table[i]); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(slide_table[i]); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(slide_table[i]); + if(i != start_idx) + { + j = row - (i - start_idx); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(slide_table[i]); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(slide_table[i]); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(slide_table[i]); + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_running_water(RGBColor rgb, int cycle) +{ + int i; + int j; + int start_idx = -1; + int row = get_argb_num() * 2; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 2; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 5; + + if(start_idx == -1) + { + start_idx = i; + } + + for(j = i - start_idx; j < row / 2; j++) + { + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_sliding(int cycle) +{ + int i; + int j; + int start_idx = -1; + int row = get_argb_num(); + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + RGBColor slide_table[REALTEK_BRIDGE_MAX_ARGB_NUM] = {0}; + RGBColor rgb = 0; + hsv_t hsv_color; + + hsv_color.saturation = 255; + hsv_color.value = 255; + for(i = 0; i < get_argb_num(); i++) + { + hsv_color.hue = (i % get_argb_num()) * (360 / get_argb_num()); + slide_table[i] = hsv2rgb(&hsv_color); + } + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 4; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 0x83; + + if(start_idx == -1) + { + start_idx = i; + } + + for(j = 0; j < row; j++) + { + rgb = slide_table[(i - start_idx + j) % row]; + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_newton_cradle(int cycle) +{ + int i; + int j; + int start_idx = -1; + int row; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + RGBColor rgb = 0; + static const int const_ball_num = 3; + static const RGBColor ball_color[] = {0x0080FF, 0x0000FF, 0x00FF00, 0xFF0000}; + static const int mid = get_argb_num() >> 1; + + if(get_argb_num() <= const_ball_num) + { + return 0; + } + + row = (get_argb_num() - const_ball_num) * 2; + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 2; + brctl_data[i * single_size + 1] = row; + memcpy(&brctl_data[i * single_size + 2], &cycle, 2); + brctl_data[i * single_size + 8] = 0x84; + + if(start_idx == -1) + { + start_idx = i; + } + + for(j = 0; j < row; j++) + { + rgb = 0; + if(i - start_idx > mid - 2 && + i - start_idx < mid + 2) + { + if(j < mid - 1 || j > row - mid) + { + if(i - start_idx == mid - 1) + { + rgb = ball_color[1]; + } + else if(i - start_idx == mid) + { + rgb = ball_color[2]; + } + else + { + rgb = ball_color[3]; + } + } + else + { + if(i - start_idx == mid - 1) + { + rgb = ball_color[0]; + } + else if(i - start_idx == mid) + { + rgb = ball_color[1]; + } + else + { + rgb = ball_color[2]; + } + } + } + else if(i - start_idx < mid) + { + if(i - start_idx == j || i - start_idx + j == row - 1) + { + rgb = ball_color[0]; + } + } + else if(i - start_idx > mid + 1) + { + if(i - start_idx - j == const_ball_num || + i - start_idx + j == row - 1 + const_ball_num) + { + rgb = ball_color[3]; + } + } + + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + } + return set_brctl_data(); +} + +int RealtekBridgeController::eff_set_meteor(RGBColor rgb, int cycle) +{ + int i; + int j; + int row = 2; + int maxrow = REALTEK_BRIDGE_MAX_APPCTL_ROW; + int single_size = maxrow * REALTEK_BRIDGE_COLOR_DEPTH + 32; + int stable_ms = cycle / row; + int latency = stable_ms / get_argb_num(); + + memset(brctl_data, 0, REALTEK_BRIDGE_CTL_DATA_SIZE); + for(i = 0; i < get_argb_num(); i++) + { + brctl_data[i * single_size + 0] = 4; + brctl_data[i * single_size + 1] = row; + brctl_data[i * single_size + 6] = stable_ms / 100; + brctl_data[i * single_size + 7] = stable_ms / 100; + brctl_data[i * single_size + 8] = 6; + memcpy(&brctl_data[i * single_size + 9], &latency, 2); + + j = 0; + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 32] = RGBGetRValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 33] = RGBGetGValue(rgb); + brctl_data[i * single_size + j * REALTEK_BRIDGE_COLOR_DEPTH + 34] = RGBGetBValue(rgb); + } + return set_brctl_data(); +} + +int RealtekBridgeController::set_argb_direct(std::vector color_buf, unsigned short brightness) +{ + int ret = -1; + size_t color_num = color_buf.size(); + size_t buf_len = color_num * REALTEK_BRIDGE_COLOR_DEPTH; + static unsigned short prev_bright = 0xFFFF; + unsigned char* buf; + + if(color_num <= 0) + { + goto exit; + } + + ret = set_appctl(true); + if(ret) + { + goto exit; + } + + if(prev_bright != brightness) + { + prev_bright = brightness; + ret = set_argb_brightness(brightness << 8); + if(ret) + { + goto exit; + } + } + + buf = (unsigned char*)malloc(buf_len); + memset(buf, 0, buf_len); + for(int i = 0; i < (int)color_num; i++) + { + buf[i * REALTEK_BRIDGE_COLOR_DEPTH + 0] = RGBGetRValue(color_buf[i]); + buf[i * REALTEK_BRIDGE_COLOR_DEPTH + 1] = RGBGetGValue(color_buf[i]); + buf[i * REALTEK_BRIDGE_COLOR_DEPTH + 2] = RGBGetBValue(color_buf[i]); + } + ret = set_direct(buf, (int)color_num); + free(buf); + if(ret) + { + goto exit; + } +exit: + return ret; +} + +int RealtekBridgeController::set_argb_effect(unsigned char mode, std::vector color_buf, int speed, unsigned short brightness) +{ + int ret = -1; + int cycle = MathUtils::IntInterpolate(REALTEK_BRIDGE_CYCLE_MAX, REALTEK_BRIDGE_CYCLE_MIN, 0, REALTEK_BRIDGE_SPEED_MAX, speed); + RGBColor rgb = 0; + static unsigned short prev_bright = 0xFFFF; + + if(color_buf.size() >= 1) + { + rgb = color_buf[0]; + } + + if(prev_bright != brightness) + { + prev_bright = brightness; + ret = set_argb_brightness(brightness << 8); + if(ret) + { + goto exit; + } + } + + switch(mode) + { + case REALTEK_BRIDGE_LED_EFF_ALWAYS: + ret = eff_set_always_on(rgb); + break; + case REALTEK_BRIDGE_LED_EFF_BLINK: + ret = eff_set_blink(rgb, cycle); + break; + case REALTEK_BRIDGE_LED_EFF_BREATHE: + ret = eff_set_breathe(rgb, cycle); + break; + case REALTEK_BRIDGE_LED_EFF_SPECTRUM: + ret = eff_set_spectrum(cycle); + break; + case REALTEK_BRIDGE_LED_EFF_SCROLL: + ret = eff_set_scroll(rgb, cycle); + break; + case REALTEK_BRIDGE_LED_EFF_RAINBOW_SCROLL: + ret = eff_set_rainbow_scroll(cycle); + break; + case REALTEK_BRIDGE_LED_EFF_RUNNING_WATER: + ret = eff_set_running_water(rgb, cycle); + break; + case REALTEK_BRIDGE_LED_EFF_SLIDING: + ret = eff_set_sliding(cycle); + break; + case REALTEK_BRIDGE_LED_EFF_NEWTON_CRADLE: + ret = eff_set_newton_cradle(cycle); + break; + case REALTEK_BRIDGE_LED_EFF_METEOR: + ret = eff_set_meteor(rgb, cycle); + break; + default: + break; + } + if(!ret) + { + ret = set_appctl(false); + } +exit: + return ret; +} diff --git a/Controllers/RealtekBridgeController/RealtekBridgeController.h b/Controllers/RealtekBridgeController/RealtekBridgeController.h new file mode 100644 index 000000000..8edfdfd1a --- /dev/null +++ b/Controllers/RealtekBridgeController/RealtekBridgeController.h @@ -0,0 +1,126 @@ +/*---------------------------------------------------------*\ +| RealtekBridgeController.h | +| | +| Controller for Realtek USB to SSD Bridge ICs | +| | +| Jerry Fan (JerryFan0612) 13 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include +#include +#include + +#include "RGBController.h" + +#define REALTEK_BRIDGE_SYNC_METHOD_OPENRGB 6 +#define REALTEK_BRIDGE_COLOR_DEPTH 3 +#define REALTEK_BRIDGE_CTL_HDR_SIZE 64 +#define REALTEK_BRIDGE_CTL_DATA_SIZE 3220 +#define REALTEK_BRIDGE_MAX_ARGB_NUM 20 +#define REALTEK_BRIDGE_MAX_APPCTL_ROW 43 + +#define REALTEK_BRIDGE_HID_DATALEN_CH1 4096 +#define REALTEK_BRIDGE_HID_DATALEN_CH2 64 +#define REALTEK_BRIDGE_HID_DATALEN_CH3 512 +#define REALTEK_BRIDGE_HID_DATALEN_CH4 1200 +#define REALTEK_BRIDGE_HID_DATALEN_CH5 2048 + +#define REALTEK_BRIDGE_HID_ID_DATA_CH1 0x57 +#define REALTEK_BRIDGE_HID_ID_DATA_CH2 0x59 +#define REALTEK_BRIDGE_HID_ID_DATA_CH3 0x5A +#define REALTEK_BRIDGE_HID_ID_DATA_CH4 0x5B +#define REALTEK_BRIDGE_HID_ID_DATA_CH5 0x5C + +enum REALTEK_BRIDGE_LED_EFF +{ + REALTEK_BRIDGE_LED_EFF_NONE, + REALTEK_BRIDGE_LED_EFF_ALWAYS, + REALTEK_BRIDGE_LED_EFF_BLINK, + REALTEK_BRIDGE_LED_EFF_BREATHE, + REALTEK_BRIDGE_LED_EFF_SPECTRUM, + REALTEK_BRIDGE_LED_EFF_SCROLL, + REALTEK_BRIDGE_LED_EFF_RAINBOW_SCROLL, + REALTEK_BRIDGE_LED_EFF_RUNNING_WATER, + REALTEK_BRIDGE_LED_EFF_SLIDING, + REALTEK_BRIDGE_LED_EFF_NEWTON_CRADLE, + REALTEK_BRIDGE_LED_EFF_METEOR, + REALTEK_BRIDGE_NUMBER_OF_LED_EFF_MODE, +}; + +enum REALTEK_BRIDGE_SPEED +{ + REALTEK_BRIDGE_SPEED_MIN = 1, + REALTEK_BRIDGE_SPEED_NORMAL = 50, + REALTEK_BRIDGE_SPEED_MAX = 100, +}; + +enum REALTEK_BRIDGE_CYCLE_MS +{ + REALTEK_BRIDGE_CYCLE_MIN = 200, + REALTEK_BRIDGE_CYCLE_NORMAL = 2000, + REALTEK_BRIDGE_CYCLE_MAX = 10000, +}; + +struct RealtekBridgeControllerFWVersion +{ + unsigned int fw_major_ver; + unsigned int fw_minor_ver; + unsigned int fw_extra_ver; + unsigned int fw_build_ver; + unsigned int fw_build_date; +}; + +class RealtekBridgeController +{ +public: + RealtekBridgeController(hid_device* dev, hid_device_info* info); + ~RealtekBridgeController(); + + unsigned char get_support_openrgb(); + std::string get_manu_name(); + std::string get_product_name(); + std::string get_sn(); + std::string get_dev_loc(); + std::string get_fw_ver(); + int get_argb_num(); + int get_argb_brightness(); + int set_argb_brightness(unsigned short bright); + + int set_argb_direct(std::vector color_buf, unsigned short brightness); + int set_argb_effect(unsigned char mode, std::vector color_buf, int speed, unsigned short brightness); + +private: + hid_device* hdev; + hid_device_info* hidinfo = NULL; + unsigned char brctl_hdr[REALTEK_BRIDGE_CTL_HDR_SIZE] = {0}; + unsigned char* brctl_data = NULL; + + int usb_hid_ioctl(unsigned char* usb_buf, unsigned char* data, int data_len, + unsigned int offset, unsigned char is_in); + int usb_hid_get_report(int data_len, int* id); + int set_write_unlock(); + int get_brctl_hdr(); + int set_brctl_hdr(); + int get_brctl_data(); + int set_brctl_data(); + int set_appctl(unsigned char ctl_sts); + int set_direct(unsigned char* color, int color_num); + int eff_set_always_on(RGBColor rgb); + int eff_set_blink(RGBColor rgb, int cycle); + int eff_set_breathe(RGBColor rgb, int cycle); + int eff_set_spectrum(int cycle); + int eff_set_scroll(RGBColor rgb, int cycle); + int eff_set_rainbow_scroll(int cycle); + int eff_set_running_water(RGBColor rgb, int cycle); + int eff_set_sliding(int cycle); + int eff_set_newton_cradle(int cycle); + int eff_set_meteor(RGBColor rgb, int cycle); +}; diff --git a/Controllers/RealtekBridgeController/RealtekBridgeControllerDetect.cpp b/Controllers/RealtekBridgeController/RealtekBridgeControllerDetect.cpp new file mode 100644 index 000000000..934accfed --- /dev/null +++ b/Controllers/RealtekBridgeController/RealtekBridgeControllerDetect.cpp @@ -0,0 +1,61 @@ +/*---------------------------------------------------------*\ +| RealtekBridgeControllerDetect.cpp | +| | +| Controller for Realtek USB to SSD Bridge ICs | +| | +| Jerry Fan (JerryFan0612) 13 Mar 2026 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include "Detector.h" +#include "RGBController_RealtekBridge.h" + +#define REALTEK_BRIDGE_VID 0x0BDA +#define REALTEK_BRIDGE_PID0 0x9220 +#define REALTEK_BRIDGE_PID1 0x9201 +#define REALTEK_BRIDGE_PID2 0x9210 + +#define REALTEK_HID2SCSI_PG 0xFF00 +#define REALTEK_HID2SCSI_USAGE 0x0001 + +/******************************************************************************************\ +* * +* DetectRealtekBridgeControllers * +* * +* Tests the USB address to see if an Realtek Bridge controller exists there * +* * +\******************************************************************************************/ +void DetectRealtekBridgeControllers(hid_device_info* info, const std::string& /*name*/) +{ + RealtekBridgeController* controller = NULL; + RGBController_RealtekBridge* rgb_controller = NULL; + hid_device* dev = hid_open_path(info->path); + + if(dev) + { + controller = new RealtekBridgeController(dev, info); + if(controller->get_support_openrgb()) + { + rgb_controller = new RGBController_RealtekBridge(controller); + if(rgb_controller->type != DEVICE_TYPE_UNKNOWN) + { + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + else + { + delete rgb_controller; + } + } + else + { + delete controller; + } + } + return; +} + +REGISTER_HID_DETECTOR_PU("RTL9220", DetectRealtekBridgeControllers, REALTEK_BRIDGE_VID, REALTEK_BRIDGE_PID0, REALTEK_HID2SCSI_PG, REALTEK_HID2SCSI_USAGE); +REGISTER_HID_DETECTOR_PU("RTL9201", DetectRealtekBridgeControllers, REALTEK_BRIDGE_VID, REALTEK_BRIDGE_PID1, REALTEK_HID2SCSI_PG, REALTEK_HID2SCSI_USAGE); +REGISTER_HID_DETECTOR_PU("RTL9210", DetectRealtekBridgeControllers, REALTEK_BRIDGE_VID, REALTEK_BRIDGE_PID2, REALTEK_HID2SCSI_PG, REALTEK_HID2SCSI_USAGE); diff --git a/MathUtils.cpp b/MathUtils.cpp new file mode 100644 index 000000000..f57b5df8d --- /dev/null +++ b/MathUtils.cpp @@ -0,0 +1,24 @@ +/*---------------------------------------------------------*\ +| MathUtils.cpp | +| | +| Math utility functions | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#include +#include "MathUtils.h" + +int MathUtils::IntInterpolate(int y0, int y1, int x0, int x1, int x) +{ + if(x1 == x0) + return y0; + + if(y0 == y1) + return y0; + + double t = (double)(x - x0) / (double)(x1 - x0); + double y = y0 * (1.0 - t) + y1 * t; + return (int)round(y); +} \ No newline at end of file diff --git a/MathUtils.h b/MathUtils.h new file mode 100644 index 000000000..b7a8f22a5 --- /dev/null +++ b/MathUtils.h @@ -0,0 +1,18 @@ +/*---------------------------------------------------------*\ +| MathUtils.h | +| | +| Math utility functions | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-or-later | +\*---------------------------------------------------------*/ + +#pragma once + +#include + +class MathUtils +{ +public: + static int IntInterpolate(int y0, int y1, int x0, int x1, int x); +}; \ No newline at end of file diff --git a/OpenRGB.pro b/OpenRGB.pro index 9f882385b..b57bd36ba 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -199,6 +199,7 @@ HEADERS += serial_port/find_usb_serial_port.h \ serial_port/serial_port.h \ super_io/super_io.h \ + MathUtils.h \ StringUtils.h \ SuspendResume/SuspendResume.h \ AutoStart/AutoStart.h \ @@ -265,6 +266,7 @@ SOURCES += interop/DeviceGuardManager.cpp \ net_port/net_port.cpp \ serial_port/serial_port.cpp \ + MathUtils.cpp \ StringUtils.cpp \ AutoStart/AutoStart.cpp \ KeyboardLayoutManager/KeyboardLayoutManager.cpp \ diff --git a/StringUtils.cpp b/StringUtils.cpp index 880a60bf4..3647de3c9 100644 --- a/StringUtils.cpp +++ b/StringUtils.cpp @@ -94,3 +94,10 @@ const std::string StringUtils::remove_null_terminating_chars(std::string input) return(input); } + +std::string StringUtils::u32int_to_hexString(unsigned int value) +{ + char hex_str[20] = {0}; + snprintf(hex_str, sizeof(hex_str), "%X", value); + return std::string(hex_str); +} \ No newline at end of file diff --git a/StringUtils.h b/StringUtils.h index 8a200f937..c008d91de 100644 --- a/StringUtils.h +++ b/StringUtils.h @@ -18,4 +18,5 @@ public: static std::string wstring_to_string(const std::wstring wstring); static std::string u16string_to_string(const std::u16string wstring); static const std::string remove_null_terminating_chars(std::string input); + static std::string u32int_to_hexString(unsigned int value); };