Skip to content

Commit 4811882

Browse files
SlouchyButtonCalcProgrammer1
authored andcommitted
Patriot Viper RAM reimplementation
1 parent d75556c commit 4811882

File tree

3 files changed

+285
-57
lines changed

3 files changed

+285
-57
lines changed

Controllers/PatriotViperController/PatriotViperController.cpp

Lines changed: 187 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@ PatriotViperController::PatriotViperController(i2c_smbus_interface* bus, viper_d
2727
led_count += 5;
2828
}
2929
}
30+
31+
keepalive_thread = NULL;
32+
keepalive_thread_run = 1;
3033
}
3134

3235
PatriotViperController::~PatriotViperController()
3336
{
34-
37+
StopKeepaliveThread();
3538
}
3639

3740
std::string PatriotViperController::GetDeviceName()
@@ -92,26 +95,16 @@ void PatriotViperController::SetEffectColor(unsigned char red, unsigned char gre
9295

9396
void PatriotViperController::SetAllColors(unsigned char red, unsigned char green, unsigned char blue)
9497
{
95-
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
96-
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
97-
98-
ViperRegisterWrite(VIPER_REG_LED0_DIRECT_COLOR, red, blue, green);
99-
ViperRegisterWrite(VIPER_REG_LED1_DIRECT_COLOR, red, blue, green);
100-
ViperRegisterWrite(VIPER_REG_LED2_DIRECT_COLOR, red, blue, green);
101-
ViperRegisterWrite(VIPER_REG_LED3_DIRECT_COLOR, red, blue, green);
102-
ViperRegisterWrite(VIPER_REG_LED4_DIRECT_COLOR, red, blue, green);
103-
104-
ViperRegisterWrite(VIPER_REG_APPLY, 0x01, 0x00, 0x00);
98+
ViperRegisterWrite(VIPER_REG_LED0_EFFECT_COLOR, red, blue, green);
99+
ViperRegisterWrite(VIPER_REG_LED1_EFFECT_COLOR, red, blue, green);
100+
ViperRegisterWrite(VIPER_REG_LED2_EFFECT_COLOR, red, blue, green);
101+
ViperRegisterWrite(VIPER_REG_LED3_EFFECT_COLOR, red, blue, green);
102+
ViperRegisterWrite(VIPER_REG_LED4_EFFECT_COLOR, red, blue, green);
105103
}
106104

107105
void PatriotViperController::SetLEDColor(unsigned int led, unsigned char red, unsigned char green, unsigned char blue)
108106
{
109-
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
110-
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
111-
112-
ViperRegisterWrite(VIPER_REG_LED0_DIRECT_COLOR + led, red, blue, green);
113-
114-
ViperRegisterWrite(VIPER_REG_APPLY, 0x01, 0x00, 0x00);
107+
ViperRegisterWrite(VIPER_REG_LED0_EFFECT_COLOR + led, red, blue, green);
115108
}
116109

117110
void PatriotViperController::SetLEDEffectColor(unsigned int led, unsigned char red, unsigned char green, unsigned char blue)
@@ -148,29 +141,198 @@ void PatriotViperController::SetLEDEffectColor(unsigned int /*slot*/, unsigned i
148141
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
149142
}
150143

151-
void PatriotViperController::SetMode(unsigned char new_mode, unsigned char new_speed)
144+
void PatriotViperController::SetMode(unsigned char new_mode, unsigned char new_speed, unsigned int color_mode)
152145
{
146+
StopKeepaliveThread();
153147
direct = false;
154148
mode = new_mode;
155-
speed = new_speed;
149+
if(mode_speed[mode] == -1)
150+
{
151+
speed = new_speed;
152+
}
153+
else
154+
{
155+
speed = mode_speed[mode];
156+
}
156157

157-
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
158-
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
159-
ViperRegisterWrite(VIPER_REG_MODE, mode, 0x00, speed);
160-
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, 0x00);
161-
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
158+
if(color_mode == 3)
159+
{
160+
/*--------------------------------------------------------------------------------------------------*\
161+
| Reset previously set mode color, because we want RAM sticks to fall-back to automatic viper colors |
162+
| These are not just rainbowey, but they are affected differently with modes. |
163+
\*--------------------------------------------------------------------------------------------------*/
164+
165+
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
166+
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
167+
ViperRegisterWrite(VIPER_REG_MODE, VIPER_MODE_DARK, 0x00, 0x00);
168+
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, 0x00);
169+
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
170+
}
171+
172+
if(mode_steps[mode] == -1)
173+
{
174+
/*--------------------------------------------------------------------------------------------------*\
175+
| Based on a header file, if number of steps in mode is -1 it means mode is not synced, |
176+
| doesn't have steps and the Keepalive thread is not needed. Set the mode directly and leave it. |
177+
\*--------------------------------------------------------------------------------------------------*/
178+
179+
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
180+
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
181+
ViperRegisterWrite(VIPER_REG_MODE, mode, 0x00, speed);
182+
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, 0x00);
183+
ViperRegisterWrite(VIPER_REG_MODE, 0xFA, 0x00, 0x00);
184+
}
185+
else
186+
{
187+
/*----------------------------------------------------------------*\
188+
| Reset step counters and fire up Keepalive thread. |
189+
| Thread will deal with changing the mode and everything else. |
190+
\*----------------------------------------------------------------*/
191+
192+
step = 0;
193+
sub_step = 0;
194+
195+
keepalive_thread = new std::thread(&PatriotViperController::KeepaliveThread, this);
196+
}
162197
}
163198

