Patriot Viper RAM reimplementation

This commit is contained in:
Aleš Nezbeda 2022-05-01 00:31:52 +00:00 committed by Adam Honse
parent d75556c3cb
commit 48118821d7
3 changed files with 285 additions and 57 deletions

View file

@ -27,11 +27,14 @@ PatriotViperController::PatriotViperController(i2c_smbus_interface* bus, viper_d
led_count += 5;
}
}
keepalive_thread = NULL;
keepalive_thread_run = 1;
}
PatriotViperController::~PatriotViperController()
{
StopKeepaliveThread();
}
std::string PatriotViperController::GetDeviceName()
@ -92,26 +95,16 @@ void PatriotViperController::SetEffectColor(unsigned char red, unsigned char gre
void PatriotViperController::SetAllColors(unsigned char red, unsigned char green, unsigned char blue)
{
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_LED0_DIRECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED1_DIRECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED2_DIRECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED3_DIRECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED4_DIRECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_APPLY, 0x01, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_LED0_EFFECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED1_EFFECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED2_EFFECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED3_EFFECT_COLOR, red, blue, green);
ViperRegisterWrite(VIPER_REG_LED4_EFFECT_COLOR, red, blue, green);
}
void PatriotViperController::SetLEDColor(unsigned int led, unsigned char red, unsigned char green, unsigned char blue)
{
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_LED0_DIRECT_COLOR + led, red, blue, green);
ViperRegisterWrite(VIPER_REG_APPLY, 0x01, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_LED0_EFFECT_COLOR + led, red, blue, green);
}
void PatriotViperController::SetLEDEffectColor(unsigned int led, unsigned char red, unsigned char green, unsigned char blue)
@ -148,25 +141,68 @@ void PatriotViperController::SetLEDEffectColor(unsigned int /*slot*/, unsigned i
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
}
void PatriotViperController::SetMode(unsigned char new_mode, unsigned char new_speed)
void PatriotViperController::SetMode(unsigned char new_mode, unsigned char new_speed, unsigned int color_mode)
{
StopKeepaliveThread();
direct = false;
mode = new_mode;
speed = new_speed;
if(mode_speed[mode] == -1)
{
speed = new_speed;
}
else
{
speed = mode_speed[mode];
}
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, mode, 0x00, speed);
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
if(color_mode == 3)
{
/*--------------------------------------------------------------------------------------------------*\
| Reset previously set mode color, because we want RAM sticks to fall-back to automatic viper colors |
| These are not just rainbowey, but they are affected differently with modes. |
\*--------------------------------------------------------------------------------------------------*/
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, VIPER_MODE_DARK, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
}
if(mode_steps[mode] == -1)
{
/*--------------------------------------------------------------------------------------------------*\
| Based on a header file, if number of steps in mode is -1 it means mode is not synced, |
| doesn't have steps and the Keepalive thread is not needed. Set the mode directly and leave it. |
\*--------------------------------------------------------------------------------------------------*/
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, mode, 0x00, speed);
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
}
else
{
/*----------------------------------------------------------------*\
| Reset step counters and fire up Keepalive thread. |
| Thread will deal with changing the mode and everything else. |
\*----------------------------------------------------------------*/
step = 0;
sub_step = 0;
keepalive_thread = new std::thread(&PatriotViperController::KeepaliveThread, this);
}
}
void PatriotViperController::SetDirect()
{
StopKeepaliveThread();
direct = true;
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_APPLY, 0x01, 0x00, 0x00);
ViperRegisterWrite(VIPER_REG_MODE, VIPER_MODE_DIRECT, 0x00, 0x00);
}
void PatriotViperController::ViperRegisterWrite(viper_register reg, unsigned char val0, unsigned char val1, unsigned char val2)
@ -174,3 +210,129 @@ void PatriotViperController::ViperRegisterWrite(viper_register reg, unsigned cha
bus->i2c_smbus_write_byte_data(dev, reg, val0);
bus->i2c_smbus_write_byte_data(dev, val2, val1);
}
void PatriotViperController::KeepaliveThread()
{
while(keepalive_thread_run.load())
{
int cur_step = step.load();
int cur_sub_step = sub_step.load();
if(cur_sub_step == 0)
{
ViperRegisterWrite(VIPER_REG_MODE, mode, cur_step, speed);
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, cur_sub_step);
}
else
{
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, cur_sub_step);
}
if(cur_sub_step == mode_sub_steps[mode])
{
sub_step.store(0);
if(cur_step == mode_steps[mode])
{
step.store(0);
}
else
{
step.store(cur_step+1);
}
}
else
{
sub_step.store(cur_sub_step+1);
}
/*---------------------------------------------------------------------------------------------------------*\
| We have to use wait_for with condition_variable since some of the modes will keep the thread waiting for |
| long time and we don't want to make user wait for mode change when in middle of waiting period. |
\*---------------------------------------------------------------------------------------------------------*/
int delay = GetDelay(mode, cur_step, cur_sub_step, cur_sub_step == mode_sub_steps[mode]);
std::unique_lock<std::mutex> l(thread_ctrl_m);
thread_ctrl.wait_for(l, std::chrono::milliseconds(delay));
}
}
void PatriotViperController::StopKeepaliveThread()
{
if(keepalive_thread != NULL)
{
keepalive_thread_run = 0;
thread_ctrl.notify_one();
keepalive_thread->join();
keepalive_thread = NULL;
keepalive_thread_run = 1;
}
}
unsigned int PatriotViperController::GetDelay(unsigned char mode, unsigned int step, unsigned int sub_step, bool loop_end)
{
if(loop_end)
{
if(mode == VIPER_MODE_VIPER)
{
return 7000;
}
else if(mode == VIPER_MODE_BREATHING)
{
return 3000;
}
else if(mode == VIPER_MODE_NEON)
{
return 600;
}
else if(mode == VIPER_MODE_AURORA)
{
return 300;
}
else
{
return 0;
}
}
if(sub_step == 0)
{
if(mode == VIPER_MODE_VIPER)
{
return 3000;
}
else if(mode == VIPER_MODE_BREATHING)
{
return 3000;
}
else
{
return 0;
}
}
else
{
if(sub_step == 4 && mode == VIPER_MODE_VIPER)
{
return 1000;
}
else if(sub_step == 5 && mode == VIPER_MODE_VIPER)
{
return 590;
}
else if(mode == VIPER_MODE_NEON)
{
return 600;
}
else if(mode == VIPER_MODE_HEARTBEAT)
{
return 100;
}
else if(mode == VIPER_MODE_MARQUEE)
{
return 300;
}
else
{
return 0;
}
}
}

