diff --git a/Controllers/PatriotViperController/PatriotViperController.cpp b/Controllers/PatriotViperController/PatriotViperController.cpp index 2bb204cb..3c9e6b87 100644 --- a/Controllers/PatriotViperController/PatriotViperController.cpp +++ b/Controllers/PatriotViperController/PatriotViperController.cpp @@ -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 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; + } + } +} \ No newline at end of file diff --git a/Controllers/PatriotViperController/PatriotViperController.h b/Controllers/PatriotViperController/PatriotViperController.h index a5677ee8..57d8dcc0 100644 --- a/Controllers/PatriotViperController/PatriotViperController.h +++ b/Controllers/PatriotViperController/PatriotViperController.h @@ -8,6 +8,7 @@ \*-----------------------------------------*/ #include +#include #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 keepalive_thread_run; + std::atomic step; + std::atomic 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 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 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 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}, + }; }; diff --git a/Controllers/PatriotViperController/RGBController_PatriotViper.cpp b/Controllers/PatriotViperController/RGBController_PatriotViper.cpp index 5fe31dd0..f538d0eb 100644 --- a/Controllers/PatriotViperController/RGBController_PatriotViper.cpp +++ b/Controllers/PatriotViperController/RGBController_PatriotViper.cpp @@ -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); } }