164199
void PatriotViperController::SetDirect()
165200
{
201+
StopKeepaliveThread();
166202
direct = true;
167203
ViperRegisterWrite(VIPER_REG_START, 0xFF, 0xFF, 0xFF);
168204
ViperRegisterWrite(VIPER_REG_STATIC, 0x04, 0x00, 0x00);
169-
ViperRegisterWrite(VIPER_REG_APPLY, 0x01, 0x00, 0x00);
205+
ViperRegisterWrite(VIPER_REG_MODE, VIPER_MODE_DIRECT, 0x00, 0x00);
170206
}
171207

172208
void PatriotViperController::ViperRegisterWrite(viper_register reg, unsigned char val0, unsigned char val1, unsigned char val2)
173209
{
174210
bus->i2c_smbus_write_byte_data(dev, reg, val0);
175211
bus->i2c_smbus_write_byte_data(dev, val2, val1);
176212
}
213+
214+
void PatriotViperController::KeepaliveThread()
215+
{
216+
while(keepalive_thread_run.load())
217+
{
218+
int cur_step = step.load();
219+
int cur_sub_step = sub_step.load();
220+
if(cur_sub_step == 0)
221+
{
222+
ViperRegisterWrite(VIPER_REG_MODE, mode, cur_step, speed);
223+
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, cur_sub_step);
224+
}
225+
else
226+
{
227+
ViperRegisterWrite(VIPER_REG_MODE, 0xAA, 0x00, cur_sub_step);
228+
}
229+
230+
if(cur_sub_step == mode_sub_steps[mode])
231+
{
232+
sub_step.store(0);
233+
234+
if(cur_step == mode_steps[mode])
235+
{
236+
step.store(0);
237+
}
238+
else
239+
{
240+
step.store(cur_step+1);
241+
}
242+
}
243+
else
244+
{
245+
sub_step.store(cur_sub_step+1);
246+
}
247+
248+
/*---------------------------------------------------------------------------------------------------------*\
249+
| We have to use wait_for with condition_variable since some of the modes will keep the thread waiting for |
250+
| long time and we don't want to make user wait for mode change when in middle of waiting period. |
251+
\*---------------------------------------------------------------------------------------------------------*/
252+
int delay = GetDelay(mode, cur_step, cur_sub_step, cur_sub_step == mode_sub_steps[mode]);
253+
std::unique_lock<std::mutex> l(thread_ctrl_m);
254+
thread_ctrl.wait_for(l, std::chrono::milliseconds(delay));
255+
}
256+
}
257+
258+
void PatriotViperController::StopKeepaliveThread()
259+
{
260+
if(keepalive_thread != NULL)
261+
{
262+
keepalive_thread_run = 0;
263+
thread_ctrl.notify_one();
264+
keepalive_thread->join();
265+
keepalive_thread = NULL;
266+
keepalive_thread_run = 1;
267+
}
268+
}
269+
270+
unsigned int PatriotViperController::GetDelay(unsigned char mode, unsigned int step, unsigned int sub_step, bool loop_end)
271+
{
272+
if(loop_end)
273+
{
274+
if(mode == VIPER_MODE_VIPER)
275+
{
276+
return 7000;
277+
}
278+
else if(mode == VIPER_MODE_BREATHING)
279+
{
280+
return 3000;
281+
}
282+
else if(mode == VIPER_MODE_NEON)
283+
{
284+
return 600;
285+
}
286+
else if(mode == VIPER_MODE_AURORA)
287+
{
288+
return 300;
289+
}
290+
else
291+
{
292+
return 0;
293+
}
294+
}
295+
296+
if(sub_step == 0)
297+
{
298+
if(mode == VIPER_MODE_VIPER)
299+
{
300+
return 3000;
301+
}
302+
else if(mode == VIPER_MODE_BREATHING)
303+
{
304+
return 3000;
305+
}
306+
else
307+
{
308+
return 0;
309+
}
310+
}
311+
else
312+
{
313+
if(sub_step == 4 && mode == VIPER_MODE_VIPER)
314+
{
315+
return 1000;
316+
}
317+
else if(sub_step == 5 && mode == VIPER_MODE_VIPER)
318+
{
319+
return 590;
320+
}
321+
else if(mode == VIPER_MODE_NEON)
322+
{
323+
return 600;
324+
}
325+
else if(mode == VIPER_MODE_HEARTBEAT)
326+
{
327+
return 100;
328+
}
329+
else if(mode == VIPER_MODE_MARQUEE)
330+
{
331+
return 300;
332+
}
333+
else
334+
{
335+
return 0;
336+
}
337+
}
338+
}