View file

@ -8,6 +8,7 @@
\*-----------------------------------------*/
#include <string>
#include <map>
#include "i2c_smbus.h"
#pragma once
@ -42,9 +43,11 @@ enum
VIPER_MODE_MARQUEE = 0x04, /* Marquee mode */
VIPER_MODE_RAINDROP = 0x05, /* Raindrop mode */
VIPER_MODE_AURORA = 0x06, /* Aurora mode */
VIPER_MODE_NEON = 0x08, /* Neon mode */
VIPER_MODE_DIRECT = 0x07, /* Direct mode */
VIPER_MODE_NEON = 0x08, /* Color cycle mode */
};
enum
{
VIPER_SPEED_MIN = 0xC8, /* Slowest speed for non-breathing mode */
@ -66,7 +69,7 @@ public:
unsigned int GetLEDCount();
unsigned int GetSlotCount();
unsigned int GetMode();
void SetMode(unsigned char new_mode, unsigned char new_speed);
void SetMode(unsigned char new_mode, unsigned char new_speed, unsigned int color_mode);
void SetDirect();
void SetAllColors(unsigned char red, unsigned char green, unsigned char blue);
@ -76,6 +79,10 @@ public:
void SetLEDEffectColor(unsigned int led, unsigned char red, unsigned char green, unsigned char blue);
void SetLEDEffectColor(unsigned int slot, unsigned int led, unsigned char red, unsigned char green, unsigned char blue);
void KeepaliveThread();
void StopKeepaliveThread();
unsigned int GetDelay(unsigned char mode, unsigned int step, unsigned int sub_step, bool loop_end);
void ViperRegisterWrite(viper_register reg, unsigned char val0, unsigned char val1, unsigned char val2);
bool direct;
@ -87,4 +94,53 @@ private:
viper_dev_id dev;
unsigned char mode;
unsigned char speed;
std::thread* keepalive_thread;
std::atomic<bool> keepalive_thread_run;
std::atomic<int> step;
std::atomic<int> sub_step;
std::condition_variable thread_ctrl;
std::mutex thread_ctrl_m;
/*-------------------------------------------------------*\
| Value -1 means mode is not synced, doesn't have steps |
| and the Keepalive thread is not needed |
\*-------------------------------------------------------*/
std::map <int, int> mode_steps =
{
{VIPER_MODE_DARK, -1},
{VIPER_MODE_BREATHING, 4},
{VIPER_MODE_VIPER, 4},
{VIPER_MODE_HEARTBEAT, 6},
{VIPER_MODE_MARQUEE, 3},
{VIPER_MODE_RAINDROP, -1},
{VIPER_MODE_AURORA, 4},
{VIPER_MODE_NEON, 0},
};
std::map <int, int> mode_sub_steps =
{
{VIPER_MODE_DARK, -1},
{VIPER_MODE_BREATHING, 1},
{VIPER_MODE_VIPER, 6},
{VIPER_MODE_HEARTBEAT, 59},
{VIPER_MODE_MARQUEE, 30},
{VIPER_MODE_RAINDROP, -1},
{VIPER_MODE_AURORA, 0},
{VIPER_MODE_NEON, 5},
};
std::map <int, int> mode_speed =
{
{VIPER_MODE_DARK, -1},
{VIPER_MODE_BREATHING, 0x06},
{VIPER_MODE_VIPER, 0x3C},
{VIPER_MODE_HEARTBEAT, 0x3C},
{VIPER_MODE_MARQUEE, 0x3C},
{VIPER_MODE_RAINDROP, -1},
{VIPER_MODE_AURORA, 0x3C},
{VIPER_MODE_NEON, 0x3C},
};
};

