Add Zotac 30 40 series gpus

This commit is contained in:
Cooper Hall 2023-07-01 05:09:02 +00:00 committed by Adam Honse
parent ddef980db4
commit a60a273893
7 changed files with 864 additions and 0 deletions

View file

@ -0,0 +1,469 @@
/*-----------------------------------------*\
| RGBController_ZotacV2GPU.cpp |
| |
| Generic RGB Interface for OpenRGB |
| ZOTAC RTX 30/40 series GPU Driver |
| |
| Krzysztof Haładyn (krzys_h) 3/16/2023 |
\*-----------------------------------------*/
#include "RGBController_ZotacV2GPU.h"
#include "LogManager.h"
#include <map>
std::map<std::string, ZotacV2GPUConfig> ZOTAC_V2_GPU_CONFIG =
{
{ "N653E-1013", { 2, false } }, // ZOTAC GAMING GeForce RTX 3070 Ti Trinity OC
{ "N612A-1012", { 2, false } }, // ZOTAC GAMING GeForce RTX 3080 Ti AMP Holo
{ "N618A-1015", { 4, true } }, // ZOTAC GAMING GeForce RTX 3090 AMP Extreme Holo
{ "N675E-1019", { 1, true } }, // ZOTAC GAMING GeForce RTX 4090 Trinity OC
{ "N675A-1019", { 5, true } }, // ZOTAC GAMING GeForce RTX 4090 AMP Extreme AIRO
};
std::vector<std::pair<RGBColor, RGBColor>> ZOTAC_V2_GPU_DUET_PRESETS =
{
{ ToRGBColor(0x32, 0xCF, 0xA7), ToRGBColor(0x93, 0x34, 0xC2) },
{ ToRGBColor(0x00, 0xC9, 0x14), ToRGBColor(0x00, 0x20, 0xF5) },
{ ToRGBColor(0xD1, 0xFC, 0x00), ToRGBColor(0xF1, 0x0C, 0x00) },
{ ToRGBColor(0xFF, 0x68, 0x7C), ToRGBColor(0xD4, 0x00, 0x4D) },
};
/**------------------------------------------------------------------*\
@name ZOTAC 30/40 series GPU
@category GPU
@type I2C
@save :robot:
@direct :x:
@effects :tools:
@detectors DetectZotacV2GPUControllers
@comment
OpenRGB does not support per-zone effect modes, so only
the synchronized mode is supported for now. Sound based
effects are not supported. Idle/active config is not
supported.
\*-------------------------------------------------------------------*/
RGBController_ZotacV2GPU::RGBController_ZotacV2GPU(ZotacV2GPUController* controller_ptr)
{
controller = controller_ptr;
name = "ZOTAC GPU";
vendor = "ZOTAC";
description = "ZOTAC 30/40 series RGB GPU Device (" + controller->GetVersion() + ")";
location = controller->GetDeviceLocation();
type = DEVICE_TYPE_GPU;
try
{
config = ZOTAC_V2_GPU_CONFIG.at(controller->GetVersion());
}
catch(std::out_of_range)
{
LOG_ERROR("No zone config found for %s", version.c_str());
config = ZotacV2GPUConfig();
}
version += std::to_string(config.numberOfZones) + " zones, "
+ (config.supportsExternalLEDStrip ? "with" : "without") + " external LED strip support";
mode STATIC;
STATIC.name = "Static";
STATIC.value = ZOTAC_V2_GPU_MODE_STATIC;
STATIC.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
STATIC.brightness_min = 0;
STATIC.brightness_max = 100;
STATIC.brightness = 100;
STATIC.color_mode = MODE_COLORS_MODE_SPECIFIC;
STATIC.colors_min = 1;
STATIC.colors_max = 1;
STATIC.colors.resize(1);
STATIC.colors[0] = ToRGBColor(0, 0, 255);
modes.push_back(STATIC);
mode BREATH;
BREATH.name = "Breath";
BREATH.value = ZOTAC_V2_GPU_MODE_BREATH;
BREATH.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
BREATH.brightness_min = 0;
BREATH.brightness_max = 100;
BREATH.brightness = 100;
BREATH.speed_min = 0;
BREATH.speed_max = 100;
BREATH.speed = 20;
BREATH.color_mode = MODE_COLORS_MODE_SPECIFIC;
BREATH.colors_min = 1;
BREATH.colors_max = 1;
BREATH.colors.resize(1);
BREATH.colors[0] = ToRGBColor(0, 0, 255);
modes.push_back(BREATH);
mode FADE;
FADE.name = "Fade";
FADE.value = ZOTAC_V2_GPU_MODE_FADE;
FADE.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED;
FADE.speed_min = 0;
FADE.speed_max = 100;
FADE.speed = 20;
FADE.color_mode = MODE_COLORS_NONE;
modes.push_back(FADE);
mode WINK;
WINK.name = "Wink";
WINK.value = ZOTAC_V2_GPU_MODE_WINK;
WINK.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
WINK.brightness_min = 0;
WINK.brightness_max = 100;
WINK.brightness = 100;
WINK.speed_min = 0;
WINK.speed_max = 100;
WINK.speed = 20;
WINK.color_mode = MODE_COLORS_MODE_SPECIFIC;
WINK.colors_min = 1;
WINK.colors_max = 1;
WINK.colors.resize(1);
WINK.colors[0] = ToRGBColor(0, 0, 255);
modes.push_back(WINK);
if(config.numberOfZones > 1)
{
// This mode is only supported on GPUs with more than one zone,
// because it spans multiple zones.
// It's also supported in synchronized mode only (which is the only
// thing this RGBController supports for now anyway)
mode FLASH;
FLASH.name = "Flash";
FLASH.value = ZOTAC_V2_GPU_MODE_FLASH;
FLASH.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED;
FLASH.speed_min = 0;
FLASH.speed_max = 100;
FLASH.speed = 20;
FLASH.color_mode = MODE_COLORS_NONE;
modes.push_back(FLASH);
}
// (Sound activated - not supported)
//mode SHINE;
//SHINE.name = "Shine";
//SHINE.value = ZOTAC_V2_GPU_MODE_SHINE;
//SHINE.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
//SHINE.brightness_min = 0;
//SHINE.brightness_max = 100;
//SHINE.brightness = 100;
//SHINE.color_mode = MODE_COLORS_MODE_SPECIFIC;
//SHINE.colors_min = 1;
//SHINE.colors_max = 1;
//SHINE.colors.resize(1);
//SHINE.colors[0] = ToRGBColor(0, 0, 255);
//modes.push_back(SHINE);
mode RANDOM;
RANDOM.name = "Random";
RANDOM.value = ZOTAC_V2_GPU_MODE_RANDOM;
RANDOM.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
RANDOM.brightness_min = 0;
RANDOM.brightness_max = 100;
RANDOM.brightness = 100;
RANDOM.speed_min = 0;
RANDOM.speed_max = 100;
RANDOM.speed = 20;
RANDOM.color_mode = MODE_COLORS_MODE_SPECIFIC;
RANDOM.colors_min = 1;
RANDOM.colors_max = 1;
RANDOM.colors.resize(1);
RANDOM.colors[0] = ToRGBColor(0, 0, 255);
modes.push_back(RANDOM);
mode SLIDE;
SLIDE.name = "Slide";
SLIDE.value = ZOTAC_V2_GPU_MODE_SLIDE;
SLIDE.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR;
SLIDE.brightness_min = 0;
SLIDE.brightness_max = 100;
SLIDE.brightness = 100;
SLIDE.speed_min = 0;
SLIDE.speed_max = 100;
SLIDE.speed = 20;
SLIDE.color_mode = MODE_COLORS_MODE_SPECIFIC;
SLIDE.colors_min = 1;
SLIDE.colors_max = 1;
SLIDE.colors.resize(1);
SLIDE.colors[0] = ToRGBColor(0, 0, 255);
modes.push_back(SLIDE);
mode RAINBOW;
RAINBOW.name = "Rainbow";
RAINBOW.value = ZOTAC_V2_GPU_MODE_RAINBOW;
RAINBOW.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR;
RAINBOW.speed_min = 0;
RAINBOW.speed_max = 100;
RAINBOW.speed = 20;
RAINBOW.color_mode = MODE_COLORS_NONE;
modes.push_back(RAINBOW);
mode RAINBOW_CIRCUIT = RAINBOW;
RAINBOW_CIRCUIT.name = "Rainbow (circuit)";
modes.push_back(RAINBOW_CIRCUIT);
mode MARQUEE;
MARQUEE.name = "Marquee";
MARQUEE.value = ZOTAC_V2_GPU_MODE_MARQUEE;
MARQUEE.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR;
MARQUEE.brightness_min = 0;
MARQUEE.brightness_max = 100;
MARQUEE.brightness = 100;
MARQUEE.speed_min = 0;
MARQUEE.speed_max = 100;
MARQUEE.speed = 20;
MARQUEE.color_mode = MODE_COLORS_MODE_SPECIFIC;
MARQUEE.colors_min = 1;
MARQUEE.colors_max = 1;
MARQUEE.colors.resize(1);
MARQUEE.colors[0] = ToRGBColor(0, 0, 255);
modes.push_back(MARQUEE);
mode MARQUEE_CIRCUIT = MARQUEE;
MARQUEE_CIRCUIT.name = "Marquee (circuit)";
modes.push_back(MARQUEE_CIRCUIT);
mode DRIP;
DRIP.name = "Drip";
DRIP.value = ZOTAC_V2_GPU_MODE_DRIP;
DRIP.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR;
DRIP.brightness_min = 0;
DRIP.brightness_max = 100;
DRIP.brightness = 100;
DRIP.speed_min = 0;
DRIP.speed_max = 100;
DRIP.speed = 20;
DRIP.color_mode = MODE_COLORS_MODE_SPECIFIC;
DRIP.colors_min = 1;
DRIP.colors_max = 1;
DRIP.colors.resize(1);
DRIP.colors[0] = ToRGBColor(0, 0, 255);
modes.push_back(DRIP);
mode DRIP_CIRCUIT = DRIP;
DRIP_CIRCUIT.name = "Drip (circuit)";
modes.push_back(DRIP_CIRCUIT);
// (Sound activated - not supported)
//mode DANCE;
//DANCE.name = "Dance (sound activated)";
//DANCE.value = ZOTAC_V2_GPU_MODE_DANCE;
//DANCE.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR;
//DANCE.brightness_min = 0;
//DANCE.brightness_max = 100;
//DANCE.brightness = 100;
//DANCE.color_mode = MODE_COLORS_MODE_SPECIFIC;
//DANCE.colors_min = 1;
//DANCE.colors_max = 1;
//DANCE.colors.resize(1);
//DANCE.colors[0] = ToRGBColor(0, 0, 255);
//modes.push_back(DANCE);
mode DUET;
DUET.name = "Duet";
DUET.value = ZOTAC_V2_GPU_MODE_DUET;
DUET.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR;
DUET.speed_min = 0;
DUET.speed_max = 100;
DUET.speed = 20;
DUET.color_mode = MODE_COLORS_MODE_SPECIFIC;
DUET.colors_min = 2;
DUET.colors_max = 2;
DUET.colors.resize(2);
DUET.colors[0] = ZOTAC_V2_GPU_DUET_PRESETS[1].first;
DUET.colors[1] = ZOTAC_V2_GPU_DUET_PRESETS[1].second;
modes.push_back(DUET);
mode DUET_CIRCUIT = DUET;
DUET_CIRCUIT.name = "Duet (circuit)";
modes.push_back(DUET_CIRCUIT);
mode PATH;
PATH.name = "Path";
PATH.value = ZOTAC_V2_GPU_MODE_PATH;
PATH.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR;
PATH.brightness_min = 0;
PATH.brightness_max = 100;
PATH.brightness = 100;
PATH.speed_min = 0;
PATH.speed_max = 100;
PATH.speed = 20;
PATH.color_mode = MODE_COLORS_NONE;
modes.push_back(PATH);
SetupZones();
}
RGBController_ZotacV2GPU::~RGBController_ZotacV2GPU()
{
delete controller;
}
void RGBController_ZotacV2GPU::SetupZones()
{
led new_led;
new_led.name = "GPU LED";
leds.push_back(new_led);
zone new_zone;
new_zone.name = "GPU Zone";
new_zone.type = ZONE_TYPE_SINGLE;
new_zone.leds_min = 1;
new_zone.leds_max = 1;
new_zone.leds_count = 1;
new_zone.matrix_map = NULL;
zones.push_back(new_zone);
SetupColors();
SetupInitialValues();
}
void RGBController_ZotacV2GPU::SetupInitialValues()
{
/*---------------------------------------------------------*\
| Retrieve current values by reading the device |
\*---------------------------------------------------------*/
bool on;
int syncMode;
ZotacV2GPUZone zoneConfig;
// We don't support anything other than synchronized mode, so read the last
// config used in synchronized mode for idle settings.
int zoneNum = FindSynchronizedZoneNum(ZOTAC_V2_GPU_SYNC_SYNCHRONIZED);
if(!controller->GetMode(zoneNum, ZOTAC_V2_GPU_CONFIG_IDLE, syncMode, zoneConfig, on))
{
return;
}
for(unsigned int i = 0; i < modes.size(); ++i)
{
if(zoneConfig.mode != modes[i].value)
{
continue;
}
if(zoneConfig.mode == ZOTAC_V2_GPU_MODE_RAINBOW ||
zoneConfig.mode == ZOTAC_V2_GPU_MODE_MARQUEE ||
zoneConfig.mode == ZOTAC_V2_GPU_MODE_DRIP ||
zoneConfig.mode == ZOTAC_V2_GPU_MODE_DUET)
{
if((zoneConfig.circuit == ZOTAC_V2_GPU_CIRCUIT_ON) != (modes[i].name.find("(circuit)") != std::string::npos))
{
continue;
}
}
active_mode = i;
}
colors[0] = zoneConfig.color1;
if(modes[active_mode].colors.size() >= 1)
{
modes[active_mode].colors[0] = zoneConfig.color1;
}
if(modes[active_mode].colors.size() >= 2)
{
modes[active_mode].colors[1] = zoneConfig.color2;
}
modes[active_mode].speed = zoneConfig.speed;
modes[active_mode].brightness = zoneConfig.brightness;
modes[active_mode].direction = zoneConfig.direction;
SignalUpdate();
}
void RGBController_ZotacV2GPU::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_ZotacV2GPU::DeviceUpdateLEDs()
{
DeviceUpdateMode();
}
void RGBController_ZotacV2GPU::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateMode();
}
void RGBController_ZotacV2GPU::UpdateSingleLED(int /*led*/)
{
DeviceUpdateMode();
}
void RGBController_ZotacV2GPU::DeviceUpdateMode()
{
ZotacV2GPUZone zoneConfig;
zoneConfig.mode = modes[active_mode].value;
zoneConfig.color1 = modes[active_mode].colors.size() >= 1 ? modes[active_mode].colors[0] : ToRGBColor(0, 0, 0);
zoneConfig.color2 = modes[active_mode].colors.size() >= 2 ? modes[active_mode].colors[1] : ToRGBColor(0, 0, 0);
// This is probably not strictly neccessary
zoneConfig.colorPreset = 0;
if(zoneConfig.mode == ZOTAC_V2_GPU_MODE_DUET)
{
zoneConfig.colorPreset = ZOTAC_V2_GPU_DUET_PRESETS.size(); // custom
for(int i = 0; i < ZOTAC_V2_GPU_DUET_PRESETS.size(); ++i)
{
if(zoneConfig.color1 == ZOTAC_V2_GPU_DUET_PRESETS[i].first &&
zoneConfig.color2 == ZOTAC_V2_GPU_DUET_PRESETS[i].second)
{
zoneConfig.colorPreset = i;
}
}
}
zoneConfig.speed = modes[active_mode].speed;
zoneConfig.brightness = modes[active_mode].brightness;
zoneConfig.direction = modes[active_mode].direction == MODE_DIRECTION_RIGHT ? ZOTAC_V2_GPU_DIR_RIGHT : ZOTAC_V2_GPU_DIR_LEFT;
if(zoneConfig.mode == ZOTAC_V2_GPU_MODE_RAINBOW ||
zoneConfig.mode == ZOTAC_V2_GPU_MODE_MARQUEE ||
zoneConfig.mode == ZOTAC_V2_GPU_MODE_DRIP ||
zoneConfig.mode == ZOTAC_V2_GPU_MODE_DUET)
{
zoneConfig.circuit = modes[active_mode].name.find("(circuit)") != std::string::npos ? ZOTAC_V2_GPU_CIRCUIT_ON : ZOTAC_V2_GPU_CIRCUIT_OFF;
}
else
{
zoneConfig.circuit = 0;
}
int zoneNum = FindSynchronizedZoneNum(ZOTAC_V2_GPU_SYNC_SYNCHRONIZED);
controller->TurnOnOff(true);
controller->SetMode(zoneNum, ZOTAC_V2_GPU_CONFIG_IDLE, ZOTAC_V2_GPU_SYNC_SYNCHRONIZED, zoneConfig);
controller->SetMode(zoneNum, ZOTAC_V2_GPU_CONFIG_ACTIVE, ZOTAC_V2_GPU_SYNC_SYNCHRONIZED, zoneConfig);
}
int RGBController_ZotacV2GPU::FindSynchronizedZoneNum(int syncMode)
{
// Figure out the index of the zone used for ZOTAC_V2_GPU_SYNC_SYNCHRONIZED
// or ZOTAC_V2_GPU_SYNC_SYNCHRONIZED_WITH_EXTERNAL settings based on the GPU
// zone config
int lastRealZone = config.numberOfZones - 1;
if(config.supportsExternalLEDStrip)
{
lastRealZone += 1;
}
if(syncMode == ZOTAC_V2_GPU_SYNC_SYNCHRONIZED)
{
return lastRealZone + 1;
}
else if(syncMode == ZOTAC_V2_GPU_SYNC_SYNCHRONIZED_WITH_EXTERNAL)
{
assert(config.supportsExternalLEDStrip);
return lastRealZone + 2;
}
else
{
assert(false);
return 0;
}
}