Controllers/PatriotViperController/PatriotViperController.h

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
\*-----------------------------------------*/
99

1010
#include <string>
11+
#include <map>
1112
#include "i2c_smbus.h"
1213

1314
#pragma once
@@ -42,9 +43,11 @@ enum
4243
VIPER_MODE_MARQUEE = 0x04, /* Marquee mode */
4344
VIPER_MODE_RAINDROP = 0x05, /* Raindrop mode */
4445
VIPER_MODE_AURORA = 0x06, /* Aurora mode */
45-
VIPER_MODE_NEON = 0x08, /* Neon mode */
46+
VIPER_MODE_DIRECT = 0x07, /* Direct mode */
47+
VIPER_MODE_NEON = 0x08, /* Color cycle mode */
4648
};
4749

50+
4851
enum
4952
{
5053
VIPER_SPEED_MIN = 0xC8, /* Slowest speed for non-breathing mode */
@@ -66,7 +69,7 @@ class PatriotViperController
6669
unsigned int GetLEDCount();
6770
unsigned int GetSlotCount();
6871
unsigned int GetMode();
69-
void SetMode(unsigned char new_mode, unsigned char new_speed);
72+
void SetMode(unsigned char new_mode, unsigned char new_speed, unsigned int color_mode);
7073
void SetDirect();
7174

7275
void SetAllColors(unsigned char red, unsigned char green, unsigned char blue);
@@ -76,6 +79,10 @@ class PatriotViperController
7679
void SetLEDEffectColor(unsigned int led, unsigned char red, unsigned char green, unsigned char blue);
7780
void SetLEDEffectColor(unsigned int slot, unsigned int led, unsigned char red, unsigned char green, unsigned char blue);
7881

82+
void KeepaliveThread();
83+
void StopKeepaliveThread();
84+
unsigned int GetDelay(unsigned char mode, unsigned int step, unsigned int sub_step, bool loop_end);
85+
7986
void ViperRegisterWrite(viper_register reg, unsigned char val0, unsigned char val1, unsigned char val2);
8087
bool direct;
8188

@@ -87,4 +94,53 @@ class PatriotViperController
8794
viper_dev_id dev;
8895
unsigned char mode;
8996
unsigned char speed;
97+
98+
std::thread* keepalive_thread;
99+
std::atomic<bool> keepalive_thread_run;
100+
std::atomic<int> step;
101+
std::atomic<int> sub_step;
102+
std::condition_variable thread_ctrl;
103+
std::mutex thread_ctrl_m;
104+
105+
106+
/*-------------------------------------------------------*\
107+
| Value -1 means mode is not synced, doesn't have steps |
108+
| and the Keepalive thread is not needed |
109+
\*-------------------------------------------------------*/
110+
111+
std::map <int, int> mode_steps =
112+
{
113+
{VIPER_MODE_DARK, -1},
114+
{VIPER_MODE_BREATHING, 4},
115+
{VIPER_MODE_VIPER, 4},
116+
{VIPER_MODE_HEARTBEAT, 6},
117+
{VIPER_MODE_MARQUEE, 3},
118+
{VIPER_MODE_RAINDROP, -1},
119+
{VIPER_MODE_AURORA, 4},
120+
{VIPER_MODE_NEON, 0},
121+
};
122+
123+
std::map <int, int> mode_sub_steps =
124+
{
125+
{VIPER_MODE_DARK, -1},
126+
{VIPER_MODE_BREATHING, 1},
127+
{VIPER_MODE_VIPER, 6},
128+
{VIPER_MODE_HEARTBEAT, 59},
129+
{VIPER_MODE_MARQUEE, 30},
130+
{VIPER_MODE_RAINDROP, -1},
131+
{VIPER_MODE_AURORA, 0},
132+
{VIPER_MODE_NEON, 5},
133+
};
134+
135+
std::map <int, int> mode_speed =
136+
{
137+
{VIPER_MODE_DARK, -1},
138+
{VIPER_MODE_BREATHING, 0x06},
139+
{VIPER_MODE_VIPER, 0x3C},
140+
{VIPER_MODE_HEARTBEAT, 0x3C},
141+
{VIPER_MODE_MARQUEE, 0x3C},
142+
{VIPER_MODE_RAINDROP, -1},
143+
{VIPER_MODE_AURORA, 0x3C},
144+
{VIPER_MODE_NEON, 0x3C},
145+
};
90146
};

0 commit comments

Comments
 (0)