Files
OpenRGB/Controllers/AlienwareController/RGBController_Alienware.cpp

357 lines
15 KiB
C++

/*---------------------------------------------------------*\
| RGBController_Alienware.cpp |
| |
| RGBController for Dell Alienware RGB USB controller |
| |
| Gabriel Marcano (gemarcano) 19 Apr 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <thread>
#include <chrono>
#include "RGBController_Alienware.h"
/**------------------------------------------------------------------*\
@name Alienware
@category Keyboard
@type USB
@save :x:
@direct :x:
@effects :white_check_mark:
@detectors DetectAlienwareControllers
@comment
\*-------------------------------------------------------------------*/
RGBController_Alienware::RGBController_Alienware(AlienwareController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetDeviceName();
vendor = "Alienware";
type = DEVICE_TYPE_KEYBOARD;
description = "Alienware USB Device";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
version = controller->GetFirmwareVersion();
mode Color;
Color.name = "Static";
Color.value = ALIENWARE_MODE_COLOR;
Color.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Color.color_mode = MODE_COLORS_PER_LED;
Color.colors_min = 1;
Color.colors_max = 1;
Color.brightness_min = 100;
Color.brightness_max = 0;
Color.brightness = 0;
modes.push_back(Color);
mode Pulse;
Pulse.name = "Flashing";
Pulse.value = ALIENWARE_MODE_PULSE;
Pulse.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE;
Pulse.color_mode = MODE_COLORS_PER_LED;
Pulse.colors_min = 1;
Pulse.colors_max = 1;
Pulse.speed_min = ALIENWARE_TEMPO_MAX;
Pulse.speed_max = 50;
Pulse.speed = 150;
Pulse.brightness_min = 100;
Pulse.brightness_max = 0;
Pulse.brightness = 0;
modes.push_back(Pulse);
mode Morph;
Morph.name = "Morph";
Morph.value = ALIENWARE_MODE_MORPH;
Morph.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE;
Morph.color_mode = MODE_COLORS_MODE_SPECIFIC;
Morph.colors_min = 2;
Morph.colors_max = 2 * controller->GetLedCount();
Morph.colors.resize(2);
Morph.colors[0] = 0x0000FF;
Morph.colors[1] = 0xFF0000;
Morph.speed_min = ALIENWARE_TEMPO_MAX;
Morph.speed_max = 20;
Morph.speed = 100;
Morph.brightness_min = 100;
Morph.brightness_max = 0;
Morph.brightness = 0;
modes.push_back(Morph);
mode Spectrum;
Spectrum.name = "Spectrum Cycle";
Spectrum.value = ALIENWARE_MODE_SPECTRUM;
Spectrum.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE;
Spectrum.color_mode = MODE_COLORS_NONE;
Spectrum.speed_min = ALIENWARE_TEMPO_MAX;
Spectrum.speed_max = ALIENWARE_TEMPO_SPECTRUM;
Spectrum.speed = 40;
Spectrum.brightness_min = 100;
Spectrum.brightness_max = 0;
Spectrum.brightness = 0;
modes.push_back(Spectrum);
mode Rainbow;
Rainbow.name = "Rainbow Wave";
Rainbow.value = ALIENWARE_MODE_RAINBOW;
Rainbow.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_MANUAL_SAVE;
Rainbow.color_mode = MODE_COLORS_NONE;
Rainbow.speed_min = ALIENWARE_TEMPO_MAX;
Rainbow.speed_max = ALIENWARE_TEMPO_SPECTRUM;
Rainbow.speed = 40;
Rainbow.direction = MODE_DIRECTION_RIGHT;
Rainbow.brightness_min = 100;
Rainbow.brightness_max = 0;
Rainbow.brightness = 0;
modes.push_back(Rainbow);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = ALIENWARE_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.speed_min = ALIENWARE_TEMPO_MAX;
Breathing.speed_max = 50;
Breathing.speed = 150;
Breathing.brightness_min = 100;
Breathing.brightness_max = 0;
Breathing.brightness = 0;
modes.push_back(Breathing);
mode Direct;
Direct.name = "Direct";
Direct.value = ALIENWARE_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Direct.color_mode = MODE_COLORS_PER_LED;
Direct.colors_min = 1;
Direct.colors_max = 1;
Direct.brightness_min = 100;
Direct.brightness_max = 0;
Direct.brightness = 0;
modes.push_back(Direct);
SetupZones();
controller->UpdateDim();
}
RGBController_Alienware::~RGBController_Alienware()
{
Shutdown();
delete controller;
}
void RGBController_Alienware::SetupZones()
{
/*-------------------------------------------------*\
| Set zones and leds |
\*-------------------------------------------------*/
std::vector<const char*> zone_names = controller->GetZoneNames();
std::vector<unsigned int> zone_led_counts = controller->GetZoneLedCounts();
/*-------------------------------------------------*\
| Pad short name tables |
\*-------------------------------------------------*/
if(zone_names.size() < controller->GetZoneCount())
{
zone_names.resize(controller->GetZoneCount(), "Unknown");
}
if(zone_led_counts.size() < controller->GetZoneCount())
{
zone_led_counts.resize(controller->GetZoneCount(), 1);
}
for(unsigned int zone_idx = 0; zone_idx < controller->GetZoneCount(); zone_idx++)
{
zone new_zone;
new_zone.name = zone_names[zone_idx];
new_zone.type = (zone_led_counts[zone_idx] > 1) ? ZONE_TYPE_LINEAR : ZONE_TYPE_SINGLE;
new_zone.leds_min = zone_led_counts[zone_idx];
new_zone.leds_max = zone_led_counts[zone_idx];
new_zone.leds_count = zone_led_counts[zone_idx];
zones.emplace_back(new_zone);
}
for(unsigned int zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
for(unsigned int led_idx = 0; led_idx < zones[zone_idx].leds_count; led_idx++)
{
led new_led;
new_led.name = zones[zone_idx].name + std::string(" LED ") + std::to_string(led_idx + 1);
leds.emplace_back(new_led);
}
}
SetupColors();
}
void RGBController_Alienware::DeviceUpdateLEDs()
{
DeviceUpdateMode();
}
void RGBController_Alienware::DeviceUpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_Alienware::DeviceUpdateSingleLED(int led)
{
DeviceUpdateZoneLEDs(led);
}
static bool modes_eq(const mode& mode1, const mode& mode2)
{
return( ( mode1.name == mode2.name )
&& ( mode1.value == mode2.value )
&& ( mode1.flags == mode2.flags )
&& ( mode1.speed_min == mode2.speed_min )
&& ( mode1.speed_max == mode2.speed_max )
&& ( mode1.colors_min == mode2.colors_min )
&& ( mode1.colors_max == mode2.colors_max )
&& ( mode1.speed == mode2.speed )
&& ( mode1.direction == mode2.direction )
&& ( mode1.color_mode == mode2.color_mode )
&& ( mode1.colors == mode2.colors )
&& ( mode1.brightness == mode2.brightness )
&& ( mode1.brightness_min == mode2.brightness_min )
&& ( mode1.brightness_max == mode2.brightness_max ) );
}
void RGBController_Alienware::DeviceUpdateMode()
{
/*---------------------------------------------------------*\
| Copy mode to get the current state-- this is racy, as the |
| UI thread can be actively modifying this variable |
\*---------------------------------------------------------*/
int current_mode_idx = active_mode;
mode current_mode = modes[current_mode_idx];
bool done = false;
while(!done)
{
/*-----------------------------------------------------*\
| Direct skips animation programming |
\*-----------------------------------------------------*/
bool direct_update = (current_mode.value == ALIENWARE_MODE_DIRECT);
/*-----------------------------------------------------*\
| Setup state per LED |
\*-----------------------------------------------------*/
unsigned int led_global_idx = 0;
for(size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
zone current_zone = zones[zone_idx];
/*-------------------------------------------------*\
| Some modes use 2000ms (0x07D0) for their duration,|
| per traces |
\*-------------------------------------------------*/
uint16_t period = 0x07d0;
uint8_t hw_idx = (uint8_t)zone_idx;
controller->SetMode( hw_idx, direct_update ? (uint8_t)ALIENWARE_MODE_DIRECT : current_mode.value);
controller->SetDirection(hw_idx, current_mode.direction);
for(unsigned int led_in_zone = 0; led_in_zone < current_zone.leds_count; led_in_zone++, led_global_idx++)
{
RGBColor led_color = (led_global_idx < colors.size()) ? colors[led_global_idx] : 0x000000;
switch(current_mode_idx)
{
case ALIENWARE_MODE_COLOR:
controller->SetPeriod( hw_idx, period);
controller->SetLedColor(led_global_idx, led_color);
controller->SetTempo( hw_idx, ALIENWARE_TEMPO_MAX);
controller->SetDim( hw_idx, modes[current_mode_idx].brightness);
break;
case ALIENWARE_MODE_PULSE:
period = std::max<uint16_t>(500, (uint16_t)(current_mode.speed * 10));
controller->SetPeriod( hw_idx, period);
controller->SetLedColor(led_global_idx, led_color);
controller->SetTempo( hw_idx, current_mode.speed);
controller->SetDim( hw_idx, modes[current_mode_idx].brightness);
break;
case ALIENWARE_MODE_MORPH:
{
RGBColor c1 = (current_mode.colors.size() >= 1) ? current_mode.colors[0] : 0x0000FF;
RGBColor c2 = (current_mode.colors.size() >= 2) ? current_mode.colors[1] : 0xFF0000;
if(current_mode.colors.size() >= (std::size_t)((led_global_idx + 1) * 2))
{
c1 = current_mode.colors[led_global_idx * 2];
c2 = current_mode.colors[(led_global_idx * 2) + 1];
}
period = std::max<uint16_t>(400, (uint16_t)(current_mode.speed * 10));
controller->SetPeriod( hw_idx, period);
controller->SetLedColor(led_global_idx, c1, c2);
controller->SetTempo( hw_idx, current_mode.speed);
controller->SetDim( hw_idx, modes[current_mode_idx].brightness);
}
break;
case ALIENWARE_MODE_SPECTRUM:
case ALIENWARE_MODE_RAINBOW:
controller->SetPeriod(hw_idx, ALIENWARE_DURATION_SPECTRUM);
controller->SetTempo( hw_idx, current_mode.speed);
controller->SetDim( hw_idx, modes[current_mode_idx].brightness);
break;
case ALIENWARE_MODE_BREATHING:
period = std::max<uint16_t>(500, (uint16_t)(current_mode.speed * 10));
controller->SetPeriod( hw_idx, period);
controller->SetLedColor(led_global_idx, led_color, 0x0);
controller->SetTempo( hw_idx, current_mode.speed);
controller->SetDim( hw_idx, modes[current_mode_idx].brightness);
break;
case ALIENWARE_MODE_DIRECT:
controller->SetLedColor(led_global_idx, led_color);
controller->SetDim( hw_idx, modes[current_mode_idx].brightness);
break;
}
}
}
/*-----------------------------------------------------*\
| Due to rate-limiting, this can take more than one |
| second to execute |
\*-----------------------------------------------------*/
controller->UpdateController();
/*-----------------------------------------------------*\
| Re-run update if there's anything that's changed from |
| under us... |
\*-----------------------------------------------------*/
int new_current_mode_idx = active_mode;
mode new_current_mode = modes[current_mode_idx];
done = (current_mode_idx == new_current_mode_idx && modes_eq(new_current_mode, current_mode));
current_mode_idx = new_current_mode_idx;
current_mode = new_current_mode;
}
}
void RGBController_Alienware::DeviceSaveMode()
{
controller->SaveController();
}