View file

@ -35,8 +35,8 @@ RGBController_PatriotViper::RGBController_PatriotViper(PatriotViperController* v
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.speed_min = 0;
Direct.speed_max = 0;
Direct.color_mode = MODE_COLORS_PER_LED;
Direct.speed = 0;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Dark;
@ -45,70 +45,80 @@ RGBController_PatriotViper::RGBController_PatriotViper(PatriotViperController* v
Dark.flags = 0;
Dark.speed_min = 0;
Dark.speed_max = 0;
Dark.color_mode = MODE_COLORS_NONE;
Dark.speed = 0;
Dark.color_mode = MODE_COLORS_NONE;
modes.push_back(Dark);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = VIPER_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Breathing.speed_min = VIPER_SPEED_BREATHING_MIN;
Breathing.speed_max = VIPER_SPEED_BREATHING_MAX;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.speed = VIPER_SPEED_BREATHING_DEFAULT;
Breathing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR;
Breathing.speed_min = 0x06;
Breathing.speed_max = 0x06;
Breathing.speed = 0x06;
Breathing.color_mode = MODE_COLORS_RANDOM;
modes.push_back(Breathing);
mode Viper;
Viper.name = "Viper";
Viper.value = VIPER_MODE_VIPER;
Viper.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Viper.speed_min = VIPER_SPEED_MIN;
Viper.speed_max = VIPER_SPEED_MAX;
Viper.color_mode = MODE_COLORS_PER_LED;
Viper.speed = VIPER_SPEED_DEFAULT;
Viper.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR;
Viper.speed_min = 0x3C;
Viper.speed_max = 0x3C;
Viper.speed = 0x3C;
Viper.color_mode = MODE_COLORS_RANDOM;
modes.push_back(Viper);
mode Heartbeat;
Heartbeat.name = "Heartbeat";
Heartbeat.value = VIPER_MODE_HEARTBEAT;
Heartbeat.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Heartbeat.speed_min = VIPER_SPEED_MIN;
Heartbeat.speed_max = VIPER_SPEED_MAX;
Heartbeat.color_mode = MODE_COLORS_PER_LED;
Heartbeat.speed = VIPER_SPEED_DEFAULT;
Heartbeat.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR;
Heartbeat.speed_min = 0x3C;
Heartbeat.speed_max = 0x3C;
Heartbeat.speed = 0x3C;
Heartbeat.color_mode = MODE_COLORS_RANDOM;
modes.push_back(Heartbeat);
mode Marquee;
Marquee.name = "Marquee";
Marquee.value = VIPER_MODE_MARQUEE;
Marquee.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Marquee.speed_min = VIPER_SPEED_MIN;
Marquee.speed_max = VIPER_SPEED_MAX;
Marquee.color_mode = MODE_COLORS_PER_LED;
Marquee.speed = VIPER_SPEED_DEFAULT;
Marquee.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR;
Marquee.speed_min = 0x3C;
Marquee.speed_max = 0x3C;
Marquee.speed = 0x3C;
Marquee.color_mode = MODE_COLORS_RANDOM;
modes.push_back(Marquee);
mode Raindrop;
Raindrop.name = "Raindrop";
Raindrop.value = VIPER_MODE_RAINDROP;
Raindrop.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Raindrop.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR;
Raindrop.speed_min = VIPER_SPEED_MIN;
Raindrop.speed_max = VIPER_SPEED_MAX;
Raindrop.color_mode = MODE_COLORS_PER_LED;
Raindrop.speed = VIPER_SPEED_DEFAULT;
Raindrop.color_mode = MODE_COLORS_RANDOM;
modes.push_back(Raindrop);
mode Aurora;
Aurora.name = "Aurora";
Aurora.value = VIPER_MODE_AURORA;
Aurora.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Aurora.speed_min = VIPER_SPEED_MIN;
Aurora.speed_max = VIPER_SPEED_MAX;
Aurora.color_mode = MODE_COLORS_PER_LED;
Aurora.speed = VIPER_SPEED_DEFAULT;
Aurora.flags = MODE_FLAG_HAS_RANDOM_COLOR;
Aurora.speed_min = 0x3C;
Aurora.speed_max = 0x3C;
Aurora.speed = 0x3C;
Aurora.color_mode = MODE_COLORS_RANDOM;
modes.push_back(Aurora);
mode Neon;
Neon.name = "Neon";
Neon.value = VIPER_MODE_NEON;
Neon.flags = MODE_FLAG_HAS_RANDOM_COLOR;
Neon.speed_min = 0x3C;
Neon.speed_max = 0x3C;
Neon.speed = 0x3C;
Neon.color_mode = MODE_COLORS_RANDOM;
modes.push_back(Neon);
SetupZones();
}
@ -214,6 +224,6 @@ void RGBController_PatriotViper::DeviceUpdateMode()
}
else
{
viper->SetMode(modes[active_mode].value, modes[active_mode].speed);
viper->SetMode(modes[active_mode].value, modes[active_mode].speed, modes[active_mode].color_mode);
}
}