Files
OpenRGB/Controllers/EVGAAmpereGPUController/EVGAGPUv3Controller.cpp
2022-09-16 12:07:56 -05:00

516 lines
20 KiB
C++

/*-----------------------------------------*\
| EVGAGPUv3Controller.cpp |
| |
| Driver for EVGA GPU RGB V3 (Ampere) |
| lighting controller |
| |
| TheRogueZeta 7/15/2021 |
\*-----------------------------------------*/
#include "EVGAGPUv3Controller.h"
#include "LogManager.h"
EVGAGPUv3Controller::EVGAGPUv3Controller(i2c_smbus_interface* bus, evga_dev_id dev)
{
this->bus = bus;
this->dev = dev;
}
EVGAGPUv3Controller::~EVGAGPUv3Controller()
{
}
std::string EVGAGPUv3Controller::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);
}
void EVGAGPUv3Controller::GetDeviceModes()
{
LOG_DEBUG("[%s] Getting Zone and LED count from HW", evgaGPUName);
uint8_t data_pkt[I2C_SMBUS_BLOCK_MAX] = {};
uint8_t result = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_MODE, 10, data_pkt);
if (result == 10)
{
for(uint8_t zone = 0 ; zone < 4; zone ++)
{
zone_modes[zone] = data_pkt[zone + 1];
zone_led_count[zone] = data_pkt[zone + 5];
LOG_DEBUG("[%s] Zone %1d LED count: %02d, mode: %02d", evgaGPUName, zone + 1, zone_led_count[zone], zone_modes[zone]);
}
zone_sync = data_pkt[9];
LOG_DEBUG("[%s] Zone Sync is %1d", evgaGPUName, zone_sync);
}
else
{
LOG_DEBUG("[%s] Invalid block read result: %02d", evgaGPUName, result);
memset(zone_led_count, 0, sizeof(zone_led_count));
memset(zone_modes, 0, sizeof(zone_modes));
}
initCard();
}
std::string EVGAGPUv3Controller::GetFWVersion()
{
return(fwVersion);
}
std::string EVGAGPUv3Controller::ReadFWVersion()
{
LOG_TRACE("[%s] Getting FW from HW", evgaGPUName);
uint8_t data_pkt[I2C_SMBUS_BLOCK_MAX] = {};
std::string return_string = "";
char version[10];
uint8_t result = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_FIRMWARE, 6, data_pkt);
if (result == 6)
{
uint8_t major = data_pkt[4];
uint8_t minor = data_pkt[5];
snprintf(version, 10, "1.%02d.%02d", major, minor);
return_string.append(version);
LOG_TRACE("[%s] Firmware %s", evgaGPUName, version);
fwVersion = return_string;
return(return_string);
}
else
{
return "";
}
}
uint8_t EVGAGPUv3Controller::GetZoneMode(uint8_t zone)
{
return zone_modes[zone];
}
EVGAv3_config EVGAGPUv3Controller::GetZoneConfig(uint8_t zone, uint8_t mode)
{
EVGAv3_config zone_config;
u16_to_u8 speed16;
bool readFail = false;
zone_config.brightness = EVGA_GPU_V3_BRIGHTNESS_DEFAULT;
zone_config.direction = 0;
zone_config.numberOfColors = 0;
zone_config.speed = EVGA_GPU_V3_SPEED_GENERIC_NORMAL;
LOG_DEBUG("[%s] Retriving Zone %1d config for mode %1d from HW", evgaGPUName, zone, mode);
uint8_t data_pkt[I2C_SMBUS_BLOCK_MAX] = {};
switch (mode)
{
case EVGA_GPU_V3_MODE_STATIC:
{
uint8_t result = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + zone, 5, data_pkt);
if (result == 5)
{
//Load data
zone_config.brightness = data_pkt[1];
uint8_t red = data_pkt[2];
uint8_t green = data_pkt[3];
uint8_t blue = data_pkt[4];
zone_config.colors[0] = ToRGBColor(red, green, blue);
zone_config.numberOfColors = 1;
zone_config.speed = 0;
zone_config.direction = 0;
}
else
{
readFail = true;
}
}
break;
case EVGA_GPU_V3_MODE_BREATHING:
{
uint8_t result = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_BREATHING + zone, 10, data_pkt);
if (result == 10)
{
//Load data
zone_config.brightness = data_pkt[1];
uint8_t red1 = data_pkt[2];
uint8_t green1 = data_pkt[3];
uint8_t blue1 = data_pkt[4];
zone_config.colors[0] = ToRGBColor(red1, green1, blue1);
uint8_t red2 = data_pkt[5];
uint8_t green2 = data_pkt[6];
uint8_t blue2 = data_pkt[7];
zone_config.colors[1] = ToRGBColor(red2, green2, blue2);
zone_config.numberOfColors= (zone_config.colors[1] != 0 ) ? 2 : 1 ;
speed16.LSB = data_pkt[8];
speed16.MSB = data_pkt[9];
zone_config.speed = speed16.u16;
zone_config.direction = 0;
}
else
{
readFail = true;
}
}
break;
case EVGA_GPU_V3_MODE_RAINBOW:
case EVGA_GPU_V3_MODE_RAINBOW_WAVE:
case EVGA_GPU_V3_MODE_STAR:
{
uint8_t result = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, 4, data_pkt);
if (result == 4)
{
//Load data
zone_config.brightness = data_pkt[1];
zone_config.numberOfColors = 0;
speed16.LSB = data_pkt[2];
speed16.MSB = data_pkt[3];
zone_config.speed = speed16.u16;
}
else
{
readFail = true;
}
}
break;
case EVGA_GPU_V3_MODE_WAVE:
{
uint8_t result = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, 7, data_pkt);
if (result == 7)
{
//Load data
zone_config.brightness = data_pkt[1];
uint8_t red = data_pkt[2];
uint8_t green = data_pkt[3];
uint8_t blue = data_pkt[4];
zone_config.colors[0] = ToRGBColor(red, green, blue);
zone_config.numberOfColors = 1;
speed16.LSB = data_pkt[5];
speed16.MSB = data_pkt[6];
zone_config.speed = speed16.u16;
}
else
{
readFail = true;
}
}
break;
case EVGA_GPU_V3_MODE_COLOR_CYCLE:
case EVGA_GPU_V3_MODE_COLOR_STACK:
{
uint8_t cd_pkt[5];
if(mode == EVGA_GPU_V3_MODE_COLOR_STACK)
{
uint8_t color_count = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_COLOR_STACK_COLOR_COUNT, 5, cd_pkt);
if(color_count == 5)
{
zone_config.numberOfColors = cd_pkt[zone + 1];
}
else
{
readFail = true;
}
uint8_t direction = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_COLOR_STACK_DIRECTION, 5, cd_pkt);
if(direction == 5)
{
zone_config.direction = cd_pkt[zone + 1];
}
else
{
readFail = true;
}
}
else
{
uint8_t color_count = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_COLOR_CYCLE_COUNT, 5, cd_pkt);
if(color_count == 5)
{
zone_config.numberOfColors = cd_pkt[zone + 1];
}
else
{
readFail = true;
}
}
uint8_t result = bus->i2c_smbus_read_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, 31, data_pkt);
if (result == 31)
{
zone_config.brightness = data_pkt[1];
for(uint8_t color_index = 0; color_index < zone_config.numberOfColors; color_index++)
{
uint8_t red = data_pkt[(color_index * 4) + 2];
uint8_t green = data_pkt[(color_index * 4) + 3];
uint8_t blue = data_pkt[(color_index * 4) + 4];
zone_config.colors[color_index] = ToRGBColor(red, green, blue);
}
speed16.LSB = data_pkt[29];
speed16.MSB = data_pkt[30];
zone_config.speed = speed16.u16;
}
else
{
readFail = true;
}
}
break;
default:
break;
}
if(readFail == false)
{
LOG_TRACE("[%s] Zone %1d Brightness: 0x%02X, Colors: %1d, Speed: 0x%04X, Direction %1d.", evgaGPUName, zone, zone_config.brightness, zone_config.numberOfColors, zone_config.speed, zone_config.direction);
for(uint8_t color_index = 0; color_index < zone_config.numberOfColors; color_index++)
{
LOG_TRACE("[%s] Color Index [%2d]: 0x%06X", evgaGPUName, color_index, zone_config.colors[color_index]);
}
LOG_DEBUG("[%s] Done loading Zone %1d configuration from HW", evgaGPUName, zone);
}
else
{
zone_config.direction = 0;
zone_config.numberOfColors = 0;
for(uint8_t i = 0; i < 7; i++)
{
zone_config.colors[i] = 0;
}
LOG_DEBUG("[%s] Failed while loading Zone %1d configuration from HW", evgaGPUName, zone);
}
return zone_config;
}
void EVGAGPUv3Controller::initCard()
{
// This command needs to be sent before the card will respond to OpenRGB commands
// NvAPI_I2CWriteEx: Dev: 0x2D RegSize: 0x01 Reg: 0xB2 Size: 0x05 Data: 0x04 0xC6 0xEB 0xEA 0x15
uint8_t data_pkt[5] = {0x04, 0xC6, 0xEB, 0xEA, 0x15};
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_ENABLE, sizeof(data_pkt), data_pkt);
LOG_TRACE("[%s] Sending SW int packet", evgaGPUName);
return;
}
void EVGAGPUv3Controller::SaveConfig()
{
LOG_DEBUG("[%s] Sending save packet", evgaGPUName);
//NvAPI_I2CWriteEx: Dev: 0x2D RegSize: 0x01 Reg: 0x90 Size: 0x05 Data: 0x04 0x9E 0xEB 0x00 0x90 //Sent on close of PX1
uint8_t data_pkt[5] = {0x04, 0x9E, 0xEB, 0x00, 0x90};
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_SAVE, sizeof(data_pkt), data_pkt);
return;
}
void EVGAGPUv3Controller::ResizeARGB(uint8_t newSize)
{
if(newSize < EVGAGPUV3_LEDS_MIN)
{
newSize = EVGAGPUV3_LEDS_MIN;
}
else if(newSize > EVGAGPUV3_LEDS_MAX)
{
newSize = EVGAGPUV3_LEDS_MAX;
}
LOG_DEBUG("[%s] Resizing ARGB header with %02d size", evgaGPUName, newSize);
uint8_t data_pkt[EVGAGPUV3_MODE_PACKET_SIZE] = { 0x09, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT,
EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, newSize, EVGAGPUV3_INIT};
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_MODE, sizeof(data_pkt), data_pkt);
return;
}
void EVGAGPUv3Controller::SetAllModes(uint8_t zone_0_mode, uint8_t zone_1_mode,uint8_t zone_2_mode,uint8_t zone_3_mode, bool sync)
{
uint8_t mode_pkt[EVGAGPUV3_MODE_PACKET_SIZE] = { EVGAGPUV3_MODE_PACKET_SIZE - 1,
EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT,
EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, 0x0 };
// Hack to keep card in sync after power loss (standby) without requireing a rescan.
// To be replaced with code that calls this once upon system resume once OpenRGB
// knows about system power states.
initCard();
// Keep zone_modes in sync
zone_modes[0] = zone_0_mode;
zone_modes[1] = zone_1_mode;
zone_modes[2] = zone_2_mode;
zone_modes[3] = zone_3_mode;
// Prep packet
mode_pkt[1] = zone_0_mode;
mode_pkt[2] = zone_1_mode;
mode_pkt[3] = zone_2_mode;
mode_pkt[4] = zone_3_mode;
mode_pkt[9] = sync;
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_MODE, EVGAGPUV3_MODE_PACKET_SIZE, mode_pkt);
//LOG_TRACE("[%s] Setting all zones to mode: %02d, %2d, %2d, %2d, zone sync %1d.", evgaGPUName, zone_0_mode, zone_1_mode, zone_2_mode, zone_3_mode, sync);
}
void EVGAGPUv3Controller::SetZoneMode(uint8_t zone, uint8_t mode)
{
uint8_t mode_pkt[EVGAGPUV3_MODE_PACKET_SIZE] = { EVGAGPUV3_MODE_PACKET_SIZE - 1,
EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT,
EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, 0x0 };
// Hack to keep card in sync after power loss (standby) without requireing a rescan.
// To be replaced with code that calls this once upon system resume once OpenRGB
// knows about system power states.
initCard();
// Keep zone_modes in sync
zone_modes[zone] = mode;
// Prep packet
mode_pkt[zone + 1] = mode;
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_MODE, EVGAGPUV3_MODE_PACKET_SIZE, mode_pkt);
//LOG_TRACE("[%s] Setting individual zone %1d to mode %02d", evgaGPUName, zone, mode);
}
void EVGAGPUv3Controller::SetZone(uint8_t zone, uint8_t mode, EVGAv3_config zone_config)
{
std::string mode_name;
u16_to_u8 speed16 = { (uint16_t) zone_config.speed };
switch (mode)
{
case EVGA_GPU_V3_MODE_OFF:
break;
case EVGA_GPU_V3_MODE_STATIC:
{
uint8_t zone_pkt[5] = {EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT, EVGAGPUV3_INIT};
zone_pkt[0] = sizeof(zone_pkt) - 1;
zone_pkt[1] = zone_config.brightness;
zone_pkt[2] = RGBGetRValue(zone_config.colors[0]);
zone_pkt[3] = RGBGetGValue(zone_config.colors[0]);
zone_pkt[4] = RGBGetBValue(zone_config.colors[0]);
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + zone, sizeof(zone_pkt), zone_pkt);
}
break;
case EVGA_GPU_V3_MODE_BREATHING:
{
uint8_t zone_pkt[10];
memset(zone_pkt, EVGAGPUV3_INIT, sizeof(zone_pkt));
zone_pkt[0] = sizeof(zone_pkt) - 1;
zone_pkt[1] = zone_config.brightness;
zone_pkt[2] = RGBGetRValue(zone_config.colors[0]);
zone_pkt[3] = RGBGetGValue(zone_config.colors[0]);
zone_pkt[4] = RGBGetBValue(zone_config.colors[0]);
if(zone_config.numberOfColors == 1)
{
zone_config.colors[1] = 0;
}
zone_pkt[5] = RGBGetRValue(zone_config.colors[1]);
zone_pkt[6] = RGBGetGValue(zone_config.colors[1]);
zone_pkt[7] = RGBGetBValue(zone_config.colors[1]);
zone_pkt[8] = speed16.LSB;
zone_pkt[9] = speed16.MSB;
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, sizeof(zone_pkt), zone_pkt);
}
break;
case EVGA_GPU_V3_MODE_RAINBOW:
case EVGA_GPU_V3_MODE_RAINBOW_WAVE:
case EVGA_GPU_V3_MODE_STAR:
{
uint8_t zone_pkt[4];
memset(zone_pkt, EVGAGPUV3_INIT, sizeof(zone_pkt));
zone_pkt[0] = sizeof(zone_pkt) - 1;
zone_pkt[1] = zone_config.brightness;
zone_pkt[2] = speed16.LSB;
zone_pkt[3] = speed16.MSB;
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, sizeof(zone_pkt), zone_pkt);
}
break;
case EVGA_GPU_V3_MODE_WAVE:
{
uint8_t zone_pkt[7];
memset(zone_pkt, EVGAGPUV3_INIT, sizeof(zone_pkt));
zone_pkt[0] = sizeof(zone_pkt) - 1;
zone_pkt[1] = zone_config.brightness;
zone_pkt[2] = RGBGetRValue(zone_config.colors[0]);
zone_pkt[3] = RGBGetGValue(zone_config.colors[0]);
zone_pkt[4] = RGBGetBValue(zone_config.colors[0]);
zone_pkt[5] = speed16.LSB;
zone_pkt[6] = speed16.MSB;
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, sizeof(zone_pkt), zone_pkt);
}
break;
case EVGA_GPU_V3_MODE_COLOR_CYCLE:
case EVGA_GPU_V3_MODE_COLOR_STACK:
{
uint8_t zone_pkt[31];;
memset(zone_pkt, EVGAGPUV3_INIT, sizeof(zone_pkt));
uint8_t color_cnt_pkt[5];
memset(color_cnt_pkt, EVGAGPUV3_INIT, sizeof(color_cnt_pkt));
// Zone packet construction
zone_pkt[0] = sizeof(zone_pkt) - 1;
for(uint8_t color_index = 0; color_index < zone_config.numberOfColors; color_index++)
{
zone_pkt[1 + color_index * 4] = zone_config.brightness;
zone_pkt[2 + color_index * 4] = RGBGetRValue(zone_config.colors[color_index]);
zone_pkt[3 + color_index * 4] = RGBGetGValue(zone_config.colors[color_index]);
zone_pkt[4 + color_index * 4] = RGBGetBValue(zone_config.colors[color_index]);
}
zone_pkt[29] = speed16.LSB;
zone_pkt[30] = speed16.MSB;
// Color Count packet construction
color_cnt_pkt[0] = sizeof(color_cnt_pkt) - 1;
color_cnt_pkt[zone+1] = zone_config.numberOfColors;
if(mode == EVGA_GPU_V3_MODE_COLOR_STACK)
{
uint8_t direction_pkt[5];
memset(direction_pkt, EVGAGPUV3_INIT, sizeof(direction_pkt));
// Direction packet construction
direction_pkt[0] = sizeof(direction_pkt) - 1;
direction_pkt[zone+1] = zone_config.direction;
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, sizeof(zone_pkt), zone_pkt);
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_COLOR_STACK_COLOR_COUNT, sizeof(color_cnt_pkt), color_cnt_pkt);
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_COLOR_STACK_DIRECTION, sizeof(direction_pkt), direction_pkt);
}
else
{
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_STATIC + ((mode -1) * 4) + zone, sizeof(zone_pkt), zone_pkt);
bus->i2c_smbus_write_i2c_block_data(dev, EVGA_GPU_V3_REG_COLOR_CYCLE_COUNT, sizeof(color_cnt_pkt), color_cnt_pkt);
}
}
break;
default:
{
LOG_TRACE("[%s] Mode %02d not found", evgaGPUName, mode);
}
break;
}
}