From 26a0b889375a2063c0f7837606c0d4d82c230171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Milan=20=C4=8Cerm=C3=A1k?= Date: Tue, 8 Jul 2025 23:39:22 +0200 Subject: [PATCH] Initial commit for TeamGroup T-Force Xtreem ARGB DDR4 Memory --- .../ENESMBusControllerDetect.cpp | 7 +- .../RGBController_TForceXtreem.cpp | 502 ++++++++++++++++++ .../RGBController_TForceXtreem.h | 37 ++ .../TForceXtreemController.cpp | 183 +++++++ .../TForceXtreemController.h | 111 ++++ .../TForceXtreemControllerDetect.cpp | 184 +++++++ 6 files changed, 1021 insertions(+), 3 deletions(-) create mode 100644 Controllers/TForceXtreemController/RGBController_TForceXtreem.cpp create mode 100644 Controllers/TForceXtreemController/RGBController_TForceXtreem.h create mode 100644 Controllers/TForceXtreemController/TForceXtreemController.cpp create mode 100644 Controllers/TForceXtreemController/TForceXtreemController.h create mode 100644 Controllers/TForceXtreemController/TForceXtreemControllerDetect.cpp diff --git a/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp b/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp index cfbf062f..21edbce7 100644 --- a/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp +++ b/Controllers/ENESMBusController/ENESMBusControllerDetect.cpp @@ -84,7 +84,7 @@ static const unsigned char aura_mobo_addresses[] = * * \******************************************************************************************/ -unsigned char ENERegisterRead(i2c_smbus_interface* bus, ene_dev_id dev, ene_register reg) +static unsigned char ENERegisterRead(i2c_smbus_interface* bus, ene_dev_id dev, ene_register reg) { //Write ENE register bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); @@ -103,7 +103,7 @@ unsigned char ENERegisterRead(i2c_smbus_interface* bus, ene_dev_id dev, ene_regi * * \******************************************************************************************/ -void ENERegisterWrite(i2c_smbus_interface* bus, ene_dev_id dev, ene_register reg, unsigned char val) +static void ENERegisterWrite(i2c_smbus_interface* bus, ene_dev_id dev, ene_register reg, unsigned char val) { //Write ENE register bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); @@ -154,6 +154,7 @@ bool TestForENESMBusController(i2c_smbus_interface* bus, unsigned char address) LOG_VERBOSE("[ENE SMBus] Detection failed testing register %02X. Expected %02X, got %02X.", i, (i - 0xA0), res); pass = false; + break; } } @@ -208,7 +209,7 @@ void DetectENESMBusDRAMControllers(std::vector &busses) { int res = busses[bus]->i2c_smbus_write_quick(0x77, I2C_SMBUS_WRITE); - if (res < 0) + if(res < 0) { LOG_DEBUG("[ENE SMBus DRAM] No device detected at 0x77, aborting remap"); diff --git a/Controllers/TForceXtreemController/RGBController_TForceXtreem.cpp b/Controllers/TForceXtreemController/RGBController_TForceXtreem.cpp new file mode 100644 index 00000000..35107595 --- /dev/null +++ b/Controllers/TForceXtreemController/RGBController_TForceXtreem.cpp @@ -0,0 +1,502 @@ +/*---------------------------------------------------------*\ +| RGBController_TForceXtreem.cpp | +| | +| RGBController for TeamGroup T-Force Xtreem RAM | +| | +| Milan Cermak (krysmanta) 28 Dec 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "RGBController_TForceXtreem.h" +#include "LogManager.h" +#include "ResourceManager.h" + +/**------------------------------------------------------------------*\ + @name T-Force Xtreem + @category RAM + @type SMBus + @save :white_check_mark: + @direct :white_check_mark: + @effects :white_check_mark: + @detectors DetectTForceXtreemControllers + @comment + Verified models: + TeamGroup T-Force Xtreem ARGB DDR4 +\*-------------------------------------------------------------------*/ + +RGBController_TForceXtreem::RGBController_TForceXtreem(TForceXtreemController * controller_ptr) +{ + controller = controller_ptr; + + type = DEVICE_TYPE_DRAM; + name = "T-Force Xtreem RGB"; + vendor = "TeamGroup"; + + location = controller->GetDeviceLocation(); + description = "TeamGroup T-Force Xtreem DRAM"; + + mode Direct; + Direct.name = "Direct"; + Direct.value = 0xFFFF; + Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Direct.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Direct); + + mode Off; + Off.name = "Off"; + Off.value = XTREEM_MODE_OFF; + Off.flags = 0; + Off.color_mode = MODE_COLORS_NONE; + modes.push_back(Off); + + mode Static; + Static.name = "Static"; + Static.value = XTREEM_MODE_STATIC; + Static.flags = MODE_FLAG_HAS_PER_LED_COLOR; + Static.color_mode = MODE_COLORS_PER_LED; + modes.push_back(Static); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = XTREEM_MODE_BREATHING; + Breathing.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED; + Breathing.color_mode = MODE_COLORS_PER_LED; + Breathing.speed_min = XTREEM_SPEED_SLOWEST; + Breathing.speed_max = XTREEM_SPEED_FASTEST; + Breathing.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Breathing); + + mode Flashing; + Flashing.name = "Flashing"; + Flashing.value = XTREEM_MODE_FLASHING; + Flashing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED; + Flashing.color_mode = MODE_COLORS_PER_LED; + Flashing.speed_min = XTREEM_SPEED_SLOWEST; + Flashing.speed_max = XTREEM_SPEED_FASTEST; + Flashing.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Flashing); + + mode SpectrumCycle; + SpectrumCycle.name = "Spectrum Cycle"; + SpectrumCycle.value = XTREEM_MODE_SPECTRUM_CYCLE; + SpectrumCycle.flags = MODE_FLAG_HAS_SPEED; + SpectrumCycle.color_mode = MODE_COLORS_NONE; + SpectrumCycle.speed_min = XTREEM_SPEED_SLOWEST; + SpectrumCycle.speed_max = XTREEM_SPEED_FASTEST; + SpectrumCycle.speed = XTREEM_SPEED_NORMAL; + modes.push_back(SpectrumCycle); + + mode Rainbow; + Rainbow.name = "Rainbow"; + Rainbow.value = XTREEM_MODE_RAINBOW; + Rainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR; + Rainbow.color_mode = MODE_COLORS_NONE; + Rainbow.speed_min = XTREEM_SPEED_SLOWEST; + Rainbow.speed_max = XTREEM_SPEED_FASTEST; + Rainbow.speed = XTREEM_SPEED_NORMAL; + Rainbow.direction = MODE_DIRECTION_LEFT; + modes.push_back(Rainbow); + + mode ChaseFade; + ChaseFade.name = "Chase Fade"; + ChaseFade.value = XTREEM_MODE_CHASE_FADE; + ChaseFade.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR; + ChaseFade.color_mode = MODE_COLORS_PER_LED; + ChaseFade.speed_min = XTREEM_SPEED_SLOWEST; + ChaseFade.speed_max = XTREEM_SPEED_FASTEST; + ChaseFade.speed = XTREEM_SPEED_NORMAL; + ChaseFade.direction = MODE_DIRECTION_LEFT; + modes.push_back(ChaseFade); + + mode Chase; + Chase.name = "Chase"; + Chase.value = XTREEM_MODE_CHASE; + Chase.flags = MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR; + Chase.color_mode = MODE_COLORS_PER_LED; + Chase.speed_min = XTREEM_SPEED_SLOWEST; + Chase.speed_max = XTREEM_SPEED_FASTEST; + Chase.speed = XTREEM_SPEED_NORMAL; + ChaseFade.direction = MODE_DIRECTION_LEFT; + modes.push_back(Chase); + + mode RandomFlicker; + RandomFlicker.name = "Random Flicker"; + RandomFlicker.value = XTREEM_MODE_RANDOM_FLICKER; + RandomFlicker.flags = MODE_FLAG_HAS_SPEED; + RandomFlicker.color_mode = MODE_COLORS_NONE; + RandomFlicker.speed_min = XTREEM_SPEED_SLOWEST; + RandomFlicker.speed_max = XTREEM_SPEED_FASTEST; + RandomFlicker.speed = XTREEM_SPEED_NORMAL; + modes.push_back(RandomFlicker); + + mode Stack; + Stack.name = "Stack"; + Stack.value = XTREEM_MODE_STACK; + Stack.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR; + Stack.color_mode = MODE_COLORS_NONE; + Stack.speed_min = XTREEM_SPEED_SLOWEST; + Stack.speed_max = XTREEM_SPEED_FASTEST; + Stack.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Stack); + + mode Pong; + Pong.name = "Pong"; + Pong.value = XTREEM_MODE_PONG; + Pong.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR; + Pong.color_mode = MODE_COLORS_NONE; + Pong.speed_min = XTREEM_SPEED_SLOWEST; + Pong.speed_max = XTREEM_SPEED_FASTEST; + Pong.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Pong); + + mode Fillup; + Fillup.name = "Fill up"; + Fillup.value = XTREEM_MODE_FILLUP; + Fillup.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR; + Fillup.color_mode = MODE_COLORS_NONE; + Fillup.speed_min = XTREEM_SPEED_SLOWEST; + Fillup.speed_max = XTREEM_SPEED_FASTEST; + Fillup.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Fillup); + + mode Neon; + Neon.name = "Neon Sign"; + Neon.value = XTREEM_MODE_NEON; + Neon.flags = MODE_FLAG_HAS_SPEED; + Neon.color_mode = MODE_COLORS_NONE; + Neon.speed_min = XTREEM_SPEED_SLOWEST; + Neon.speed_max = XTREEM_SPEED_FASTEST; + Neon.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Neon); + + mode ColorWave; + ColorWave.name = "Wave"; + ColorWave.value = XTREEM_MODE_COLOR_WAVE; + ColorWave.flags = MODE_FLAG_HAS_SPEED; + ColorWave.color_mode = MODE_COLORS_NONE; + ColorWave.speed_min = XTREEM_SPEED_SLOWEST; + ColorWave.speed_max = XTREEM_SPEED_FASTEST; + ColorWave.speed = XTREEM_SPEED_NORMAL; + modes.push_back(ColorWave); + + mode DoubleWave; + DoubleWave.name = "Double Wave"; + DoubleWave.value = XTREEM_MODE_COLOR_DOUBLE_WAVE; + DoubleWave.flags = MODE_FLAG_HAS_SPEED; + DoubleWave.color_mode = MODE_COLORS_NONE; + DoubleWave.speed_min = XTREEM_SPEED_SLOWEST; + DoubleWave.speed_max = XTREEM_SPEED_FASTEST; + DoubleWave.speed = XTREEM_SPEED_NORMAL; + modes.push_back(DoubleWave); + + mode Mixer; + Mixer.name = "Mixer"; + Mixer.value = XTREEM_MODE_MIXER; + Mixer.flags = MODE_FLAG_HAS_SPEED; + Mixer.color_mode = MODE_COLORS_NONE; + Mixer.speed_min = XTREEM_SPEED_SLOWEST; + Mixer.speed_max = XTREEM_SPEED_FASTEST; + Mixer.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Mixer); + + mode Spectrum2; + Spectrum2.name = "Spectrum Cycle 2"; + Spectrum2.value = XTREEM_MODE_SPECTRUM_CYCLE_2; + Spectrum2.flags = MODE_FLAG_HAS_SPEED; + Spectrum2.color_mode = MODE_COLORS_NONE; + Spectrum2.speed_min = XTREEM_SPEED_SLOWEST; + Spectrum2.speed_max = XTREEM_SPEED_FASTEST; + Spectrum2.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Spectrum2); + + mode FireBreathing; + FireBreathing.name = "Fire Breathing"; + FireBreathing.value = XTREEM_MODE_FIRE_BREATHING; + FireBreathing.flags = MODE_FLAG_HAS_SPEED; + FireBreathing.color_mode = MODE_COLORS_NONE; + FireBreathing.speed_min = XTREEM_SPEED_SLOWEST; + FireBreathing.speed_max = XTREEM_SPEED_FASTEST; + FireBreathing.speed = XTREEM_SPEED_NORMAL; + modes.push_back(FireBreathing); + + mode Spectrum3; + Spectrum3.name = "Spectrum Cycle 3"; + Spectrum3.value = XTREEM_MODE_SPECTRUM_CYCLE_3; + Spectrum3.flags = MODE_FLAG_HAS_SPEED; + Spectrum3.color_mode = MODE_COLORS_NONE; + Spectrum3.speed_min = XTREEM_SPEED_SLOWEST; + Spectrum3.speed_max = XTREEM_SPEED_FASTEST; + Spectrum3.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Spectrum3); + + mode Slither; + Slither.name = "Slither"; + Slither.value = XTREEM_MODE_SLITHER; + Slither.flags = MODE_FLAG_HAS_SPEED; + Slither.color_mode = MODE_COLORS_NONE; + Slither.speed_min = XTREEM_SPEED_SLOWEST; + Slither.speed_max = XTREEM_SPEED_FASTEST; + Slither.speed = XTREEM_SPEED_NORMAL; + modes.push_back(Slither); + + mode TForceXtreem; + TForceXtreem.name = "T-Force Xtreem"; + TForceXtreem.value = XTREEM_MODE_TFORCE_XTREEM; + TForceXtreem.flags = MODE_FLAG_HAS_SPEED; + TForceXtreem.color_mode = MODE_COLORS_NONE; + TForceXtreem.speed_min = XTREEM_SPEED_SLOWEST; + TForceXtreem.speed_max = XTREEM_SPEED_FASTEST; + TForceXtreem.speed = XTREEM_SPEED_NORMAL; + modes.push_back(TForceXtreem); + + SetupZones(); + + /*-------------------------------------------------*\ + | Initialize active mode | + \*-------------------------------------------------*/ + active_mode = GetDeviceMode(); +} + +RGBController_TForceXtreem::~RGBController_TForceXtreem() +{ + delete controller; +} + +int RGBController_TForceXtreem::GetDeviceMode() +{ + /*-----------------------------------------------------------------*\ + | Determine starting mode by reading the mode and direct registers | + \*-----------------------------------------------------------------*/ + int dev_mode = controller->ENERegisterRead(XTREEM_REG_MODE); + int color_mode = MODE_COLORS_PER_LED; + int speed = controller->ENERegisterRead(XTREEM_REG_SPEED); + int direction = controller->ENERegisterRead(XTREEM_REG_DIRECTION); + + LOG_TRACE("[%s] Retrieved ENE mode from module: %02d", name.c_str(), dev_mode); + + if(controller->ENERegisterRead(XTREEM_REG_DIRECT)) + { + dev_mode = 0xFFFF; + } + + switch(dev_mode) + { + case XTREEM_MODE_OFF: + case XTREEM_MODE_RAINBOW: + case XTREEM_MODE_SPECTRUM_CYCLE: + case XTREEM_MODE_RANDOM_FLICKER: + color_mode = MODE_COLORS_NONE; + break; + + case XTREEM_MODE_SPECTRUM_CYCLE_CHASE: + dev_mode = XTREEM_MODE_CHASE; + color_mode = MODE_COLORS_RANDOM; + break; + + case XTREEM_MODE_SPECTRUM_CYCLE_BREATHING: + dev_mode = XTREEM_MODE_BREATHING; + color_mode = MODE_COLORS_RANDOM; + break; + + case XTREEM_MODE_SPECTRUM_CYCLE_CHASE_FADE: + dev_mode = XTREEM_MODE_CHASE_FADE; + color_mode = MODE_COLORS_RANDOM; + break; + } + + for(int mode = 0; mode < (int)modes.size(); mode++) + { + if(modes[mode].value == dev_mode) + { + active_mode = mode; + modes[mode].color_mode = color_mode; + + if(modes[mode].flags & MODE_FLAG_HAS_SPEED) + { + modes[mode].speed = speed; + } + + if(modes[mode].flags & MODE_FLAG_HAS_DIRECTION_LR) + { + if(direction == XTREEM_DIRECTION_FORWARD) + { + modes[mode].direction = MODE_DIRECTION_RIGHT; + } + else + { + modes[mode].direction = MODE_DIRECTION_LEFT; + } + } + + break; + } + } + + /*---------------------------------------------------------*\ + | Initialize colors for each LED | + \*---------------------------------------------------------*/ + for(std::size_t led_idx = 0; led_idx < leds.size(); led_idx++) + { + unsigned int led = leds[led_idx].value; + unsigned char red; + unsigned char grn; + unsigned char blu; + + if(active_mode == 0) + { + red = controller->GetLEDRed(led); + grn = controller->GetLEDGreen(led); + blu = controller->GetLEDBlue(led); + } + else + { + red = controller->GetLEDRedEffect(led); + grn = controller->GetLEDGreenEffect(led); + blu = controller->GetLEDBlueEffect(led); + } + + colors[led_idx] = ToRGBColor(red, grn, blu); + } + + return(active_mode); +} + +void RGBController_TForceXtreem::DeviceUpdateLEDs() +{ + if(GetMode() == 0) + { + controller->SetAllColorsDirect(&colors[0]); + } + else + { + controller->SetAllColorsEffect(&colors[0]); + } + +} + +void RGBController_TForceXtreem::UpdateZoneLEDs(int zone) +{ + for(std::size_t led_idx = 0; led_idx < zones[zone].leds_count; led_idx++) + { + int led = zones[zone].leds[led_idx].value; + RGBColor color = colors[led]; + unsigned char red = RGBGetRValue(color); + unsigned char grn = RGBGetGValue(color); + unsigned char blu = RGBGetBValue(color); + + if(GetMode() == 0) + { + controller->SetLEDColorDirect(led, red, grn, blu); + } + else + { + controller->SetLEDColorEffect(led, red, grn, blu); + } + } +} + +void RGBController_TForceXtreem::UpdateSingleLED(int led) +{ + RGBColor color = colors[led]; + unsigned char red = RGBGetRValue(color); + unsigned char grn = RGBGetGValue(color); + unsigned char blu = RGBGetBValue(color); + + if(GetMode() == 0) + { + controller->SetLEDColorDirect(led, red, grn, blu); + } + else + { + controller->SetLEDColorEffect(led, red, grn, blu); + } +} + +void RGBController_TForceXtreem::SetupZones() +{ + /*---------------------------------------------------------*\ + | Set up zone | + \*---------------------------------------------------------*/ + zone new_zone; + new_zone.name = "DRAM"; + new_zone.type = ZONE_TYPE_LINEAR; + new_zone.leds_min = XTREEM_LED_COUNT; + new_zone.leds_max = XTREEM_LED_COUNT; + new_zone.leds_count = XTREEM_LED_COUNT; + new_zone.matrix_map = NULL; + zones.push_back(new_zone); + + /*---------------------------------------------------------*\ + | Set up LEDs | + \*---------------------------------------------------------*/ + for(std::size_t led_idx = 0; led_idx < zones[0].leds_count; led_idx++) + { + led new_led; + new_led.name = "DRAM LED "; + new_led.name.append(std::to_string(led_idx)); + leds.push_back(new_led); + } + + SetupColors(); +} + +void RGBController_TForceXtreem::ResizeZone(int /*zone*/, int /*new_size*/) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_TForceXtreem::DeviceUpdateMode() +{ + if(modes[active_mode].value == 0xFFFF) + { + controller->SetDirect(true); + } + else + { + int new_mode = modes[active_mode].value; + int new_speed = 0; + int new_direction = 0; + + if(modes[active_mode].color_mode == MODE_COLORS_RANDOM) + { + switch(new_mode) + { + case XTREEM_MODE_CHASE: + new_mode = XTREEM_MODE_SPECTRUM_CYCLE_CHASE; + break; + case XTREEM_MODE_BREATHING: + new_mode = XTREEM_MODE_SPECTRUM_CYCLE_BREATHING; + break; + case XTREEM_MODE_CHASE_FADE: + new_mode = XTREEM_MODE_SPECTRUM_CYCLE_CHASE_FADE; + break; + } + } + + if(modes[active_mode].flags & MODE_FLAG_HAS_SPEED) + { + new_speed = modes[active_mode].speed; + } + + if(modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_LR) + { + switch(modes[active_mode].direction) + { + case MODE_DIRECTION_LEFT: + new_direction = XTREEM_DIRECTION_REVERSE; + break; + + case MODE_DIRECTION_RIGHT: + new_direction = XTREEM_DIRECTION_FORWARD; + break; + } + } + + controller->SetMode(new_mode, new_speed, new_direction); + controller->SetDirect(false); + } +} diff --git a/Controllers/TForceXtreemController/RGBController_TForceXtreem.h b/Controllers/TForceXtreemController/RGBController_TForceXtreem.h new file mode 100644 index 00000000..33c4f091 --- /dev/null +++ b/Controllers/TForceXtreemController/RGBController_TForceXtreem.h @@ -0,0 +1,37 @@ +/*---------------------------------------------------------*\ +| RGBController_TForceXtreem.h | +| | +| RGBController for TeamGroup T-Force Xtreem RAM | +| | +| Milan Cermak (krysmanta) 28 Dec 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "TForceXtreemController.h" + +class RGBController_TForceXtreem : public RGBController +{ +public: + RGBController_TForceXtreem(TForceXtreemController* controller_ptr); + ~RGBController_TForceXtreem(); + + void SetupZones(); + + void ResizeZone(int zone, int new_size); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int zone); + void UpdateSingleLED(int led); + + void DeviceUpdateMode(); + +private: + TForceXtreemController* controller; + + int GetDeviceMode(); +}; diff --git a/Controllers/TForceXtreemController/TForceXtreemController.cpp b/Controllers/TForceXtreemController/TForceXtreemController.cpp new file mode 100644 index 00000000..7e073507 --- /dev/null +++ b/Controllers/TForceXtreemController/TForceXtreemController.cpp @@ -0,0 +1,183 @@ +/*---------------------------------------------------------*\ +| TForceXtreemController.cpp | +| | +| Driver for T-Force XTreem DRAM | +| | +| Milan Cermak (krysmanta) 28 Dec 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include "TForceXtreemController.h" +#include "LogManager.h" + +TForceXtreemController::TForceXtreemController(i2c_smbus_interface *bus, ene_dev_id dev) +{ + this->bus = bus; + this->dev = dev; +} + +TForceXtreemController::~TForceXtreemController() +{ +} + +std::string TForceXtreemController::GetDeviceLocation() +{ + std::string return_string(bus->device_name); + + char addr[5]; + snprintf(addr, 5, "0x%02X", dev); + return_string.append(", address "); + return_string.append(addr); + + return(return_string); +} + +unsigned int TForceXtreemController::GetLEDCount() +{ + return(XTREEM_LED_COUNT); +} + +/*---------------------------------------------------*\ +| LEDs are in a single strip that is folded in half. | +| That makes the LED order: 0-14-1-13-2-...-7-9-8 | +\*---------------------------------------------------*/ +#define XTREEM_LED_OFFSET(x) ((((x) & 0x01) > 0) ? XTREEM_LED_COUNT - 1 - ((x) >> 1) : ((x) >> 1)) + +unsigned char TForceXtreemController::GetLEDRed(unsigned int led) +{ + return(ENERegisterRead(XTREEM_REG_COLORS_DIRECT + ( 3 * XTREEM_LED_OFFSET(led) ))); +} + +unsigned char TForceXtreemController::GetLEDGreen(unsigned int led) +{ + return(ENERegisterRead(XTREEM_REG_COLORS_DIRECT + ( 3 * XTREEM_LED_OFFSET(led) ) + 2)); +} + +unsigned char TForceXtreemController::GetLEDBlue(unsigned int led) +{ + return(ENERegisterRead(XTREEM_REG_COLORS_DIRECT + ( 3 * XTREEM_LED_OFFSET(led) ) + 1)); +} + +unsigned char TForceXtreemController::GetLEDRedEffect(unsigned int led) +{ + return(ENERegisterRead(XTREEM_REG_COLORS_EFFECT + ( 3 * XTREEM_LED_OFFSET(led) ))); +} + +unsigned char TForceXtreemController::GetLEDGreenEffect(unsigned int led) +{ + return(ENERegisterRead(XTREEM_REG_COLORS_EFFECT + ( 3 * XTREEM_LED_OFFSET(led) ) + 2)); +} + +unsigned char TForceXtreemController::GetLEDBlueEffect(unsigned int led) +{ + return(ENERegisterRead(XTREEM_REG_COLORS_EFFECT + ( 3 * XTREEM_LED_OFFSET(led) ) + 1)); +} + +void TForceXtreemController::SetAllColorsDirect(RGBColor* colors) +{ + unsigned char* color_buf = new unsigned char[XTREEM_LED_COUNT * 3]; + unsigned int bytes_sent = 0; + + for(unsigned int i = 0; i < XTREEM_LED_COUNT; i++) + { + unsigned int offset = 3 * XTREEM_LED_OFFSET(i); + color_buf[offset + 0] = RGBGetRValue(colors[i]); + color_buf[offset + 1] = RGBGetBValue(colors[i]); + color_buf[offset + 2] = RGBGetGValue(colors[i]); + } + + while(bytes_sent < (XTREEM_LED_COUNT * 3)) + { + ENERegisterWriteBlock(XTREEM_REG_COLORS_DIRECT + bytes_sent, &color_buf[bytes_sent], 3); + + bytes_sent += 3; + } + + delete[] color_buf; +} + +void TForceXtreemController::SetAllColorsEffect(RGBColor* colors) +{ + unsigned char* color_buf = new unsigned char[XTREEM_LED_COUNT * 3]; + unsigned int bytes_sent = 0; + + for(unsigned int i = 0; i < XTREEM_LED_COUNT; i++) + { + unsigned int offset = 3 * XTREEM_LED_OFFSET(i); + color_buf[offset + 0] = RGBGetRValue(colors[i]); + color_buf[offset + 1] = RGBGetBValue(colors[i]); + color_buf[offset + 2] = RGBGetGValue(colors[i]); + } + + while(bytes_sent < (XTREEM_LED_COUNT * 3)) + { + ENERegisterWriteBlock(XTREEM_REG_COLORS_EFFECT + bytes_sent, &color_buf[bytes_sent], 3); + + bytes_sent += 3; + } + + ENERegisterWrite(XTREEM_REG_APPLY, XTREEM_APPLY_VAL); + + delete[] color_buf; +} + + +void TForceXtreemController::SetDirect(unsigned char direct) +{ + ENERegisterWrite(XTREEM_REG_DIRECT, direct); + ENERegisterWrite(XTREEM_REG_APPLY, XTREEM_APPLY_VAL); +} + +void TForceXtreemController::SetLEDColorDirect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue) +{ + unsigned char colors[3] = { red, blue, green }; + + ENERegisterWriteBlock(XTREEM_REG_COLORS_DIRECT + ( 3 * XTREEM_LED_OFFSET(led) ), colors, 3); +} + +void TForceXtreemController::SetLEDColorEffect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue) +{ + unsigned char colors[3] = { red, blue, green }; + + ENERegisterWriteBlock(XTREEM_REG_COLORS_EFFECT + (3 * XTREEM_LED_OFFSET(led)), colors, 3); + + ENERegisterWrite(XTREEM_REG_APPLY, XTREEM_APPLY_VAL); +} + +void TForceXtreemController::SetMode(unsigned char mode, unsigned char speed, unsigned char direction) +{ + ENERegisterWrite(XTREEM_REG_MODE, mode); + ENERegisterWrite(XTREEM_REG_SPEED, speed); + ENERegisterWrite(XTREEM_REG_DIRECTION, direction); + ENERegisterWrite(XTREEM_REG_APPLY, XTREEM_APPLY_VAL); +} + +unsigned char TForceXtreemController::ENERegisterRead(ene_register reg) +{ + //Write ENE register + bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); + + //Read ENE value + return(bus->i2c_smbus_read_byte_data(dev, 0x81)); +} + +void TForceXtreemController::ENERegisterWrite(ene_register reg, unsigned char val) +{ + //Write ENE register + bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); + + //Write ENE value + bus->i2c_smbus_write_byte_data(dev, 0x01, val); +} + +void TForceXtreemController::ENERegisterWriteBlock(ene_register reg, unsigned char * data, unsigned char sz) +{ + //Write ENE register + bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); + + //Write ENE block data + bus->i2c_smbus_write_block_data(dev, 0x03, sz, data); +} diff --git a/Controllers/TForceXtreemController/TForceXtreemController.h b/Controllers/TForceXtreemController/TForceXtreemController.h new file mode 100644 index 00000000..c12bd4d9 --- /dev/null +++ b/Controllers/TForceXtreemController/TForceXtreemController.h @@ -0,0 +1,111 @@ +/*---------------------------------------------------------*\ +| TForceXtreemController.h | +| | +| Driver for T-Force Xtreem DRAM | +| | +| Milan Cermak (krysmanta) 28 Dec 2024 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "RGBController.h" +#include "i2c_smbus.h" + +#define XTREEM_APPLY_VAL 0x01 /* Value for Apply Changes Register */ +#define XTREEM_LED_COUNT 15 + +typedef unsigned short ene_register; +typedef unsigned char ene_dev_id; + +enum +{ + XTREEM_REG_DIRECT = 0xE020, /* "Direct Access" Selection Register */ + XTREEM_REG_MODE = 0xE021, /* Mode Selection Register */ + XTREEM_REG_SPEED = 0xE022, /* Speed Control Register */ + XTREEM_REG_DIRECTION = 0xE023, /* Direction Control Register */ + XTREEM_REG_APPLY = 0xE02F, /* Apply Changes Register */ + XTREEM_REG_SLOT_INDEX = 0xE0F8, /* Slot Index Register (RAM only) */ + XTREEM_REG_I2C_ADDRESS = 0xE0F9, /* I2C Address Register (RAM only) */ + XTREEM_REG_COLORS_DIRECT = 0xE100, /* Colors for Direct Mode 45 bytes */ + XTREEM_REG_COLORS_EFFECT = 0xE300, /* Colors for Internal Effects 45 bytes */ +}; + +enum +{ + XTREEM_MODE_OFF = 0, /* OFF mode */ + XTREEM_MODE_STATIC = 1, /* Static color mode */ + XTREEM_MODE_BREATHING = 2, /* Breathing effect mode */ + XTREEM_MODE_FLASHING = 3, /* Flashing effect mode */ + XTREEM_MODE_SPECTRUM_CYCLE = 4, /* Spectrum Cycle mode */ + XTREEM_MODE_RAINBOW = 5, /* Rainbow effect mode */ + XTREEM_MODE_SPECTRUM_CYCLE_BREATHING = 6, /* Rainbow Breathing effect mode */ + XTREEM_MODE_CHASE_FADE = 7, /* Chase with Fade effect mode */ + XTREEM_MODE_SPECTRUM_CYCLE_CHASE_FADE = 8, /* Chase with Fade, Rainbow effect mode */ + XTREEM_MODE_CHASE = 9, /* Chase effect mode */ + XTREEM_MODE_SPECTRUM_CYCLE_CHASE = 10, /* Chase with Rainbow effect mode */ + XTREEM_MODE_SPECTRUM_CYCLE_WAVE = 11, /* Wave effect mode */ + XTREEM_MODE_CHASE_RAINBOW_PULSE = 12, /* Chase with Rainbow Pulse effect mode*/ + XTREEM_MODE_RANDOM_FLICKER = 13, /* Random flicker effect mode */ + XTREEM_MODE_STACK = 14, /* Stacking effect mode */ + XTREEM_MODE_PONG = 15, /* Pong effect mode */ + XTREEM_MODE_FILLUP = 16, /* Fill up effect mode */ + XTREEM_MODE_NEON = 17, /* Neon effect mode */ + XTREEM_MODE_COLOR_WAVE = 18, /* Color Wave effect mode */ + XTREEM_MODE_COLOR_DOUBLE_WAVE = 19, /* Color double wave effect mode */ + XTREEM_MODE_MIXER = 20, /* Mixer effect mode */ + XTREEM_MODE_SPECTRUM_CYCLE_2 = 21, /* Spectrum cycle 2 effect mode */ + XTREEM_MODE_FIRE_BREATHING = 22, /* Color shift breathing effect mode */ + XTREEM_MODE_SPECTRUM_CYCLE_3 = 23, /* Spectrum cycle 3 effect mode */ + XTREEM_MODE_SLITHER = 24, /* Slither effect mode */ + XTREEM_MODE_TFORCE_XTREEM = 25, /* Default T-Force Xtreem mode */ + XTREEM_NUMBER_MODES /* Number of Aura modes */ +}; + +enum +{ + XTREEM_SPEED_SLOWEST = 0x04, /* Slowest effect speed */ + XTREEM_SPEED_SLOW = 0x03, /* Slow effect speed */ + XTREEM_SPEED_NORMAL = 0x02, /* Normal effect speed */ + XTREEM_SPEED_FAST = 0x01, /* Fast effect speed */ + XTREEM_SPEED_FASTEST = 0x00, /* Fastest effect speed */ +}; + +enum +{ + XTREEM_DIRECTION_FORWARD = 0x0, /* Forward effect direction */ + XTREEM_DIRECTION_REVERSE = 0x1, /* Reverse effect direction */ +}; + +class TForceXtreemController +{ +public: + TForceXtreemController(i2c_smbus_interface *bus, ene_dev_id dev); + ~TForceXtreemController(); + + std::string GetDeviceLocation(); + unsigned int GetLEDCount(); + unsigned char GetLEDRed(unsigned int led); + unsigned char GetLEDGreen(unsigned int led); + unsigned char GetLEDBlue(unsigned int led); + unsigned char GetLEDRedEffect(unsigned int led); + unsigned char GetLEDGreenEffect(unsigned int led); + unsigned char GetLEDBlueEffect(unsigned int led); + void SetAllColorsDirect(RGBColor* colors); + void SetAllColorsEffect(RGBColor* colors); + void SetDirect(unsigned char direct); + void SetLEDColorDirect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue); + void SetLEDColorEffect(unsigned int led, unsigned char red, unsigned char green, unsigned char blue); + void SetMode(unsigned char mode, unsigned char speed, unsigned char direction); + + unsigned char ENERegisterRead(ene_register reg); + void ENERegisterWrite(ene_register reg, unsigned char val); + void ENERegisterWriteBlock(ene_register reg, unsigned char * data, unsigned char sz); + +private: + i2c_smbus_interface * bus; + ene_dev_id dev; +}; diff --git a/Controllers/TForceXtreemController/TForceXtreemControllerDetect.cpp b/Controllers/TForceXtreemController/TForceXtreemControllerDetect.cpp new file mode 100644 index 00000000..e5a7452b --- /dev/null +++ b/Controllers/TForceXtreemController/TForceXtreemControllerDetect.cpp @@ -0,0 +1,184 @@ +/*---------------------------------------------------------*\ +| TForceXtreemControllerDetect.cpp | +| | +| Detector for T-Force Xtreem RAM | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include "Detector.h" +#include "TForceXtreemController.h" +#include "LogManager.h" +#include "RGBController_TForceXtreem.h" +#include "i2c_smbus.h" + +#define DETECTOR_NAME "TForce Xtreem Controller" + +using namespace std::chrono_literals; + +/*----------------------------------------------------------------------*\ +| Windows defines "interface" for some reason. Work around this | +\*----------------------------------------------------------------------*/ +#ifdef interface +#undef interface +#endif + +/*----------------------------------------------------------------------*\ +| This list contains the available SMBus addresses for mapping ENE RAM | +\*----------------------------------------------------------------------*/ +#define XTREEM_RAM_ADDRESS_COUNT 13 + +static const unsigned char xtreem_ram_addresses[] = +{ + 0x70, + 0x71, + 0x72, + 0x73, + 0x74, + 0x75, + 0x76, + 0x78, + 0x39, + 0x3A, + 0x3B, + 0x3C, + 0x3D +}; + +/******************************************************************************************\ +* * +* XtreemRegisterWrite * +* * +* A standalone version of the TForceXtreemController::ENERegisterWrite function for * +* access to ENE devices without instancing the TForceXtreemController class. * +* * +\******************************************************************************************/ + +static void XtreemRegisterWrite(i2c_smbus_interface* bus, ene_dev_id dev, ene_register reg, unsigned char val) +{ + //Write ENE register + bus->i2c_smbus_write_word_data(dev, 0x00, ((reg << 8) & 0xFF00) | ((reg >> 8) & 0x00FF)); + + //Write ENE value + bus->i2c_smbus_write_byte_data(dev, 0x01, val); +} + +/******************************************************************************************\ +* * +* TestForENESMBusController * +* * +* Tests the given address to see if an ENE controller exists there. First does a * +* quick write to test for a response, and if so does a simple read at 0x90 to test * +* for incrementing values 10...1F which was observed at this location * +* * +\******************************************************************************************/ + +bool TestForTForceXtreemController(i2c_smbus_interface* bus, unsigned char address) +{ + bool pass = false; + + LOG_DEBUG("[%s] looking for devices at 0x%02X...", DETECTOR_NAME, address); + + int res = bus->i2c_smbus_read_byte(address); + + if(res < 0) + { + res = bus->i2c_smbus_read_byte_data(address, 0x00); + } + + if(res >= 0) + { + pass = true; + + LOG_DEBUG("[%s] Detected an I2C device at address %02X, testing register range", DETECTOR_NAME, address); + + for(int i = 0x90; i < 0xA1; i++) + { + res = bus->i2c_smbus_read_byte_data(address, i); + + if(res != (i - 0x80)) + { + LOG_VERBOSE("[%s] Detection failed testing register %02X. Expected %02X, got %02X.", DETECTOR_NAME, i, (i - 0x80), res); + + pass = false; + break; + } + } + } + + return(pass); + +} /* TestForTForceXtreemController() */ + +/******************************************************************************************\ +* * +* DetectTForceXtreemDRAMControllers * +* * +* Detects T-Force Xtreem controllers on DRAM devices * +* * +* bus - pointer to i2c_smbus_interface where device is connected * +* slots - SPD accessors to occupied slots * +* * +\******************************************************************************************/ + +void DetectTForceXtreemControllers(i2c_smbus_interface* bus, std::vector &slots) +{ + + LOG_DEBUG("[%s] Remapping ENE SMBus RAM modules on 0x77", DETECTOR_NAME); + + for(SPDWrapper *slot : slots) + { + int address_list_idx = slot->index() - 1; + int res; + + /*-------------------------------------------------*\ + | Full test to avoid conflicts with other ENE DRAMs | + \*-------------------------------------------------*/ + if(!TestForTForceXtreemController(bus, 0x77)) + { + LOG_DEBUG("[%s] No device detected at 0x77, aborting remap", DETECTOR_NAME); + + break; + } + + do + { + address_list_idx++; + + if(address_list_idx < XTREEM_RAM_ADDRESS_COUNT) + { + LOG_DEBUG("[%s] Testing address %02X to see if there is a device there", DETECTOR_NAME, xtreem_ram_addresses[address_list_idx]); + + res = bus->i2c_smbus_write_quick(xtreem_ram_addresses[address_list_idx], I2C_SMBUS_WRITE); + } + else + { + break; + } + } while(res >= 0); + + if(address_list_idx < XTREEM_RAM_ADDRESS_COUNT) + { + LOG_DEBUG("[%s] Remapping slot %d to address %02X", DETECTOR_NAME, slot, xtreem_ram_addresses[address_list_idx]); + + XtreemRegisterWrite(bus, 0x77, XTREEM_REG_SLOT_INDEX, slot->index()); + XtreemRegisterWrite(bus, 0x77, XTREEM_REG_I2C_ADDRESS, (xtreem_ram_addresses[address_list_idx] << 1)); + } + } + + // Add ENE controllers at their remapped addresses + for(unsigned int address_list_idx = 0; address_list_idx < XTREEM_RAM_ADDRESS_COUNT; address_list_idx++) + { + if(TestForTForceXtreemController(bus, xtreem_ram_addresses[address_list_idx])) + { + TForceXtreemController* controller = new TForceXtreemController(bus, xtreem_ram_addresses[address_list_idx]); + RGBController_TForceXtreem* rgb_controller = new RGBController_TForceXtreem(controller); + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } + } +} /* DetectTForceXtreemControllers() */ + +REGISTER_I2C_DIMM_DETECTOR("T-Force Xtreem DDR4 DRAM", DetectTForceXtreemControllers, JEDEC_TEAMGROUP, SPD_DDR4_SDRAM);