View file

@ -0,0 +1,38 @@
/*-----------------------------------------*\
| RGBController_ZotacV2GPU.h |
| |
| Generic RGB Interface for OpenRGB |
| ZOTAC RTX 30/40 series GPU Driver |
| |
| Krzysztof Haładyn (krzys_h) 3/16/2023 |
\*-----------------------------------------*/
#pragma once
#include "RGBController.h"
#include "ZotacV2GPUController.h"
class RGBController_ZotacV2GPU : public RGBController
{
public:
RGBController_ZotacV2GPU(ZotacV2GPUController* controller_ptr);
~RGBController_ZotacV2GPU();
void SetupInitialValues();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
ZotacV2GPUConfig config;
private:
ZotacV2GPUController* controller;
int FindSynchronizedZoneNum(int syncMode);
};

View file

@ -0,0 +1,204 @@
/*------------------------------------------*\
| ZotacV2GPUController.cpp |
| |
| Driver for ZOTAC GeForce RTX 30/40 series |
| GPU lighting controller |
| |
| Krzysztof Haładyn (krzys_h) 3/16/2023 |
\*------------------------------------------*/
#include "ZotacV2GPUController.h"
#include "LogManager.h"
ZotacV2GPUController::ZotacV2GPUController(i2c_smbus_interface* bus, u8 dev)
{
this->bus = bus;
this->dev = dev;
if(dev)
{
ReadVersion();
}
}
ZotacV2GPUController::~ZotacV2GPUController()
{
}
std::string ZotacV2GPUController::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 ("I2C: " + return_string);
}
std::string ZotacV2GPUController::GetVersion()
{
return version;
}
bool ZotacV2GPUController::ReadVersion()
{
u8 data_pkt[] = { ZOTAC_V2_GPU_REG_RGB, 0xF1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
if(bus->i2c_write_block(dev, sizeof(data_pkt), data_pkt) < 0)
{
return false;
}
u8 rdata_pkt[I2C_SMBUS_BLOCK_MAX] = { 0x00 };
int rdata_len = sizeof(rdata_pkt);
if(bus->i2c_read_block(dev, &rdata_len, rdata_pkt) < 0)
{
return false;
}
version = std::string((char*)rdata_pkt);
return true;
}
bool ZotacV2GPUController::TurnOnOff(bool on)
{
return SendCommand(on, false, 0, 0, 0, ZotacV2GPUZone());
}
bool ZotacV2GPUController::ResetToDefaults()
{
return SendCommand(true, true, 0, 0, 0, ZotacV2GPUZone());
}
bool ZotacV2GPUController::SetMode(int zone, int idleActive, int syncMode, ZotacV2GPUZone zoneConfig)
{
// NOTE: This only works if the device is in the ON state. Otherwise, the SetMode command will behave
// like TurnOnOff(true), and the change will be ignored.
// NOTE: syncMode is per idleActive, NOT per (zone, idleActive) pair like zoneConfig is - as in,
// you can have ACTIVE in INDIVIDUAL mode and IDLE in SYNCHRONIZED mode, but you can't have
// different syncModes in different zones. The last written value is always applied, so make
// sure you don't change it accidentally between writes.
// TODO: Verify what I said above - it doesn't match the GUI, but it seems to match the NvAPISpy traces
// From the GUI it seems like syncMode should be global, period.
return SendCommand(true, false, zone, idleActive, syncMode, zoneConfig);
}
bool ZotacV2GPUController::GetMode(int zone, int idleActive, int& syncMode, ZotacV2GPUZone& zoneConfig, bool& on)
{
u8 data_pkt[] =
{
ZOTAC_V2_GPU_REG_RGB,
0xF0,
0x00,
0x00,
0x00,
(u8)idleActive,
(u8)zone,
0x00,
};
if(bus->i2c_write_block(dev, sizeof(data_pkt), data_pkt) < 0)
{
return false;
}
u8 rdata_pkt[I2C_SMBUS_BLOCK_MAX] = { 0x00 };
int rdata_len = sizeof(rdata_pkt);
if(bus->i2c_read_block(dev, &rdata_len, rdata_pkt) < 0)
{
return false;
}
bool readReset;
int readZone;
int readIdleActive;
if(!ParseCommand(on, readReset, readZone, readIdleActive, syncMode, zoneConfig))
{
return false;
}
if(readReset != 0)
{
LOG_WARNING("Reset byte was not 0?!");
}
if(readZone != zone || readIdleActive != idleActive)
{
LOG_WARNING("Got unexpected data - expected to recieve data for (%d, %d) but got for (%d, %d)", zone, idleActive, readZone, readIdleActive);
return false;
}
return true;
}
bool ZotacV2GPUController::SendCommand(bool on, bool reset, int zone, int idleActive, int syncMode, ZotacV2GPUZone zoneConfig)
{
u8 data_pkt[] =
{
ZOTAC_V2_GPU_REG_RGB,
on ? (u8)0x01 : (u8)0x00,
reset ? (u8)0x01 : (u8)0x00,
0x00,
0x00,
(u8)idleActive,
(u8)zone,
(u8)zoneConfig.mode,
(u8)RGBGetRValue(zoneConfig.color1),
(u8)RGBGetGValue(zoneConfig.color1),
(u8)RGBGetBValue(zoneConfig.color1),
(u8)zoneConfig.speed,
(u8)zoneConfig.brightness,
(u8)zoneConfig.direction,
0x00,
(u8)syncMode,
(u8)zoneConfig.circuit,
(u8)RGBGetRValue(zoneConfig.color2),
(u8)RGBGetGValue(zoneConfig.color2),
(u8)RGBGetBValue(zoneConfig.color2),
(u8)zoneConfig.colorPreset,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
};
if(bus->i2c_write_block(dev, sizeof(data_pkt), data_pkt) < 0)
{
return false;
}
return true;
}
bool ZotacV2GPUController::ParseCommand(bool& on, bool& reset, int& zone, int& idleActive, int& syncMode, ZotacV2GPUZone& zoneConfig)
{
u8 rdata_pkt[I2C_SMBUS_BLOCK_MAX] = { 0x00 };
int rdata_len = sizeof(rdata_pkt);
if(bus->i2c_read_block(dev, &rdata_len, rdata_pkt) < 0)
{
return false;
}
on = rdata_pkt[0] != 0x00;
reset = rdata_pkt[1] != 0x00;
idleActive = rdata_pkt[4];
zone = rdata_pkt[5];
zoneConfig.mode = rdata_pkt[6];
zoneConfig.color1 = ToRGBColor(rdata_pkt[7], rdata_pkt[8], rdata_pkt[9]);
zoneConfig.speed = rdata_pkt[10];
zoneConfig.brightness = rdata_pkt[11];
zoneConfig.direction = rdata_pkt[12];
syncMode = rdata_pkt[14];
zoneConfig.circuit = rdata_pkt[15];
zoneConfig.color2 = ToRGBColor(rdata_pkt[16], rdata_pkt[17], rdata_pkt[18]);
zoneConfig.colorPreset = rdata_pkt[19];
return true;
}

View file

@ -0,0 +1,106 @@
/*-----------------------------------------*\
| ZotacV2GPUController.cpp |
| |
| Definitions and types for ZOTAC GeForce |
| RTX 30/40 series GPU lighting controller |
| |
| Krzysztof Haładyn (krzys_h) 3/16/2023 |
\*-----------------------------------------*/
#include <string>
#include "i2c_smbus.h"
#include "RGBController.h"
#pragma once
enum
{
ZOTAC_V2_GPU_REG_RGB = 0xA0,
};
enum
{
ZOTAC_V2_GPU_CONFIG_IDLE = 0x00, // Config for when there is no load
ZOTAC_V2_GPU_CONFIG_ACTIVE = 0x01, // Config for when GPU is under load
};
enum
{
ZOTAC_V2_GPU_SYNC_INDIVIDUAL = 0x00, // Everything separated
ZOTAC_V2_GPU_SYNC_SYNCHRONIZED = 0x01, // All internal zones synchronized, external is separated
ZOTAC_V2_GPU_SYNC_SYNCHRONIZED_WITH_EXTERNAL = 0x02, // Everything synchronized
};
enum
{
ZOTAC_V2_GPU_MODE_STATIC = 0x00, // Basic static color
ZOTAC_V2_GPU_MODE_BREATH = 0x01, // Single color fades on and off
ZOTAC_V2_GPU_MODE_FADE = 0x02, // All colors fade through the spectrum
ZOTAC_V2_GPU_MODE_WINK = 0x03, // Single color flashes on and off
ZOTAC_V2_GPU_MODE_FLASH = 0x04, // Each zone flashes a different color (only supported in SYNCHRONIZED or SYNCHRONIZED_WITH_EXTERNAL mode)
ZOTAC_V2_GPU_MODE_SHINE = 0x05, // (Sound activated) Single color, on and off
ZOTAC_V2_GPU_MODE_RANDOM = 0x06, // Single color, random patern
ZOTAC_V2_GPU_MODE_SLIDE = 0x07, // Single color, moves one side to the other
ZOTAC_V2_GPU_MODE_RAINBOW = 0x08, // All colors move one side to the other
ZOTAC_V2_GPU_MODE_MARQUEE = 0x09, // Very similar to SLIDE effect
ZOTAC_V2_GPU_MODE_DRIP = 0x0A, // Similar to SLIDE as well, less color moves
ZOTAC_V2_GPU_MODE_DANCE = 0x0B, // (Sound activated) Single color, equalizer effect
ZOTAC_V2_GPU_MODE_DUET = 0x17, // Dual colors
ZOTAC_V2_GPU_MODE_PATH = 0x18, // Very similar to RAINBOW effect
};
enum
{
ZOTAC_V2_GPU_DIR_LEFT = 0x00,
ZOTAC_V2_GPU_DIR_RIGHT = 0x01,
};
enum
{
ZOTAC_V2_GPU_CIRCUIT_ON = 0x00,
ZOTAC_V2_GPU_CIRCUIT_OFF = 0x01,
};
struct ZotacV2GPUConfig
{
int numberOfZones = 0;
bool supportsExternalLEDStrip = false;
};
struct ZotacV2GPUZone
{
int mode = 0;
RGBColor color1 = ToRGBColor(0, 0, 0);
RGBColor color2 = ToRGBColor(0, 0, 0);
unsigned int colorPreset = 0;
unsigned int speed = 0;
unsigned int brightness = 0;
unsigned int direction = 0;
unsigned int circuit = 0;
};
class ZotacV2GPUController
{
public:
ZotacV2GPUController(i2c_smbus_interface* bus, u8 dev);
~ZotacV2GPUController();
std::string GetDeviceLocation();
std::string GetVersion();
bool TurnOnOff(bool on);
bool ResetToDefaults();
bool GetMode(int zone, int idleActive, int& syncMode, ZotacV2GPUZone& zoneConfig, bool& on);
bool SetMode(int zone, int idleActive, int syncMode, ZotacV2GPUZone zoneConfig);
private:
bool ReadVersion();
bool SendCommand(bool on, bool reset, int zone, int idleActive, int syncMode, ZotacV2GPUZone zoneConfig);
bool ParseCommand(bool& on, bool& reset, int& zone, int& idleActive, int& syncMode, ZotacV2GPUZone& zoneConfig);
i2c_smbus_interface* bus;
u8 dev;
std::string version;
};

View file

@ -0,0 +1,36 @@
#include "Detector.h"
#include "ZotacV2GPUController.h"
#include "RGBController.h"
#include "RGBController_ZotacV2GPU.h"
#include "i2c_smbus.h"
#include "pci_ids.h"
/******************************************************************************************\
* *
* DetectZotacV2GPUControllers *
* *
* Detect ZOTAC 30/40 series RGB controllers on the enumerated I2C busses *
* at address 0x49. *
* *
* bus - pointer to i2c_smbus_interface where RGB device is connected *
* dev - I2C address of RGB device *
* *
\******************************************************************************************/
void DetectZotacV2GPUControllers(i2c_smbus_interface* bus, u8 i2c_addr, const std::string& name)
{
ZotacV2GPUController* controller = new ZotacV2GPUController(bus, i2c_addr);
RGBController_ZotacV2GPU* rgb_controller = new RGBController_ZotacV2GPU(controller);
rgb_controller->name = name;
if(rgb_controller->config.numberOfZones > 0)
{
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
REGISTER_I2C_PCI_DETECTOR("ZOTAC GAMING GeForce RTX 3070 Ti Trinity OC", DetectZotacV2GPUControllers, NVIDIA_VEN, NVIDIA_RTX3070TI_DEV, ZOTAC_SUB_VEN, ZOTAC_RTX3070TI_TRINITY_SUB_DEV, 0x49);
REGISTER_I2C_PCI_DETECTOR("ZOTAC GAMING GeForce RTX 3080 Ti AMP Holo", DetectZotacV2GPUControllers, NVIDIA_VEN, NVIDIA_RTX3080TI_DEV, ZOTAC_SUB_VEN, ZOTAC_RTX3080TI_AMP_SUB_DEV, 0x49);
REGISTER_I2C_PCI_DETECTOR("ZOTAC GAMING GeForce RTX 3090 AMP Extreme Holo", DetectZotacV2GPUControllers, NVIDIA_VEN, NVIDIA_RTX3090_DEV, ZOTAC_SUB_VEN, ZOTAC_RTX3090_AMP_SUB_DEV, 0x49);
REGISTER_I2C_PCI_DETECTOR("ZOTAC GAMING GeForce RTX 4090 Trinity OC", DetectZotacV2GPUControllers, NVIDIA_VEN, NVIDIA_RTX4090_DEV, ZOTAC_SUB_VEN, ZOTAC_RTX4090_TRINITY_SUB_DEV, 0x49);
REGISTER_I2C_PCI_DETECTOR("ZOTAC GAMING GeForce RTX 4090 AMP Extreme AIRO", DetectZotacV2GPUControllers, NVIDIA_VEN, NVIDIA_RTX4090_DEV, ZOTAC_SUB_VEN, ZOTAC_RTX4090_AMP_SUB_DEV, 0x49);

View file

@ -189,6 +189,7 @@ INCLUDEPATH +=
Controllers/YeelightController/ \
Controllers/ZalmanZSyncController/ \
Controllers/ZotacTuringGPUController/ \
Controllers/ZotacV2GPUController/ \
KeyboardLayoutManager/ \
RGBController/ \
qt/
@ -734,6 +735,8 @@ HEADERS +=
Controllers/ZETKeyboardController/RGBController_ZETBladeOptical.h \
Controllers/ZotacTuringGPUController/ZotacTuringGPUController.h \
Controllers/ZotacTuringGPUController/RGBController_ZotacTuringGPU.h \
Controllers/ZotacV2GPUController/ZotacV2GPUController.h \
Controllers/ZotacV2GPUController/RGBController_ZotacV2GPU.h \
KeyboardLayoutManager/KeyboardLayoutManager.h \
RGBController/RGBController.h \
RGBController/RGBController_Dummy.h \
@ -1431,6 +1434,9 @@ SOURCES +=
Controllers/ZotacTuringGPUController/ZotacTuringGPUController.cpp \
Controllers/ZotacTuringGPUController/ZotacTuringGPUControllerDetect.cpp \
Controllers/ZotacTuringGPUController/RGBController_ZotacTuringGPU.cpp \
Controllers/ZotacV2GPUController/ZotacV2GPUController.cpp \
Controllers/ZotacV2GPUController/ZotacV2GPUControllerDetect.cpp \
Controllers/ZotacV2GPUController/RGBController_ZotacV2GPU.cpp \
KeyboardLayoutManager/KeyboardLayoutManager.cpp \
RGBController/RGBController.cpp \
RGBController/RGBController_Dummy.cpp \

View file

@ -628,6 +628,11 @@
#define ZOTAC_RTX2060S_AMP_SUB_DEV 0x5511
#define ZOTAC_RTX2070S_GAMING_SUB_DEV 0x7500
#define ZOTAC_RTX2080_AMP_SUB_DEV 0x3500
#define ZOTAC_RTX3070TI_TRINITY_SUB_DEV 0x1653
#define ZOTAC_RTX3080TI_AMP_SUB_DEV 0x2612
#define ZOTAC_RTX3090_AMP_SUB_DEV 0x1619
#define ZOTAC_RTX4090_TRINITY_SUB_DEV 0x3675
#define ZOTAC_RTX4090_AMP_SUB_DEV 0x4675
/*-----------------------------------------------------*\
| Manli Sub-Device IDs |