Support for Kingston Fury DDR4/5 DIMMs
This commit is contained in:
parent
6fdcca3ca1
commit
c366de98e7
5 changed files with 1510 additions and 0 deletions
|
|
@ -0,0 +1,347 @@
|
|||
/*---------------------------------------------------------*\
|
||||
| KingstonFuryDRAMController.cpp |
|
||||
| |
|
||||
| Driver for Kingston Fury DDR4/5 RAM modules |
|
||||
| |
|
||||
| Geofrey Mon (geofbot) 14 Jul 2024 |
|
||||
| Milan Cermak (krysmanta) |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "KingstonFuryDRAMController.h"
|
||||
#include "RGBController.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
KingstonFuryDRAMController::KingstonFuryDRAMController(
|
||||
i2c_smbus_interface* bus, unsigned char base_addr, std::vector<int> slots)
|
||||
{
|
||||
this->bus = bus;
|
||||
this->base_addr = base_addr;
|
||||
this->slots = slots;
|
||||
|
||||
reg_cache.resize(slots.size());
|
||||
}
|
||||
|
||||
std::string KingstonFuryDRAMController::GetDeviceLocation()
|
||||
{
|
||||
std::string return_string(bus->device_name);
|
||||
return_string.append(", addresses [");
|
||||
for(std::size_t idx = 0; idx < slots.size(); idx++)
|
||||
{
|
||||
char addr[5];
|
||||
snprintf(addr, 5, "0x%02X", base_addr + slots[idx]);
|
||||
return_string.append(addr);
|
||||
if(idx < slots.size() - 1)
|
||||
{
|
||||
return_string.append(",");
|
||||
}
|
||||
else
|
||||
{
|
||||
return_string.append("]");
|
||||
}
|
||||
}
|
||||
return("I2C: " + return_string);
|
||||
}
|
||||
|
||||
unsigned KingstonFuryDRAMController::GetLEDCount()
|
||||
{
|
||||
return GetLEDPerDIMM() * slots.size();
|
||||
}
|
||||
|
||||
unsigned int KingstonFuryDRAMController::GetSlotCount()
|
||||
{
|
||||
return slots.size();
|
||||
}
|
||||
|
||||
unsigned char KingstonFuryDRAMController::GetMode()
|
||||
{
|
||||
unsigned char mode = 0;
|
||||
CachedRead(0, FURY_REG_MODE, &mode);
|
||||
return mode;
|
||||
}
|
||||
|
||||
bool KingstonFuryDRAMController::SmbusRead(int slot_idx, unsigned char reg, unsigned char *val)
|
||||
{
|
||||
if(val == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char device_addr = base_addr + slots[slot_idx];
|
||||
int res;
|
||||
|
||||
for(int retries = 1; retries <= 5; retries++)
|
||||
{
|
||||
res = bus->i2c_smbus_read_word_data(device_addr, reg);
|
||||
if(res >= 0)
|
||||
{
|
||||
*val = (res >> 8) & 0xff;
|
||||
LOG_DEBUG("[%s] %02X reading register &%02X=%02X; res=%02X",
|
||||
FURY_CONTROLLER_NAME, device_addr, reg, *val, res);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(3 * retries * FURY_DELAY);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool KingstonFuryDRAMController::SmbusWrite(int slot_idx, unsigned char reg, unsigned char val)
|
||||
{
|
||||
unsigned char device_addr = base_addr + slots[slot_idx];
|
||||
int res;
|
||||
|
||||
for(int retries = 1; retries <= 5; retries++)
|
||||
{
|
||||
res = bus->i2c_smbus_write_byte_data(device_addr,
|
||||
reg, val);
|
||||
LOG_DEBUG("[%s] %02X setting register &%02X=%02X; res=%02X",
|
||||
FURY_CONTROLLER_NAME, device_addr, reg, val, res);
|
||||
if(res >= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::this_thread::sleep_for(3 * retries * FURY_DELAY);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns whether a read was successful
|
||||
bool KingstonFuryDRAMController::CachedRead(int slot_idx, unsigned char reg, unsigned char *val)
|
||||
{
|
||||
if(val == NULL)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned char device_addr = base_addr + slots[slot_idx];
|
||||
if(reg_cache[slot_idx].find(reg) == reg_cache[slot_idx].end())
|
||||
{
|
||||
if(SmbusRead(slot_idx, reg, val))
|
||||
{
|
||||
reg_cache[slot_idx][reg] = *val;
|
||||
return true;
|
||||
}
|
||||
LOG_ERROR("[%s] %02X failed to get register &%02X",
|
||||
FURY_CONTROLLER_NAME, device_addr, reg);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
*val = reg_cache[slot_idx][reg];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// returns whether a write was actually performed
|
||||
bool KingstonFuryDRAMController::CachedWrite(int slot_idx, unsigned char reg, unsigned char val)
|
||||
{
|
||||
unsigned char device_addr = base_addr + slots[slot_idx];
|
||||
if(reg_cache[slot_idx].find(reg) == reg_cache[slot_idx].end() ||
|
||||
reg_cache[slot_idx][reg] != val)
|
||||
{
|
||||
if(SmbusWrite(slot_idx, reg, val))
|
||||
{
|
||||
reg_cache[slot_idx][reg] = val;
|
||||
return true;
|
||||
}
|
||||
LOG_ERROR("[%s] %02X failed to set register &%02X=%02X",
|
||||
FURY_CONTROLLER_NAME, device_addr, reg, val);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG_DEBUG("[%s] %02X register already set &%02X=%02X",
|
||||
FURY_CONTROLLER_NAME, device_addr, reg, val);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SendPreamble(bool synchronize)
|
||||
{
|
||||
SendBegin();
|
||||
|
||||
for(std::size_t idx = 0; idx < slots.size(); idx++)
|
||||
{
|
||||
char written_index = 0;
|
||||
#ifdef FURY_SYNC
|
||||
if(!synchronize)
|
||||
{
|
||||
// some modes set all indices to 0 so that the
|
||||
// individual sticks don't sync with each other
|
||||
written_index = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*--------------------------------------------------------------*\
|
||||
| The index tells physical location of the RAM slot |
|
||||
| from the border to the CPU slot. On most motherboards, |
|
||||
| the address relates to the slot location, |
|
||||
| but there are exceptions. |
|
||||
| The official software writes the indices in decreasing order. |
|
||||
| |
|
||||
| Hardware effects seem to support only up to 4 sticks. |
|
||||
| So we give the first 4 and last 4 sticks separate numbering. |
|
||||
\*--------------------------------------------------------------*/
|
||||
written_index = idx % 4;
|
||||
}
|
||||
#endif
|
||||
LOG_DEBUG("[%s] %02X writing index %d",
|
||||
FURY_CONTROLLER_NAME, base_addr + slots[idx],
|
||||
written_index);
|
||||
SmbusWrite(idx, FURY_REG_INDEX, written_index);
|
||||
}
|
||||
// The RGB controller is a bit slow and requires delay;
|
||||
// however, we can delay once for all of the sticks instead of
|
||||
// delaying individually for each stick.
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
|
||||
SendApply();
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SendBegin()
|
||||
{
|
||||
for(std::size_t idx = 0; idx < slots.size(); idx++)
|
||||
{
|
||||
LOG_DEBUG("[%s] %02X beginning transaction",
|
||||
FURY_CONTROLLER_NAME, base_addr + slots[idx]);
|
||||
SmbusWrite(idx, FURY_REG_APPLY, FURY_BEGIN_TRNSFER);
|
||||
}
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SendApply()
|
||||
{
|
||||
for(std::size_t idx = 0; idx < slots.size(); idx++)
|
||||
{
|
||||
LOG_DEBUG("[%s] %02X ending transaction",
|
||||
FURY_CONTROLLER_NAME, base_addr + slots[idx]);
|
||||
SmbusWrite(idx, FURY_REG_APPLY, FURY_END_TRNSFER);
|
||||
}
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SetMode(unsigned char val)
|
||||
{
|
||||
SetRegister(FURY_REG_MODE, val);
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SetNumSlots()
|
||||
{
|
||||
if(slots.size() <= 4)
|
||||
{
|
||||
SetRegister(FURY_REG_NUM_SLOTS, slots.size());
|
||||
}
|
||||
else
|
||||
{
|
||||
// hardware effects seem to only support at most 4 slots;
|
||||
// if there are >= 4 slots, then essentially the first 4 slots
|
||||
// run their effects independent of the last 4 slots
|
||||
SetRegister(FURY_REG_NUM_SLOTS, 4);
|
||||
}
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SetRegister(int reg, unsigned char val)
|
||||
{
|
||||
bool write_occurred = false;
|
||||
for(std::size_t idx = 0; idx < slots.size(); idx++)
|
||||
{
|
||||
write_occurred = CachedWrite(idx, reg, val) || write_occurred;
|
||||
}
|
||||
if(write_occurred)
|
||||
{
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SetRegister(int reg, std::vector<unsigned char> vals)
|
||||
{
|
||||
bool write_occurred = false;
|
||||
if(vals.size() < slots.size())
|
||||
{
|
||||
LOG_ERROR("[%s] vector of values has wrong size when setting register &%02X",
|
||||
FURY_CONTROLLER_NAME, reg);
|
||||
return;
|
||||
}
|
||||
for(std::size_t idx = 0; idx < slots.size(); idx++)
|
||||
{
|
||||
write_occurred = CachedWrite(idx, reg, vals[idx]) || write_occurred;
|
||||
}
|
||||
if(write_occurred)
|
||||
{
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
}
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SetModeColors(std::vector<RGBColor> colors)
|
||||
{
|
||||
if(colors.empty() || colors.size() > FURY_MAX_MODE_COLORS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
SetRegister(FURY_REG_NUM_COLORS, colors.size());
|
||||
for(std::size_t idx = 0; idx < colors.size(); idx++)
|
||||
{
|
||||
RGBColor color = colors[idx];
|
||||
unsigned char red = RGBGetRValue(color);
|
||||
unsigned char green = RGBGetGValue(color);
|
||||
unsigned char blue = RGBGetBValue(color);
|
||||
|
||||
int red_idx = FURY_REG_MODE_BASE_RED + idx * 3;
|
||||
int green_idx = FURY_REG_MODE_BASE_GREEN + idx * 3;
|
||||
int blue_idx = FURY_REG_MODE_BASE_BLUE + idx * 3;
|
||||
SetRegister(red_idx, red);
|
||||
SetRegister(green_idx, green);
|
||||
SetRegister(blue_idx, blue);
|
||||
}
|
||||
}
|
||||
|
||||
void KingstonFuryDRAMController::SetLEDColors(std::vector<RGBColor> colors)
|
||||
{
|
||||
if(colors.size() != GetLEDCount())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int led_per_dimm = GetLEDPerDIMM();
|
||||
for(unsigned int led_idx = 0; led_idx < led_per_dimm; led_idx++)
|
||||
{
|
||||
int red_register = FURY_REG_BASE_RED + 3 * led_idx;
|
||||
int green_register = FURY_REG_BASE_GREEN + 3 * led_idx;
|
||||
int blue_register = FURY_REG_BASE_BLUE + 3 * led_idx;
|
||||
|
||||
std::vector<unsigned char> reds, greens, blues;
|
||||
for(std::size_t slot_idx = 0; slot_idx < GetSlotCount(); slot_idx++)
|
||||
{
|
||||
RGBColor color = colors[slot_idx * led_per_dimm + led_idx];
|
||||
unsigned char red = RGBGetRValue(color);
|
||||
unsigned char green = RGBGetGValue(color);
|
||||
unsigned char blue = RGBGetBValue(color);
|
||||
reds.push_back(red);
|
||||
greens.push_back(green);
|
||||
blues.push_back(blue);
|
||||
}
|
||||
|
||||
SetRegister(red_register, reds);
|
||||
SetRegister(blue_register, blues);
|
||||
SetRegister(green_register, greens);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int KingstonFuryDRAMController::GetLEDPerDIMM()
|
||||
{
|
||||
if(base_addr == FURY_BASE_ADDR_DDR4)
|
||||
{
|
||||
return FURY_LEDS_PER_DIMM_DDR4;
|
||||
}
|
||||
return FURY_LEDS_PER_DIMM_DDR5;
|
||||
}
|
||||
|
|
@ -0,0 +1,155 @@
|
|||
/*---------------------------------------------------------*\
|
||||
| KingstonFuryDRAMController.h |
|
||||
| |
|
||||
| Driver for Kingston Fury DDR4/5 RAM modules |
|
||||
| |
|
||||
| Geofrey Mon (geofbot) 14 Jul 2024 |
|
||||
| Milan Cermak (krysmanta) |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "i2c_smbus.h"
|
||||
#include "RGBController.h"
|
||||
|
||||
#define FURY_CONTROLLER_NAME "Kingston Fury DDR4/5 DRAM"
|
||||
#define FURY_BASE_ADDR_DDR4 0x58
|
||||
#define FURY_BASE_ADDR_DDR5 0x60
|
||||
#define FURY_DELAY std::chrono::milliseconds(10)
|
||||
#define FURY_MAX_SLOTS 8
|
||||
#define FURY_LEDS_PER_DIMM_DDR4 10
|
||||
#define FURY_LEDS_PER_DIMM_DDR5 12
|
||||
#define FURY_MAX_MODE_COLORS 10
|
||||
#define FURY_DEFAULT_BG_COLOR ToRGBColor(16,16,16)
|
||||
#define FURY_ALT_DIRECTIONS {\
|
||||
FURY_DIR_BOTTOM_TO_TOP,\
|
||||
FURY_DIR_TOP_TO_BOTTOM,\
|
||||
FURY_DIR_BOTTOM_TO_TOP,\
|
||||
FURY_DIR_TOP_TO_BOTTOM,\
|
||||
FURY_DIR_BOTTOM_TO_TOP,\
|
||||
FURY_DIR_TOP_TO_BOTTOM,\
|
||||
FURY_DIR_BOTTOM_TO_TOP,\
|
||||
FURY_DIR_TOP_TO_BOTTOM}
|
||||
|
||||
enum
|
||||
{
|
||||
FURY_MODEL_BEAST_DDR5 = 0x10,
|
||||
FURY_MODEL_RENEGADE_DDR5 = 0x11,
|
||||
FURY_MODEL_BEAST_WHITE_DDR4 = 0x21,
|
||||
FURY_MODEL_BEAST_DDR4 = 0x23,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FURY_REG_MODEL = 0x06,
|
||||
FURY_REG_APPLY = 0x08,
|
||||
FURY_REG_MODE = 0x09,
|
||||
FURY_REG_INDEX = 0x0B,
|
||||
FURY_REG_DIRECTION = 0x0C,
|
||||
FURY_REG_DELAY = 0x0D,
|
||||
FURY_REG_SPEED = 0x0E,
|
||||
FURY_REG_DYNAMIC_HOLD_A = 0x12,
|
||||
FURY_REG_DYNAMIC_HOLD_B = 0x13,
|
||||
FURY_REG_DYNAMIC_FADE_A = 0x14,
|
||||
FURY_REG_DYNAMIC_FADE_B = 0x15,
|
||||
FURY_REG_BREATH_MIN_TO_MID = 0x16,
|
||||
FURY_REG_BREATH_MID_TO_MAX = 0x17,
|
||||
FURY_REG_BREATH_MAX_TO_MID = 0x18,
|
||||
FURY_REG_BREATH_MID_TO_MIN = 0x19,
|
||||
FURY_REG_BREATH_MIN_HOLD = 0x1A,
|
||||
FURY_REG_BREATH_MAX_BRIGHTNESS = 0x1B,
|
||||
FURY_REG_BREATH_MID_BRIGHTNESS = 0x1C,
|
||||
FURY_REG_BREATH_MIN_BRIGHTNESS = 0x1D,
|
||||
FURY_REG_BRIGHTNESS = 0x20,
|
||||
FURY_REG_BG_RED = 0x23,
|
||||
FURY_REG_BG_GREEN = 0x24,
|
||||
FURY_REG_BG_BLUE = 0x25,
|
||||
FURY_REG_LENGTH = 0x26,
|
||||
FURY_REG_NUM_SLOTS = 0x27,
|
||||
FURY_REG_NUM_COLORS = 0x30,
|
||||
FURY_REG_MODE_BASE_RED = 0x31,
|
||||
FURY_REG_MODE_BASE_GREEN = 0x32,
|
||||
FURY_REG_MODE_BASE_BLUE = 0x33,
|
||||
FURY_REG_BASE_RED = 0x50,
|
||||
FURY_REG_BASE_GREEN = 0x51,
|
||||
FURY_REG_BASE_BLUE = 0x52,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FURY_BEGIN_TRNSFER = 0x53,
|
||||
FURY_END_TRNSFER = 0x44,
|
||||
};
|
||||
|
||||
// Differentiate modes which use the same written value using the upper bytes.
|
||||
// The lowest order byte is generally the value written to the mode register.
|
||||
enum
|
||||
{
|
||||
FURY_MODE_STATIC = 0x00,
|
||||
FURY_MODE_RAINBOW = 0x001,
|
||||
FURY_MODE_SPECTRUM = 0x101,
|
||||
FURY_MODE_RHYTHM = 0x02,
|
||||
FURY_MODE_BREATH = 0x03,
|
||||
FURY_MODE_DYNAMIC = 0x04,
|
||||
FURY_MODE_SLIDE = 0x005,
|
||||
FURY_MODE_SLITHER = 0x105,
|
||||
FURY_MODE_TELEPORT = 0x205,
|
||||
FURY_MODE_WIND = 0x305,
|
||||
FURY_MODE_COMET = 0x006,
|
||||
FURY_MODE_RAIN = 0x106,
|
||||
FURY_MODE_FIREWORK = 0x206,
|
||||
FURY_MODE_VOLTAGE = 0x07,
|
||||
FURY_MODE_COUNTDOWN = 0x08,
|
||||
FURY_MODE_FLAME = 0x09,
|
||||
FURY_MODE_TWILIGHT = 0x0A,
|
||||
FURY_MODE_FURY = 0x0B,
|
||||
FURY_MODE_DIRECT = 0x10,
|
||||
FURY_MODE_PRISM = 0x11,
|
||||
FURY_MODE_BREATH_DIRECT = 0x13,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
FURY_DIR_BOTTOM_TO_TOP = 0x01,
|
||||
FURY_DIR_TOP_TO_BOTTOM = 0x02,
|
||||
};
|
||||
|
||||
class KingstonFuryDRAMController
|
||||
{
|
||||
public:
|
||||
KingstonFuryDRAMController(i2c_smbus_interface* bus, unsigned char base_addr, std::vector<int> slots);
|
||||
|
||||
std::string GetDeviceLocation();
|
||||
unsigned int GetLEDCount();
|
||||
unsigned int GetLEDPerDIMM();
|
||||
unsigned int GetSlotCount();
|
||||
unsigned char GetMode();
|
||||
|
||||
void SendPreamble(bool synchronize);
|
||||
void SendBegin();
|
||||
void SendApply();
|
||||
void SetMode(unsigned char val);
|
||||
void SetNumSlots();
|
||||
|
||||
void SetRegister(int reg, unsigned char val);
|
||||
void SetRegister(int reg, std::vector<unsigned char> vals);
|
||||
void SetModeColors(std::vector<RGBColor> colors);
|
||||
void SetLEDColors(std::vector<RGBColor> colors);
|
||||
|
||||
private:
|
||||
bool CachedRead(int slot_idx, unsigned char reg, unsigned char *val);
|
||||
bool CachedWrite(int slot_idx, unsigned char reg, unsigned char val);
|
||||
bool SmbusRead(int slot_idx, unsigned char reg, unsigned char *val);
|
||||
bool SmbusWrite(int slot_idx, unsigned char reg, unsigned char val);
|
||||
|
||||
i2c_smbus_interface* bus;
|
||||
std::vector<int> slots;
|
||||
unsigned char base_addr;
|
||||
std::vector<std::map<unsigned char, unsigned char>> reg_cache;
|
||||
};
|
||||
|
|
@ -0,0 +1,226 @@
|
|||
/*---------------------------------------------------------*\
|
||||
| KingstonFuryDRAMControllerDetect.cpp |
|
||||
| |
|
||||
| Detection of Kingston Fury DDR4/5 RAM modules |
|
||||
| |
|
||||
| Geofrey Mon (geofbot) 14 Jul 2024 |
|
||||
| Milan Cermak (krysmanta) |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <bitset>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
#include "Detector.h"
|
||||
#include "KingstonFuryDRAMController.h"
|
||||
#include "LogManager.h"
|
||||
#include "RGBController.h"
|
||||
#include "RGBController_KingstonFuryDRAM.h"
|
||||
#include "i2c_smbus.h"
|
||||
#include "pci_ids.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RESULT_PASS = 0,
|
||||
RESULT_FAIL = 1,
|
||||
RESULT_ERROR = 2
|
||||
} TestResult;
|
||||
|
||||
TestResult TestForFurySlot(i2c_smbus_interface *bus, unsigned int slot_addr, bool (*modelChecker)(char))
|
||||
{
|
||||
char model_code = 0;
|
||||
int res = bus->i2c_smbus_write_quick(slot_addr, I2C_SMBUS_WRITE);
|
||||
|
||||
LOG_DEBUG("[%s] Probing address %02X, res=%02X", FURY_CONTROLLER_NAME, slot_addr, res);
|
||||
if(res < 0)
|
||||
{
|
||||
return RESULT_FAIL;
|
||||
}
|
||||
|
||||
// Get the model code
|
||||
res = bus->i2c_smbus_read_word_data(slot_addr, FURY_REG_MODEL);
|
||||
if(res < 0)
|
||||
{
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
model_code = res >> 8;
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
LOG_DEBUG("[%s] Reading model code at address %02X register %02X, res=%02X",
|
||||
FURY_CONTROLLER_NAME, slot_addr, FURY_REG_MODEL, model_code);
|
||||
|
||||
if(!modelChecker(model_code))
|
||||
{
|
||||
LOG_DEBUG("[%s] Unknown model code 0x%02X", FURY_CONTROLLER_NAME, model_code);
|
||||
return RESULT_FAIL;
|
||||
}
|
||||
return RESULT_PASS;
|
||||
}
|
||||
|
||||
bool TestDDR4Models(char code)
|
||||
{
|
||||
return (code == FURY_MODEL_BEAST_WHITE_DDR4 ||
|
||||
code == FURY_MODEL_BEAST_DDR4);
|
||||
}
|
||||
|
||||
bool TestDDR5Models(char code)
|
||||
{
|
||||
return (code == FURY_MODEL_BEAST_DDR5 ||
|
||||
code == FURY_MODEL_RENEGADE_DDR5);
|
||||
}
|
||||
|
||||
// Checking Fury signature in the RGB address space
|
||||
TestResult TestForFurySignature(i2c_smbus_interface *bus, unsigned int slot_addr)
|
||||
{
|
||||
bool passed = true;
|
||||
char test_str[] = "FURY";
|
||||
int res;
|
||||
|
||||
// Start transaction
|
||||
res = bus->i2c_smbus_write_byte_data(slot_addr, FURY_REG_APPLY, FURY_BEGIN_TRNSFER);
|
||||
if(res < 0)
|
||||
{
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
LOG_DEBUG("[%s] %02X beginning transaction; res=%02X",
|
||||
FURY_CONTROLLER_NAME, slot_addr, res);
|
||||
|
||||
// Read and check the signature
|
||||
for(int i = 1; i <= 4; i++)
|
||||
{
|
||||
for(int retry = 3; retry > 0; retry--)
|
||||
{
|
||||
res = bus->i2c_smbus_read_word_data(slot_addr, i);
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
if(res >= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(res < 0)
|
||||
{
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
|
||||
char shifted = (res >> 8) & 0xff;
|
||||
LOG_DEBUG("[%s] Testing address %02X register %02X, res=%02X",
|
||||
FURY_CONTROLLER_NAME, slot_addr, i, shifted);
|
||||
if(shifted != test_str[i-1])
|
||||
{
|
||||
passed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Close transaction
|
||||
res = bus->i2c_smbus_write_byte_data(slot_addr, FURY_REG_APPLY, FURY_END_TRNSFER);
|
||||
if(res < 0)
|
||||
{
|
||||
return RESULT_ERROR;
|
||||
}
|
||||
std::this_thread::sleep_for(FURY_DELAY);
|
||||
LOG_DEBUG("[%s] %02X ending transaction; res=%02X",
|
||||
FURY_CONTROLLER_NAME, slot_addr, res);
|
||||
|
||||
if(!passed)
|
||||
{
|
||||
return RESULT_FAIL;
|
||||
}
|
||||
return RESULT_PASS;
|
||||
}
|
||||
|
||||
/******************************************************************************************\
|
||||
* *
|
||||
* DetectKingstonFuryDRAMControllers *
|
||||
* *
|
||||
* Detect Kingston Fury DDR4/5 DRAM controllers on the enumerated I2C busses. *
|
||||
* *
|
||||
\******************************************************************************************/
|
||||
|
||||
void DetectKingstonFuryDRAMControllers(std::vector<i2c_smbus_interface*> &busses)
|
||||
{
|
||||
enum { FURY_UNKNOWN, FURY_DDR4, FURY_DDR5 } fury_type = FURY_UNKNOWN;
|
||||
|
||||
for(unsigned int bus = 0; bus < busses.size(); bus++)
|
||||
{
|
||||
IF_DRAM_SMBUS(busses[bus]->pci_vendor, busses[bus]->pci_device)
|
||||
{
|
||||
std::vector<int> slots;
|
||||
for(int slot_index = 0; slot_index < FURY_MAX_SLOTS; slot_index++)
|
||||
{
|
||||
int retries = 0;
|
||||
TestResult result = RESULT_ERROR;
|
||||
while(retries < 3 && result == RESULT_ERROR)
|
||||
{
|
||||
// Check for DDR4 module (no point, if we already found DDR5 module)
|
||||
if(fury_type != FURY_DDR5)
|
||||
{
|
||||
result = TestForFurySlot(busses[bus],
|
||||
FURY_BASE_ADDR_DDR4 + slot_index, TestDDR4Models);
|
||||
if(result == RESULT_PASS)
|
||||
{
|
||||
result = TestForFurySignature(busses[bus],
|
||||
FURY_BASE_ADDR_DDR4 + slot_index);
|
||||
}
|
||||
if(result == RESULT_PASS)
|
||||
{
|
||||
fury_type = FURY_DDR4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Check for DDR5 module (no point, if we already found DDR4 module)
|
||||
if(fury_type != FURY_DDR4 && result != RESULT_PASS)
|
||||
{
|
||||
result = TestForFurySlot(busses[bus],
|
||||
FURY_BASE_ADDR_DDR5 + slot_index, TestDDR5Models);
|
||||
if(result == RESULT_PASS)
|
||||
{
|
||||
result = TestForFurySignature(busses[bus],
|
||||
FURY_BASE_ADDR_DDR5 + slot_index);
|
||||
}
|
||||
if(result == RESULT_PASS)
|
||||
{
|
||||
fury_type = FURY_DDR5;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(result == RESULT_ERROR)
|
||||
{
|
||||
// I/O error - wait for a bit and retry
|
||||
retries++;
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
}
|
||||
|
||||
// RAM module successfully detected in the slot 'slot_index'
|
||||
if(result == RESULT_PASS)
|
||||
{
|
||||
LOG_DEBUG("[%s] detected at slot index %d",
|
||||
FURY_CONTROLLER_NAME, slot_index);
|
||||
slots.push_back(slot_index);
|
||||
}
|
||||
}
|
||||
|
||||
if(!slots.empty() && fury_type != FURY_UNKNOWN)
|
||||
{
|
||||
unsigned char base_addr =
|
||||
(fury_type == FURY_DDR4) ? FURY_BASE_ADDR_DDR4 : FURY_BASE_ADDR_DDR5;
|
||||
KingstonFuryDRAMController* controller =
|
||||
new KingstonFuryDRAMController(busses[bus], base_addr, slots);
|
||||
RGBController_KingstonFuryDRAM* rgb_controller =
|
||||
new RGBController_KingstonFuryDRAM(controller);
|
||||
rgb_controller->name =
|
||||
(fury_type == FURY_DDR4) ? "Kingston Fury DDR4 RGB" : "Kingston Fury DDR5 RGB";
|
||||
ResourceManager::get()->RegisterRGBController(rgb_controller);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
REGISTER_I2C_DETECTOR("Kingston Fury DDR4/5 DRAM", DetectKingstonFuryDRAMControllers);
|
||||
|
|
@ -0,0 +1,746 @@
|
|||
/*---------------------------------------------------------*\
|
||||
| RGBController_KingstonFuryDRAM.cpp |
|
||||
| |
|
||||
| Driver for Kingston Fury DDR4/5 RAM modules |
|
||||
| |
|
||||
| Geofrey Mon (geofbot) 14 Jul 2024 |
|
||||
| Milan Cermak (krysmanta) |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include "RGBController_KingstonFuryDRAM.h"
|
||||
#include "KingstonFuryDRAMController.h"
|
||||
#include "LogManager.h"
|
||||
|
||||
const RGBColor default_colors[] =
|
||||
{
|
||||
ToRGBColor(0xFF, 0x00, 0x00),
|
||||
ToRGBColor(0x00, 0xFF, 0x00),
|
||||
ToRGBColor(0xFF, 0x64, 0x00),
|
||||
ToRGBColor(0x00, 0x00, 0xFF),
|
||||
ToRGBColor(0xEF, 0xEF, 0x00),
|
||||
ToRGBColor(0x80, 0x00, 0x80),
|
||||
ToRGBColor(0x00, 0x6D, 0x77),
|
||||
ToRGBColor(0xFF, 0xC8, 0x00),
|
||||
ToRGBColor(0xFF, 0x55, 0xFF),
|
||||
ToRGBColor(0x3C, 0x7D, 0xFF),
|
||||
};
|
||||
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name Kingston Fury DDR4/5 DRAM
|
||||
@category RAM
|
||||
@type SMBus
|
||||
@save :x:
|
||||
@direct :white_check_mark:
|
||||
@effects :white_check_mark:
|
||||
@detectors DetectKingstonFuryDRAMControllers
|
||||
@comment
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
RGBController_KingstonFuryDRAM::RGBController_KingstonFuryDRAM(KingstonFuryDRAMController* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
name = "Kingston Fury DDR4/5 DRAM";
|
||||
vendor = "Kingston";
|
||||
type = DEVICE_TYPE_DRAM;
|
||||
description = "Kingston Fury Beast/Renegade DDR4/5 DRAM Device";
|
||||
location = controller->GetDeviceLocation();
|
||||
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.value = FURY_MODE_DIRECT;
|
||||
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 = 100;
|
||||
Direct.brightness = 80;
|
||||
modes.push_back(Direct);
|
||||
|
||||
mode Static;
|
||||
Static.name = "Static";
|
||||
Static.value = FURY_MODE_STATIC;
|
||||
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Static.colors_min = 1;
|
||||
Static.colors_max = 1;
|
||||
Static.colors.assign(default_colors, default_colors + 1);
|
||||
Static.brightness_min = 0;
|
||||
Static.brightness_max = 100;
|
||||
Static.brightness = 80;
|
||||
modes.push_back(Static);
|
||||
|
||||
// All speed values are inverted
|
||||
mode Rainbow;
|
||||
Rainbow.name = "Rainbow";
|
||||
Rainbow.value = FURY_MODE_RAINBOW;
|
||||
Rainbow.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Rainbow.speed_min = 60;
|
||||
Rainbow.speed_max = 0;
|
||||
Rainbow.speed = 25;
|
||||
Rainbow.direction = MODE_DIRECTION_UP;
|
||||
Rainbow.brightness_min = 0;
|
||||
Rainbow.brightness_max = 100;
|
||||
Rainbow.brightness = 80;
|
||||
Rainbow.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Rainbow);
|
||||
|
||||
mode Spectrum;
|
||||
Spectrum.name = "Spectrum";
|
||||
Spectrum.value = FURY_MODE_SPECTRUM;
|
||||
Spectrum.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Spectrum.speed_min = 60;
|
||||
Spectrum.speed_max = 0;
|
||||
Spectrum.speed = 25;
|
||||
Spectrum.direction = MODE_DIRECTION_UP;
|
||||
Spectrum.brightness_min = 0;
|
||||
Spectrum.brightness_max = 100;
|
||||
Spectrum.brightness = 80;
|
||||
Spectrum.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Spectrum);
|
||||
|
||||
mode Rhythm;
|
||||
Rhythm.name = "Rhythm";
|
||||
Rhythm.value = FURY_MODE_RHYTHM;
|
||||
Rhythm.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Rhythm.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Rhythm.colors_min = 2;
|
||||
Rhythm.colors_max = 11;
|
||||
Rhythm.colors.assign(default_colors, default_colors + 10);
|
||||
Rhythm.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Rhythm.speed_min = 10;
|
||||
Rhythm.speed_max = 0;
|
||||
Rhythm.speed = 0;
|
||||
Rhythm.brightness_min = 0;
|
||||
Rhythm.brightness_max = 100;
|
||||
Rhythm.brightness = 80;
|
||||
modes.push_back(Rhythm);
|
||||
|
||||
mode Breath;
|
||||
Breath.name = "Breath";
|
||||
Breath.value = FURY_MODE_BREATH;
|
||||
Breath.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Breath.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Breath.colors_min = 1;
|
||||
Breath.colors_max = 10;
|
||||
Breath.colors.assign(default_colors, default_colors + 10);
|
||||
Breath.speed_min = 10;
|
||||
Breath.speed_max = 1;
|
||||
Breath.speed = 5;
|
||||
Breath.brightness_min = 0;
|
||||
Breath.brightness_max = 100;
|
||||
Breath.brightness = 80;
|
||||
modes.push_back(Breath);
|
||||
|
||||
mode Dynamic;
|
||||
Dynamic.name = "Dynamic";
|
||||
Dynamic.value = FURY_MODE_DYNAMIC;
|
||||
Dynamic.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Dynamic.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Dynamic.colors_min = 1;
|
||||
Dynamic.colors_max = 10;
|
||||
Dynamic.colors.assign(default_colors, default_colors + 10);
|
||||
Dynamic.speed_min = 1000;
|
||||
Dynamic.speed_max = 100;
|
||||
Dynamic.speed = 300;
|
||||
Dynamic.brightness_min = 0;
|
||||
Dynamic.brightness_max = 100;
|
||||
Dynamic.brightness = 80;
|
||||
modes.push_back(Dynamic);
|
||||
|
||||
mode Slide;
|
||||
Slide.name = "Slide";
|
||||
Slide.value = FURY_MODE_SLIDE;
|
||||
Slide.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Slide.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Slide.colors_min = 2;
|
||||
Slide.colors_max = 11;
|
||||
Slide.colors.assign(default_colors, default_colors + 10);
|
||||
Slide.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Slide.speed_min = 255;
|
||||
Slide.speed_max = 0;
|
||||
Slide.speed = 8;
|
||||
Slide.direction = MODE_DIRECTION_UP;
|
||||
Slide.brightness_min = 0;
|
||||
Slide.brightness_max = 100;
|
||||
Slide.brightness = 80;
|
||||
modes.push_back(Slide);
|
||||
|
||||
mode Slither;
|
||||
Slither.name = "Slither";
|
||||
Slither.value = FURY_MODE_SLITHER;
|
||||
Slither.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Slither.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Slither.colors_min = 2;
|
||||
Slither.colors_max = 11;
|
||||
Slither.colors.assign(default_colors, default_colors + 10);
|
||||
Slither.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Slither.speed_min = 255;
|
||||
Slither.speed_max = 0;
|
||||
Slither.speed = 40;
|
||||
Slither.brightness_min = 0;
|
||||
Slither.brightness_max = 100;
|
||||
Slither.brightness = 80;
|
||||
modes.push_back(Slither);
|
||||
|
||||
mode Teleport;
|
||||
Teleport.name = "Teleport";
|
||||
Teleport.value = FURY_MODE_TELEPORT;
|
||||
Teleport.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Teleport.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Teleport.colors_min = 2;
|
||||
Teleport.colors_max = 11;
|
||||
Teleport.colors.assign(default_colors, default_colors + 10);
|
||||
Teleport.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Teleport.speed_min = 255;
|
||||
Teleport.speed_max = 0;
|
||||
Teleport.speed = 8;
|
||||
Teleport.brightness_min = 0;
|
||||
Teleport.brightness_max = 100;
|
||||
Teleport.brightness = 80;
|
||||
modes.push_back(Teleport);
|
||||
|
||||
mode Wind;
|
||||
Wind.name = "Wind";
|
||||
Wind.value = FURY_MODE_WIND;
|
||||
Wind.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Wind.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Wind.colors_min = 2;
|
||||
Wind.colors_max = 11;
|
||||
Wind.colors.assign(default_colors, default_colors + 10);
|
||||
Wind.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Wind.speed_min = 255;
|
||||
Wind.speed_max = 0;
|
||||
Wind.speed = 8;
|
||||
Wind.direction = MODE_DIRECTION_UP;
|
||||
Wind.brightness_min = 0;
|
||||
Wind.brightness_max = 100;
|
||||
Wind.brightness = 80;
|
||||
modes.push_back(Wind);
|
||||
|
||||
mode Comet;
|
||||
Comet.name = "Comet";
|
||||
Comet.value = FURY_MODE_COMET;
|
||||
Comet.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Comet.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Comet.colors_min = 1;
|
||||
Comet.colors_max = 10;
|
||||
Comet.colors.assign(default_colors, default_colors + 10);
|
||||
Comet.speed_min = 255;
|
||||
Comet.speed_max = 0;
|
||||
Comet.speed = 25;
|
||||
Comet.direction = MODE_DIRECTION_UP;
|
||||
Comet.brightness_min = 0;
|
||||
Comet.brightness_max = 100;
|
||||
Comet.brightness = 80;
|
||||
modes.push_back(Comet);
|
||||
|
||||
mode Rain;
|
||||
Rain.name = "Rain";
|
||||
Rain.value = FURY_MODE_RAIN;
|
||||
Rain.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Rain.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Rain.colors_min = 1;
|
||||
Rain.colors_max = 10;
|
||||
Rain.colors.assign(default_colors, default_colors + 10);
|
||||
Rain.speed_min = 28;
|
||||
Rain.speed_max = 8;
|
||||
Rain.speed = 25;
|
||||
Rain.direction = MODE_DIRECTION_DOWN;
|
||||
Rain.brightness_min = 0;
|
||||
Rain.brightness_max = 100;
|
||||
Rain.brightness = 80;
|
||||
modes.push_back(Rain);
|
||||
|
||||
mode Firework;
|
||||
Firework.name = "Firework";
|
||||
Firework.value = FURY_MODE_FIREWORK;
|
||||
Firework.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Firework.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Firework.colors_min = 1;
|
||||
Firework.colors_max = 10;
|
||||
Firework.colors.assign(default_colors, default_colors + 10);
|
||||
Firework.speed_min = 83;
|
||||
Firework.speed_max = 33;
|
||||
Firework.speed = 33;
|
||||
Firework.direction = MODE_DIRECTION_UP;
|
||||
Firework.brightness_min = 0;
|
||||
Firework.brightness_max = 100;
|
||||
Firework.brightness = 80;
|
||||
modes.push_back(Firework);
|
||||
|
||||
mode Voltage;
|
||||
Voltage.name = "Voltage";
|
||||
Voltage.value = FURY_MODE_VOLTAGE;
|
||||
Voltage.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Voltage.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Voltage.colors_min = 2;
|
||||
Voltage.colors_max = 11;
|
||||
Voltage.colors.assign(default_colors, default_colors + 10);
|
||||
Voltage.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Voltage.speed_min = 18;
|
||||
Voltage.speed_max = 5;
|
||||
Voltage.speed = 16;
|
||||
Voltage.direction = MODE_DIRECTION_UP;
|
||||
Voltage.brightness_min = 0;
|
||||
Voltage.brightness_max = 100;
|
||||
Voltage.brightness = 80;
|
||||
modes.push_back(Voltage);
|
||||
|
||||
#ifdef FURY_SYNC
|
||||
mode Countdown;
|
||||
Countdown.name = "Countdown";
|
||||
Countdown.value = FURY_MODE_COUNTDOWN;
|
||||
Countdown.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Countdown.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Countdown.colors_min = 2;
|
||||
Countdown.colors_max = 11;
|
||||
Countdown.colors.assign(default_colors, default_colors + 10);
|
||||
Countdown.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Countdown.speed_min = 76;
|
||||
Countdown.speed_max = 20;
|
||||
Countdown.speed = 76;
|
||||
Countdown.direction = MODE_DIRECTION_UP;
|
||||
Countdown.brightness_min = 0;
|
||||
Countdown.brightness_max = 100;
|
||||
Countdown.brightness = 80;
|
||||
modes.push_back(Countdown);
|
||||
#endif
|
||||
|
||||
mode Flame;
|
||||
Flame.name = "Flame";
|
||||
Flame.value = FURY_MODE_FLAME;
|
||||
Flame.flags = MODE_FLAG_HAS_SPEED |
|
||||
MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Flame.speed_min = 64;
|
||||
Flame.speed_max = 40;
|
||||
Flame.speed = 64;
|
||||
Flame.direction = MODE_DIRECTION_UP;
|
||||
Flame.brightness_min = 0;
|
||||
Flame.brightness_max = 100;
|
||||
Flame.brightness = 80;
|
||||
Flame.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Flame);
|
||||
|
||||
mode Twilight;
|
||||
Twilight.name = "Twilight";
|
||||
Twilight.value = FURY_MODE_TWILIGHT;
|
||||
Twilight.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Twilight.speed_min = 255;
|
||||
Twilight.speed_max = 0;
|
||||
Twilight.speed = 64;
|
||||
Twilight.brightness_min = 0;
|
||||
Twilight.brightness_max = 100;
|
||||
Twilight.brightness = 80;
|
||||
Twilight.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Twilight);
|
||||
|
||||
mode Fury;
|
||||
Fury.name = "Fury";
|
||||
Fury.value = FURY_MODE_FURY;
|
||||
Fury.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR |
|
||||
MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS |
|
||||
MODE_FLAG_HAS_DIRECTION_UD;
|
||||
Fury.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Fury.colors_min = 2;
|
||||
Fury.colors_max = 11;
|
||||
Fury.colors.assign(default_colors, default_colors + 10);
|
||||
Fury.colors.push_back(FURY_DEFAULT_BG_COLOR);
|
||||
Fury.speed_min = 255;
|
||||
Fury.speed_max = 0;
|
||||
Fury.speed = 76;
|
||||
Fury.direction = MODE_DIRECTION_UP;
|
||||
Fury.brightness_min = 0;
|
||||
Fury.brightness_max = 100;
|
||||
Fury.brightness = 80;
|
||||
modes.push_back(Fury);
|
||||
|
||||
mode Prism;
|
||||
Prism.name = "Prism";
|
||||
Prism.value = FURY_MODE_PRISM;
|
||||
Prism.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
|
||||
Prism.speed_min = 60;
|
||||
Prism.speed_max = 0;
|
||||
Prism.speed = 40;
|
||||
Prism.brightness_min = 0;
|
||||
Prism.brightness_max = 100;
|
||||
Prism.brightness = 80;
|
||||
Prism.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Prism);
|
||||
|
||||
SetupZones();
|
||||
|
||||
// default per-LED color is red
|
||||
colors.assign(colors.size(), default_colors[0]);
|
||||
}
|
||||
|
||||
RGBController_KingstonFuryDRAM::~RGBController_KingstonFuryDRAM()
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_KingstonFuryDRAM::SetupZones()
|
||||
{
|
||||
for(unsigned int slot = 0; slot < controller->GetSlotCount(); slot++)
|
||||
{
|
||||
zone* new_zone = new zone;
|
||||
|
||||
new_zone->name = "Fury Slot ";
|
||||
new_zone->name.append(std::to_string(slot + 1));
|
||||
new_zone->type = ZONE_TYPE_LINEAR;
|
||||
new_zone->leds_min = controller->GetLEDPerDIMM();
|
||||
new_zone->leds_max = new_zone->leds_min;
|
||||
new_zone->leds_count = new_zone->leds_min;
|
||||
new_zone->matrix_map = NULL;
|
||||
|
||||
zones.push_back(*new_zone);
|
||||
}
|
||||
|
||||
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
|
||||
{
|
||||
for(std::size_t led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++)
|
||||
{
|
||||
led* new_led = new led();
|
||||
|
||||
new_led->name = "Fury Slot ";
|
||||
new_led->name.append(std::to_string(zone_idx + 1));
|
||||
new_led->name.append(", LED ");
|
||||
new_led->name.append(std::to_string(led_idx + 1));
|
||||
|
||||
new_led->value = leds.size();
|
||||
|
||||
leds.push_back(*new_led);
|
||||
}
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_KingstonFuryDRAM::ResizeZone(int /*zone*/, int /*new_size*/)
|
||||
{
|
||||
/*---------------------------------------------------------*\
|
||||
| This device does not support resizing zones |
|
||||
\*---------------------------------------------------------*/
|
||||
LOG_DEBUG("[%s] resize zone",
|
||||
FURY_CONTROLLER_NAME);
|
||||
}
|
||||
|
||||
// some modes have different actual values to be written, depending on the color mode
|
||||
unsigned char RGBController_KingstonFuryDRAM::GetRealModeValue()
|
||||
{
|
||||
int mode_value = modes[active_mode].value;
|
||||
switch(mode_value)
|
||||
{
|
||||
case FURY_MODE_BREATH:
|
||||
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC)
|
||||
{
|
||||
return FURY_MODE_BREATH;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FURY_MODE_BREATH_DIRECT;
|
||||
}
|
||||
}
|
||||
return mode_value;
|
||||
}
|
||||
|
||||
void RGBController_KingstonFuryDRAM::DeviceUpdateLEDs()
|
||||
{
|
||||
controller->SendBegin();
|
||||
controller->SetMode(GetRealModeValue());
|
||||
|
||||
// Fixed mode specific parameters
|
||||
switch(modes[active_mode].value)
|
||||
{
|
||||
case FURY_MODE_STATIC:
|
||||
controller->SetRegister(FURY_REG_DIRECTION, FURY_DIR_BOTTOM_TO_TOP);
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
controller->SetRegister(FURY_REG_SPEED, 0);
|
||||
break;
|
||||
|
||||
case FURY_MODE_RAINBOW:
|
||||
case FURY_MODE_VOLTAGE:
|
||||
case FURY_MODE_COUNTDOWN:
|
||||
case FURY_MODE_FLAME:
|
||||
case FURY_MODE_TWILIGHT:
|
||||
case FURY_MODE_FURY:
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
break;
|
||||
|
||||
case FURY_MODE_RHYTHM:
|
||||
controller->SetRegister(FURY_REG_DIRECTION,
|
||||
FURY_DIR_BOTTOM_TO_TOP);
|
||||
break;
|
||||
|
||||
case FURY_MODE_BREATH:
|
||||
controller->SetRegister(FURY_REG_DIRECTION,
|
||||
FURY_DIR_BOTTOM_TO_TOP);
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
break;
|
||||
|
||||
case FURY_MODE_DYNAMIC:
|
||||
controller->SetRegister(FURY_REG_DIRECTION,
|
||||
FURY_DIR_BOTTOM_TO_TOP);
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
break;
|
||||
|
||||
case FURY_MODE_SLITHER:
|
||||
controller->SetRegister(FURY_REG_DELAY, 12);
|
||||
controller->SetRegister(FURY_REG_DIRECTION,
|
||||
FURY_ALT_DIRECTIONS);
|
||||
break;
|
||||
|
||||
case FURY_MODE_TELEPORT:
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
controller->SetRegister(FURY_REG_DIRECTION,
|
||||
FURY_ALT_DIRECTIONS);
|
||||
break;
|
||||
|
||||
case FURY_MODE_RAIN:
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
controller->SetRegister(FURY_REG_LENGTH, 3);
|
||||
break;
|
||||
|
||||
case FURY_MODE_FIREWORK:
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
controller->SetRegister(FURY_REG_LENGTH, 7);
|
||||
break;
|
||||
}
|
||||
|
||||
// Mode-specific parameters that are customizable in Kingston's software
|
||||
// but which are not yet available in the OpenRGB interface.
|
||||
// Default values are used here and the parameter ranges are annotated
|
||||
switch(modes[active_mode].value)
|
||||
{
|
||||
case FURY_MODE_RHYTHM:
|
||||
// between 2 and 5
|
||||
controller->SetRegister(FURY_REG_DELAY, 3);
|
||||
break;
|
||||
|
||||
|
||||
case FURY_MODE_SLIDE:
|
||||
// between 1 and 4
|
||||
controller->SetRegister(FURY_REG_DELAY, 3);
|
||||
// between 1 and 12
|
||||
controller->SetRegister(FURY_REG_LENGTH, 4);
|
||||
break;
|
||||
|
||||
case FURY_MODE_SLITHER:
|
||||
// between 1 and 32
|
||||
controller->SetRegister(FURY_REG_LENGTH, 12);
|
||||
break;
|
||||
|
||||
case FURY_MODE_TELEPORT:
|
||||
// between 1 and 12
|
||||
controller->SetRegister(FURY_REG_LENGTH, 3);
|
||||
|
||||
case FURY_MODE_WIND:
|
||||
// between 0 and 32
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
// between 1 and 32
|
||||
controller->SetRegister(FURY_REG_LENGTH, 12);
|
||||
break;
|
||||
|
||||
case FURY_MODE_COMET:
|
||||
// between 0 and 20
|
||||
controller->SetRegister(FURY_REG_DELAY, 0);
|
||||
// between 1 and 18
|
||||
controller->SetRegister(FURY_REG_LENGTH, 7);
|
||||
break;
|
||||
|
||||
case FURY_MODE_PRISM:
|
||||
// between 2 and 4
|
||||
controller->SetRegister(FURY_REG_DELAY, 2);
|
||||
break;
|
||||
|
||||
case FURY_MODE_SPECTRUM:
|
||||
// between 2 and 6
|
||||
controller->SetRegister(FURY_REG_DELAY, 4);
|
||||
break;
|
||||
}
|
||||
|
||||
switch(modes[active_mode].color_mode)
|
||||
{
|
||||
case MODE_COLORS_PER_LED:
|
||||
controller->SetLEDColors(colors);
|
||||
break;
|
||||
|
||||
case MODE_COLORS_MODE_SPECIFIC:
|
||||
switch(modes[active_mode].value)
|
||||
{
|
||||
case FURY_MODE_RHYTHM:
|
||||
case FURY_MODE_SLIDE:
|
||||
case FURY_MODE_SLITHER:
|
||||
case FURY_MODE_TELEPORT:
|
||||
case FURY_MODE_WIND:
|
||||
case FURY_MODE_VOLTAGE:
|
||||
case FURY_MODE_COUNTDOWN:
|
||||
case FURY_MODE_FURY:
|
||||
{
|
||||
std::vector<RGBColor> mode_colors(modes[active_mode].colors.begin(),
|
||||
modes[active_mode].colors.end() - 1);
|
||||
controller->SetModeColors(mode_colors);
|
||||
// handle background color
|
||||
RGBColor color = modes[active_mode].colors[mode_colors.size()];
|
||||
unsigned char red = RGBGetRValue(color);
|
||||
unsigned char green = RGBGetGValue(color);
|
||||
unsigned char blue = RGBGetBValue(color);
|
||||
|
||||
controller->SetRegister(FURY_REG_BG_RED, red);
|
||||
controller->SetRegister(FURY_REG_BG_GREEN, green);
|
||||
controller->SetRegister(FURY_REG_BG_BLUE, blue);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
controller->SetModeColors(modes[active_mode].colors);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if(modes[active_mode].flags & MODE_FLAG_HAS_DIRECTION_UD)
|
||||
{
|
||||
if(modes[active_mode].direction == MODE_DIRECTION_UP)
|
||||
{
|
||||
controller->SetRegister(FURY_REG_DIRECTION,
|
||||
FURY_DIR_BOTTOM_TO_TOP);
|
||||
}
|
||||
else
|
||||
{
|
||||
controller->SetRegister(FURY_REG_DIRECTION,
|
||||
FURY_DIR_TOP_TO_BOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
if(modes[active_mode].flags & MODE_FLAG_HAS_SPEED)
|
||||
{
|
||||
switch(modes[active_mode].value)
|
||||
{
|
||||
case FURY_MODE_DYNAMIC:
|
||||
controller->SetRegister(FURY_REG_SPEED, 0);
|
||||
|
||||
// time spent holding a color
|
||||
controller->SetRegister(FURY_REG_DYNAMIC_HOLD_A,
|
||||
modes[active_mode].speed >> 8);
|
||||
// set to 1 as long as the time above is nonzero
|
||||
controller->SetRegister(FURY_REG_DYNAMIC_HOLD_B, 1);
|
||||
|
||||
// time spent fading to next color
|
||||
controller->SetRegister(FURY_REG_DYNAMIC_FADE_A,
|
||||
(modes[active_mode].speed * 5) >> 8);
|
||||
// set to 1 as long as the time above is nonzero
|
||||
controller->SetRegister(FURY_REG_DYNAMIC_FADE_B, 1);
|
||||
break;
|
||||
|
||||
case FURY_MODE_BREATH:
|
||||
controller->SetRegister(FURY_REG_SPEED, 0);
|
||||
|
||||
// These are the speed values used by Kingston's software,
|
||||
// representing the time spent fading between two brightness levels
|
||||
controller->SetRegister(FURY_REG_BREATH_MIN_TO_MID,
|
||||
modes[active_mode].speed * 3);
|
||||
controller->SetRegister(FURY_REG_BREATH_MID_TO_MAX,
|
||||
modes[active_mode].speed);
|
||||
controller->SetRegister(FURY_REG_BREATH_MAX_TO_MID,
|
||||
modes[active_mode].speed);
|
||||
controller->SetRegister(FURY_REG_BREATH_MID_TO_MIN,
|
||||
modes[active_mode].speed * 3);
|
||||
|
||||
// Time spent holding min brightness
|
||||
controller->SetRegister(FURY_REG_BREATH_MIN_HOLD, 1);
|
||||
|
||||
// Brightness values (relative to overall brightness)
|
||||
controller->SetRegister(FURY_REG_BREATH_MAX_BRIGHTNESS, 100);
|
||||
controller->SetRegister(FURY_REG_BREATH_MID_BRIGHTNESS, 64);
|
||||
controller->SetRegister(FURY_REG_BREATH_MIN_BRIGHTNESS, 0);
|
||||
// Kingston software uses 1 for min brightness,
|
||||
// but 0 seems to look better.
|
||||
|
||||
break;
|
||||
|
||||
case FURY_MODE_RAIN:
|
||||
{
|
||||
// speed offsets taken from Kingston software
|
||||
unsigned char offsets[4] = {11, 0, 15, 9};
|
||||
std::vector<unsigned char> speeds;
|
||||
for (std::size_t idx = 0; idx < controller->GetSlotCount(); idx++)
|
||||
{
|
||||
speeds.push_back(modes[active_mode].speed + offsets[idx % 4]);
|
||||
}
|
||||
controller->SetRegister(FURY_REG_SPEED, speeds);
|
||||
break;
|
||||
}
|
||||
|
||||
case FURY_MODE_FIREWORK:
|
||||
{
|
||||
// speed offsets taken from Kingston software
|
||||
unsigned char offsets[4] = {15, 0, 19, 4};
|
||||
std::vector<unsigned char> speeds;
|
||||
for (std::size_t idx = 0; idx < controller->GetSlotCount(); idx++)
|
||||
{
|
||||
speeds.push_back(modes[active_mode].speed + offsets[idx % 4]);
|
||||
}
|
||||
controller->SetRegister(FURY_REG_SPEED, speeds);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
controller->SetRegister(FURY_REG_SPEED, modes[active_mode].speed);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
controller->SetRegister(FURY_REG_BRIGHTNESS,
|
||||
modes[active_mode].brightness);
|
||||
controller->SetNumSlots();
|
||||
controller->SendApply();
|
||||
}
|
||||
|
||||
void RGBController_KingstonFuryDRAM::UpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_KingstonFuryDRAM::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_KingstonFuryDRAM::DeviceUpdateMode()
|
||||
{
|
||||
LOG_DEBUG("[%s] device update mode",
|
||||
FURY_CONTROLLER_NAME);
|
||||
// Preamble only necessary when changing modes.
|
||||
if(GetRealModeValue() != controller->GetMode())
|
||||
{
|
||||
controller->SendPreamble(modes[active_mode].value != FURY_MODE_RAIN &&
|
||||
modes[active_mode].value != FURY_MODE_FIREWORK &&
|
||||
modes[active_mode].value != FURY_MODE_DIRECT);
|
||||
}
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
/*---------------------------------------------------------*\
|
||||
| RGBController_KingstonFuryDRAM.h |
|
||||
| |
|
||||
| Driver for Kingston Fury DDR4/5 RAM modules |
|
||||
| |
|
||||
| Geofrey Mon (geofbot) 14 Jul 2024 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-only |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RGBController.h"
|
||||
#include "KingstonFuryDRAMController.h"
|
||||
|
||||
class RGBController_KingstonFuryDRAM : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_KingstonFuryDRAM(KingstonFuryDRAMController* controller_ptr);
|
||||
~RGBController_KingstonFuryDRAM();
|
||||
|
||||
void SetupZones();
|
||||
|
||||
void ResizeZone(int zone, int new_size);
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSingleLED(int led);
|
||||
|
||||
void DeviceUpdateMode();
|
||||
|
||||
private:
|
||||
unsigned char GetRealModeValue();
|
||||
KingstonFuryDRAMController* controller;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue