Publish LumaOps source
This commit is contained in:
@@ -0,0 +1,384 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| CMARGBGen2A1Controller.cpp |
|
||||
| |
|
||||
| Driver for Cooler Master ARGB Gen 2 A1 controller |
|
||||
| |
|
||||
| Morgan Guimard (morg) 26 Jun 2022 |
|
||||
| Fabian R (kderazorback) 11 Aug 2023 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <cstring>
|
||||
#include "CMARGBGen2A1Controller.h"
|
||||
#include "StringUtils.h"
|
||||
|
||||
CMARGBGen2A1controller::CMARGBGen2A1controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
|
||||
{
|
||||
dev = dev_handle;
|
||||
location = info.path;
|
||||
name = dev_name;
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Setup direct mode on start |
|
||||
\*---------------------------------------------*/
|
||||
SetupDirectMode();
|
||||
}
|
||||
|
||||
CMARGBGen2A1controller::~CMARGBGen2A1controller()
|
||||
{
|
||||
hid_close(dev);
|
||||
}
|
||||
|
||||
std::string CMARGBGen2A1controller::GetDeviceLocation()
|
||||
{
|
||||
return("HID: " + location);
|
||||
}
|
||||
|
||||
std::string CMARGBGen2A1controller::GetNameString()
|
||||
{
|
||||
return(name);
|
||||
}
|
||||
|
||||
std::string CMARGBGen2A1controller::GetSerialString()
|
||||
{
|
||||
wchar_t serial_string[128];
|
||||
int ret = hid_get_serial_number_string(dev, serial_string, 128);
|
||||
|
||||
if(ret != 0)
|
||||
{
|
||||
return("");
|
||||
}
|
||||
|
||||
return(StringUtils::wstring_to_string(serial_string));
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::SaveToFlash()
|
||||
{
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
|
||||
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_FLASH;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_LONG));
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::SetupDirectMode()
|
||||
{
|
||||
ResetDevice();
|
||||
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Swith to direct mode |
|
||||
\*---------------------------------------------*/
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_HW_MODE_SETUP;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
usb_buf[4] = CM_ARGB_GEN2_A1_CHANNEL_ALL; // CHANNEL
|
||||
usb_buf[5] = CM_ARGB_GEN2_A1_SUBCHANNEL_ALL; // SUBCHANNEL
|
||||
usb_buf[6] = CM_ARGB_GEN2_A1_CUSTOM_MODE;
|
||||
usb_buf[7] = CM_ARGB_GEN2_A1_SPEED_HALF;
|
||||
usb_buf[8] = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
usb_buf[9] = 0xFF; // R
|
||||
usb_buf[10] = 0xFF; // G
|
||||
usb_buf[11] = 0xFF; // B
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_SHORT));
|
||||
|
||||
std::vector<RGBColor> colorOffChain;
|
||||
colorOffChain.push_back(0);
|
||||
for(unsigned int channel = 0; channel < CM_ARGB_GEN2_A1_CHANNEL_COUNT; channel++)
|
||||
{
|
||||
SendChannelColors(channel, CM_ARGB_GEN2_A1_SUBCHANNEL_ALL, colorOffChain);
|
||||
}
|
||||
|
||||
for(unsigned int channel = 0; channel < CM_ARGB_GEN2_A1_CHANNEL_COUNT; channel++)
|
||||
{
|
||||
SetCustomSequence(channel);
|
||||
}
|
||||
|
||||
software_mode_activated = true;
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::SetupZoneSize(unsigned int zone_id, unsigned int size)
|
||||
{
|
||||
/*---------------------------------------------*\
|
||||
| Set the mode sequence to full static |
|
||||
| (01 for static) |
|
||||
| |
|
||||
| This device stores 2 distinct values |
|
||||
| - effect speed |
|
||||
| - approximated zone size |
|
||||
| |
|
||||
| It's probably based on standard ARGB sizes |
|
||||
| Still, the 06 value has some mystery. |
|
||||
| |
|
||||
| ES= effect speed |
|
||||
| LC= LEDs count |
|
||||
| |
|
||||
| ES LC |
|
||||
| ----- |
|
||||
| 0a 06 |
|
||||
| 09 06 |
|
||||
| 08 07 |
|
||||
| 07 08 |
|
||||
| 06 0a |
|
||||
| 05 0c |
|
||||
| 04 0f |
|
||||
| 03 14 |
|
||||
| 02 1e |
|
||||
| 01 3c |
|
||||
\*---------------------------------------------*/
|
||||
|
||||
const unsigned char gaps[10] =
|
||||
{
|
||||
0x05, 0x06, 0x07, 0x08, 0x0A, 0x0C, 0x0F, 0x14, 0x1E, 0x3C
|
||||
};
|
||||
|
||||
unsigned char speed = 0x0A;
|
||||
|
||||
for(unsigned int g = 0; g < 10; g++)
|
||||
{
|
||||
if(size <= gaps[g])
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
speed--;
|
||||
}
|
||||
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
|
||||
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_SIZES;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
usb_buf[4] = 1 << zone_id;
|
||||
|
||||
usb_buf[5] = speed;
|
||||
usb_buf[6] = size;
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_LONG));
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Refresh direct mode to cycle the strips |
|
||||
| with the new length |
|
||||
\*---------------------------------------------*/
|
||||
if(software_mode_activated)
|
||||
{
|
||||
SetupDirectMode();
|
||||
}
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::SendChannelColors(unsigned int zone_id, unsigned int subchannel_id, std::vector<RGBColor> colors)
|
||||
{
|
||||
/*---------------------------------------------*\
|
||||
| Create the color data array |
|
||||
\*---------------------------------------------*/
|
||||
std::vector<unsigned char> color_data = CreateColorData(colors);
|
||||
|
||||
std::vector<unsigned char>::iterator it = color_data.begin();
|
||||
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
|
||||
unsigned int offset;
|
||||
|
||||
/*----------------------------------------------------*\
|
||||
| Break-up color data in packet/s |
|
||||
| Intentionally clearing first packet only |
|
||||
| Leaving garbage on subsequent packets |
|
||||
| Original software appears to not clear them anyways. |
|
||||
\*----------------------------------------------------*/
|
||||
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
for(unsigned int p = 0; p < CM_ARGB_GEN2_A1_PACKETS_PER_CHANNEL && it != color_data.end(); p++)
|
||||
{
|
||||
offset = 1;
|
||||
|
||||
usb_buf[offset++] = p;
|
||||
usb_buf[offset++] = CM_ARGB_GEN2_A1_SET_RGB_VALUES;
|
||||
usb_buf[offset++] = CM_ARGB_GEN2_A1_WRITE;
|
||||
usb_buf[offset++] = 1 << zone_id;
|
||||
usb_buf[offset++] = 1 << subchannel_id;
|
||||
|
||||
while(it != color_data.end() && offset < CM_ARGB_GEN2_A1_PACKET_LENGTH)
|
||||
{
|
||||
usb_buf[offset++] = *it;
|
||||
it++;
|
||||
}
|
||||
|
||||
if(p >= CM_ARGB_GEN2_A1_PACKETS_PER_CHANNEL - 1 || it == color_data.end())
|
||||
{
|
||||
/*--------------------------*\
|
||||
| Rewrite as end packet |
|
||||
\*--------------------------*/
|
||||
usb_buf[1] = p + 0x80;
|
||||
}
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
/*-----------------------------------------------*\
|
||||
| This device needs some delay before we send |
|
||||
| any other packet :( |
|
||||
| This time is critical since the device is |
|
||||
| still latching its input buffer. |
|
||||
| Reducing this may start to introduce artifacts |
|
||||
\*-----------------------------------------------*/
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_MEDIUM));
|
||||
}
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Next channel needs some delay as well |
|
||||
\*---------------------------------------------*/
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_SHORT));
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::SetMode(unsigned int mode_value, unsigned char speed, unsigned char brightness, RGBColor color, bool random)
|
||||
{
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Switch to hardware mode if needed |
|
||||
\*---------------------------------------------*/
|
||||
if(software_mode_activated)
|
||||
{
|
||||
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_LIGHTNING_CONTROL;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
software_mode_activated = false;
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_LONG));
|
||||
}
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Set the mode values and write to the device |
|
||||
\*---------------------------------------------*/
|
||||
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_HW_MODE_SETUP;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
|
||||
usb_buf[4] = CM_ARGB_GEN2_A1_CHANNEL_ALL;
|
||||
usb_buf[5] = CM_ARGB_GEN2_A1_SUBCHANNEL_ALL;
|
||||
|
||||
usb_buf[6] = mode_value;
|
||||
|
||||
bool is_custom_mode = (mode_value == CM_ARGB_GEN2_A1_CUSTOM_MODE);
|
||||
|
||||
if(is_custom_mode)
|
||||
{
|
||||
usb_buf[7] = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
usb_buf[8] = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
usb_buf[9] = 0xFF; // R
|
||||
usb_buf[10] = 0xFF; // G
|
||||
usb_buf[11] = 0xFF; // B
|
||||
}
|
||||
else
|
||||
{
|
||||
usb_buf[7] = speed;
|
||||
usb_buf[8] = brightness;
|
||||
usb_buf[9] = RGBGetRValue(color);
|
||||
usb_buf[10] = RGBGetGValue(color);
|
||||
usb_buf[11] = RGBGetBValue(color);
|
||||
usb_buf[12] = random;
|
||||
}
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_LONG));
|
||||
|
||||
if(is_custom_mode)
|
||||
{
|
||||
for(unsigned int channel = 0; channel < CM_ARGB_GEN2_A1_CHANNEL_COUNT; channel++)
|
||||
{
|
||||
SetCustomSequence(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> CMARGBGen2A1controller::CreateColorData(std::vector<RGBColor> colors)
|
||||
{
|
||||
std::vector<unsigned char> color_data;
|
||||
|
||||
for(unsigned int c = 0; c < colors.size(); c++)
|
||||
{
|
||||
color_data.push_back(RGBGetRValue(colors[c]));
|
||||
color_data.push_back(RGBGetGValue(colors[c]));
|
||||
color_data.push_back(RGBGetBValue(colors[c]));
|
||||
}
|
||||
|
||||
return(color_data);
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::SetCustomSequence(unsigned int zone_id)
|
||||
{
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
|
||||
/*---------------------------------------------*\
|
||||
| Set custom speed for sequence mode |
|
||||
\*---------------------------------------------*/
|
||||
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_CUSTOM_SPEED;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
usb_buf[4] = 1 << zone_id; // CHANNEL
|
||||
usb_buf[5] = 0x32;
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_SHORT));
|
||||
|
||||
SetPipelineStaticSequence(zone_id);
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::SetPipelineStaticSequence(unsigned int zone_id)
|
||||
{
|
||||
/*------------------------------------------------*\
|
||||
| Set the mode sequence to full static |
|
||||
| All steps on the effect pipeline to 0x01 STATIC |
|
||||
\*------------------------------------------------*/
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
memset(usb_buf, CM_ARGB_GEN2_A1_STATIC_MODE, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
usb_buf[0] = 0x00;
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_CUSTOM_SEQUENCES;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
usb_buf[4] = 1 << zone_id;
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_LONG));
|
||||
}
|
||||
|
||||
void CMARGBGen2A1controller::ResetDevice()
|
||||
{
|
||||
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
|
||||
|
||||
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
usb_buf[1] = CM_ARGB_GEN2_A1_COMMAND;
|
||||
usb_buf[2] = CM_ARGB_GEN2_A1_RESET;
|
||||
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
|
||||
|
||||
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(CM_ARGB_GEN2_A1_SLEEP_LONG));
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| CMARGBGen2A1Controller.h |
|
||||
| |
|
||||
| Driver for Cooler Master ARGB Gen 2 A1 controller |
|
||||
| |
|
||||
| Morgan Guimard (morg) 26 Jun 2022 |
|
||||
| Fabian R (kderazorback) 11 Aug 2023 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <hidapi.h>
|
||||
#include "RGBController.h"
|
||||
|
||||
#define CM_ARGB_GEN2_A1_PACKET_LENGTH 65
|
||||
#define CM_ARGB_GEN2_A1_CHANNEL_MAX_SIZE 72
|
||||
#define CM_ARGB_GEN2_A1_CHANNEL_COUNT 3
|
||||
#define CM_ARGB_GEN2_A1_PACKETS_PER_CHANNEL 2
|
||||
|
||||
#define CM_ARGB_GEN2_A1_SLEEP_SHORT 5
|
||||
#define CM_ARGB_GEN2_A1_SLEEP_MEDIUM 45
|
||||
#define CM_ARGB_GEN2_A1_SLEEP_LONG 70
|
||||
|
||||
enum
|
||||
{
|
||||
CM_ARGB_GEN2_A1_DIRECT_MODE = 0xFF,
|
||||
CM_ARGB_GEN2_A1_SPECTRUM_MODE = 0x00,
|
||||
CM_ARGB_GEN2_A1_STATIC_MODE = 0x01,
|
||||
CM_ARGB_GEN2_A1_RELOAD_MODE = 0x02,
|
||||
CM_ARGB_GEN2_A1_RECOIL_MODE = 0x03,
|
||||
CM_ARGB_GEN2_A1_BREATHING_MODE = 0x04,
|
||||
CM_ARGB_GEN2_A1_REFILL_MODE = 0x05,
|
||||
CM_ARGB_GEN2_A1_DEMO_MODE = 0x06,
|
||||
CM_ARGB_GEN2_A1_FILL_FLOW_MODE = 0x07,
|
||||
CM_ARGB_GEN2_A1_RAINBOW_MODE = 0x08,
|
||||
CM_ARGB_GEN2_A1_CUSTOM_MODE = 0xC0,
|
||||
CM_ARGB_GEN2_A1_OFF_MODE = 0x09
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CM_ARGB_GEN2_A1_BRIGHTNESS_MAX = 0xFF,
|
||||
CM_ARGB_GEN2_A1_BRIGHTNESS_MIN = 0x00,
|
||||
CM_ARGB_GEN2_A1_SPEED_MAX = 0x04,
|
||||
CM_ARGB_GEN2_A1_SPEED_HALF = 0x02,
|
||||
CM_ARGB_GEN2_A1_SPEED_MIN = 0x00,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CM_ARGB_GEN2_A1_COMMAND = 0x80,
|
||||
CM_ARGB_GEN2_A1_COMMAND_EXTRA_1 = 0x81,
|
||||
CM_ARGB_GEN2_A1_COMMAND_EXTRA_2 = 0x82,
|
||||
CM_ARGB_GEN2_A1_READ = 0x01,
|
||||
CM_ARGB_GEN2_A1_WRITE = 0x02,
|
||||
CM_ARGB_GEN2_A1_RESPONSE = 0x03
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CM_ARGB_GEN2_A1_SIZES = 0x06,
|
||||
CM_ARGB_GEN2_A1_SET_RGB_VALUES = 0x08,
|
||||
CM_ARGB_GEN2_A1_FLASH = 0x0B,
|
||||
CM_ARGB_GEN2_A1_IDENTIFY = 0x0A,
|
||||
CM_ARGB_GEN2_A1_LIGHTNING_CONTROL = 0x01,
|
||||
CM_ARGB_GEN2_A1_HW_MODE_SETUP = 0x03,
|
||||
CM_ARGB_GEN2_A1_CUSTOM_SEQUENCES = 0x10,
|
||||
CM_ARGB_GEN2_A1_CUSTOM_SPEED = 0x11,
|
||||
CM_ARGB_GEN2_A1_RESET = 0xC0,
|
||||
CM_ARGB_GEN2_A1_APPLY_CHANGES = 0xB0
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
CM_ARGB_GEN2_A1_CHANNEL_A = 0x01,
|
||||
CM_ARGB_GEN2_A1_CHANNEL_B = 0x02,
|
||||
CM_ARGB_GEN2_A1_CHANNEL_C = 0x04,
|
||||
CM_ARGB_GEN2_A1_CHANNEL_ALL = 0xFF,
|
||||
CM_ARGB_GEN2_A1_SUBCHANNEL_ALL = 0xFF
|
||||
};
|
||||
|
||||
class CMARGBGen2A1controller
|
||||
{
|
||||
public:
|
||||
CMARGBGen2A1controller(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
|
||||
~CMARGBGen2A1controller();
|
||||
|
||||
std::string GetDeviceLocation();
|
||||
std::string GetNameString();
|
||||
std::string GetSerialString();
|
||||
|
||||
void SendChannelColors(unsigned int zone_id, unsigned int subchannel_id, std::vector<RGBColor> colors);
|
||||
void SetupZoneSize(unsigned int zone_id, unsigned int size);
|
||||
void SetupDirectMode();
|
||||
void SetMode(unsigned int mode_value, unsigned char speed, unsigned char brightness, RGBColor color, bool random);
|
||||
void SetCustomColors(unsigned int zone_id, std::vector<RGBColor> colors);
|
||||
void SaveToFlash();
|
||||
|
||||
private:
|
||||
std::string location;
|
||||
std::string name;
|
||||
bool software_mode_activated = false;
|
||||
hid_device* dev;
|
||||
|
||||
void SetCustomSequence(unsigned int zone_id);
|
||||
void SetPipelineStaticSequence(unsigned int zone_id);
|
||||
std::vector<unsigned char> CreateColorData(std::vector<RGBColor> colors);
|
||||
void ResetDevice();
|
||||
};
|
||||
+340
@@ -0,0 +1,340 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_CMARGBGen2A1Controller.cpp |
|
||||
| |
|
||||
| Driver for Cooler Master ARGB Gen 2 A1 controller |
|
||||
| |
|
||||
| Morgan Guimard (morg) 26 Jun 2022 |
|
||||
| Fabian R (kderazorback) 11 Aug 2023 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "RGBController_CMARGBGen2A1Controller.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name Coolermaster ARGB A1
|
||||
@category LEDStrip
|
||||
@type USB
|
||||
@save :white_check_mark:
|
||||
@direct :white_check_mark:
|
||||
@effects :white_check_mark:
|
||||
@detectors DetectCoolerMasterARGBGen2A1
|
||||
@comment OpenRGB partially supports Gen 2 protocol for this device.
|
||||
|
||||
Gen2 has auto-resize feature and parallel to serial magical stuff,
|
||||
Strip size is auto detected by the controller but not reported
|
||||
back to OpenRGB. Configure zones and segments for each channel
|
||||
to allow individual addressing.
|
||||
Take note that this controller is extremely slow, using fast
|
||||
update rates may introduce color artifacts.<
|
||||
\*-------------------------------------------------------------------*/
|
||||
|
||||
RGBController_CMARGBGen2A1Controller::RGBController_CMARGBGen2A1Controller(CMARGBGen2A1controller* controller_ptr)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
|
||||
name = controller->GetNameString();
|
||||
vendor = "CoolerMaster";
|
||||
type = DEVICE_TYPE_LEDSTRIP;
|
||||
description = "CoolerMaster LED Controller A1 Device";
|
||||
location = controller->GetDeviceLocation();
|
||||
serial = controller->GetSerialString();
|
||||
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.value = CM_ARGB_GEN2_A1_DIRECT_MODE;
|
||||
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
|
||||
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||
modes.push_back(Direct);
|
||||
|
||||
mode Spectrum;
|
||||
Spectrum.name = "Spectrum";
|
||||
Spectrum.value = CM_ARGB_GEN2_A1_SPECTRUM_MODE;
|
||||
Spectrum.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE;
|
||||
Spectrum.color_mode = MODE_COLORS_NONE;
|
||||
Spectrum.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Spectrum.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Spectrum.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Spectrum.speed = CM_ARGB_GEN2_A1_SPEED_MAX/2;
|
||||
Spectrum.speed_min = CM_ARGB_GEN2_A1_SPEED_MIN;
|
||||
Spectrum.speed_max = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
modes.push_back(Spectrum);
|
||||
|
||||
mode Static;
|
||||
Static.name = "Static";
|
||||
Static.value = CM_ARGB_GEN2_A1_STATIC_MODE;
|
||||
Static.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_MANUAL_SAVE;
|
||||
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Static.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Static.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Static.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Static.colors.resize(1);
|
||||
modes.push_back(Static);
|
||||
|
||||
mode Reload;
|
||||
Reload.name = "Reload";
|
||||
Reload.value = CM_ARGB_GEN2_A1_RELOAD_MODE;
|
||||
Reload.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_MANUAL_SAVE;
|
||||
Reload.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Reload.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Reload.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Reload.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Reload.speed = CM_ARGB_GEN2_A1_SPEED_MAX/2;
|
||||
Reload.speed_min = CM_ARGB_GEN2_A1_SPEED_MIN;
|
||||
Reload.speed_max = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
Reload.colors.resize(1);
|
||||
modes.push_back(Reload);
|
||||
|
||||
mode Recoil;
|
||||
Recoil.name = "Recoil";
|
||||
Recoil.value = CM_ARGB_GEN2_A1_RECOIL_MODE;
|
||||
Recoil.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_MANUAL_SAVE;
|
||||
Recoil.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Recoil.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Recoil.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Recoil.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Recoil.speed = CM_ARGB_GEN2_A1_SPEED_MAX/2;
|
||||
Recoil.speed_min = CM_ARGB_GEN2_A1_SPEED_MIN;
|
||||
Recoil.speed_max = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
Recoil.colors.resize(1);
|
||||
modes.push_back(Recoil);
|
||||
|
||||
mode Breathing;
|
||||
Breathing.name = "Breathing";
|
||||
Breathing.value = CM_ARGB_GEN2_A1_BREATHING_MODE;
|
||||
Breathing.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_MANUAL_SAVE;
|
||||
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Breathing.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Breathing.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Breathing.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Breathing.speed = CM_ARGB_GEN2_A1_SPEED_MAX/2;
|
||||
Breathing.speed_min = CM_ARGB_GEN2_A1_SPEED_MIN;
|
||||
Breathing.speed_max = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
Breathing.colors.resize(1);
|
||||
modes.push_back(Breathing);
|
||||
|
||||
|
||||
mode Refill;
|
||||
Refill.name = "Refill";
|
||||
Refill.value = CM_ARGB_GEN2_A1_REFILL_MODE;
|
||||
Refill.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_MANUAL_SAVE;
|
||||
Refill.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
Refill.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Refill.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Refill.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Refill.speed = CM_ARGB_GEN2_A1_SPEED_MAX/2;
|
||||
Refill.speed_min = CM_ARGB_GEN2_A1_SPEED_MIN;
|
||||
Refill.speed_max = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
Refill.colors.resize(1);
|
||||
modes.push_back(Refill);
|
||||
|
||||
mode Demo;
|
||||
Demo.name = "Demo";
|
||||
Demo.value = CM_ARGB_GEN2_A1_DEMO_MODE;
|
||||
Demo.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Demo.color_mode = MODE_COLORS_NONE;
|
||||
Demo.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Demo.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Demo.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
modes.push_back(Demo);
|
||||
|
||||
mode FillFlow;
|
||||
FillFlow.name = "Fill Flow";
|
||||
FillFlow.value = CM_ARGB_GEN2_A1_FILL_FLOW_MODE;
|
||||
FillFlow.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE;;
|
||||
FillFlow.color_mode = MODE_COLORS_NONE;
|
||||
FillFlow.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
FillFlow.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
FillFlow.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
FillFlow.speed = CM_ARGB_GEN2_A1_SPEED_MAX/2;
|
||||
FillFlow.speed_min = CM_ARGB_GEN2_A1_SPEED_MIN;
|
||||
FillFlow.speed_max = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
modes.push_back(FillFlow);
|
||||
|
||||
mode Rainbow;
|
||||
Rainbow.name = "Rainbow";
|
||||
Rainbow.value = CM_ARGB_GEN2_A1_RAINBOW_MODE;
|
||||
Rainbow.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_MANUAL_SAVE;;
|
||||
Rainbow.color_mode = MODE_COLORS_NONE;
|
||||
Rainbow.brightness = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Rainbow.brightness_min = CM_ARGB_GEN2_A1_BRIGHTNESS_MIN;
|
||||
Rainbow.brightness_max = CM_ARGB_GEN2_A1_BRIGHTNESS_MAX;
|
||||
Rainbow.speed = CM_ARGB_GEN2_A1_SPEED_MAX/2;
|
||||
Rainbow.speed_min = CM_ARGB_GEN2_A1_SPEED_MIN;
|
||||
Rainbow.speed_max = CM_ARGB_GEN2_A1_SPEED_MAX;
|
||||
modes.push_back(Rainbow);
|
||||
|
||||
mode Custom;
|
||||
Custom.name = "Custom";
|
||||
Custom.value = CM_ARGB_GEN2_A1_CUSTOM_MODE;
|
||||
Custom.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_MANUAL_SAVE;
|
||||
Custom.color_mode = MODE_COLORS_PER_LED;
|
||||
modes.push_back(Custom);
|
||||
|
||||
mode Off;
|
||||
Off.name = "Off";
|
||||
Off.value = CM_ARGB_GEN2_A1_OFF_MODE;
|
||||
Off.flags = MODE_FLAG_MANUAL_SAVE;
|
||||
Off.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Off);
|
||||
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
RGBController_CMARGBGen2A1Controller::~RGBController_CMARGBGen2A1Controller()
|
||||
{
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::SetupZones()
|
||||
{
|
||||
unsigned int total_leds = 0;
|
||||
|
||||
for(unsigned int channel = 0; channel < CM_ARGB_GEN2_A1_CHANNEL_COUNT; channel++)
|
||||
{
|
||||
zone new_zone;
|
||||
|
||||
new_zone.name = "Channel " + std::to_string(channel + 1);
|
||||
new_zone.type = ZONE_TYPE_LINEAR;
|
||||
new_zone.leds_min = 0;
|
||||
new_zone.leds_max = CM_ARGB_GEN2_A1_CHANNEL_MAX_SIZE;
|
||||
new_zone.leds_count = 0;
|
||||
new_zone.matrix_map = nullptr;
|
||||
|
||||
zones.push_back(new_zone);
|
||||
|
||||
total_leds += new_zone.leds_count;
|
||||
}
|
||||
|
||||
leds.resize(total_leds);
|
||||
|
||||
for(unsigned int i = 0; i < total_leds; i++)
|
||||
{
|
||||
leds[i].name = "LED " + std::to_string(i + 1);
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::ResizeZone(int zone, int new_size)
|
||||
{
|
||||
zones[zone].leds_count = new_size;
|
||||
|
||||
unsigned int total_leds = 0;
|
||||
|
||||
for(unsigned int channel = 0; channel < CM_ARGB_GEN2_A1_CHANNEL_COUNT; channel++)
|
||||
{
|
||||
total_leds += zones[channel].leds_count;
|
||||
}
|
||||
|
||||
leds.resize(total_leds);
|
||||
|
||||
for(unsigned int i = 0; i < total_leds; i++)
|
||||
{
|
||||
leds[i].name = "LED " + std::to_string(i + 1);
|
||||
}
|
||||
|
||||
controller->SetupZoneSize(zone, new_size);
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::DeviceUpdateLEDs()
|
||||
{
|
||||
for(unsigned int channel = 0; channel < CM_ARGB_GEN2_A1_CHANNEL_COUNT; channel ++)
|
||||
{
|
||||
if (zones[channel].segments.size() > 0)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
for(std::vector<segment>::iterator it = zones[channel].segments.begin(); it != zones[channel].segments.end(); it++)
|
||||
{
|
||||
UpdateSegmentLEDs(channel, i++);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UpdateSegmentLEDs(channel, CM_ARGB_GEN2_A1_SUBCHANNEL_ALL);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::UpdateZoneLEDs(int zone)
|
||||
{
|
||||
if(zones[zone].leds_count > 0)
|
||||
{
|
||||
unsigned int start = zones[zone].start_idx;
|
||||
unsigned int end = start + zones[zone].leds_count;
|
||||
|
||||
std::vector<RGBColor> zone_colors(colors.begin() + start , colors.begin() + end);
|
||||
|
||||
controller->SendChannelColors(zone, CM_ARGB_GEN2_A1_SUBCHANNEL_ALL, zone_colors);
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::UpdateSegmentLEDs(int zone, int subchannel)
|
||||
{
|
||||
if(zones[zone].leds_count <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int start = zones[zone].start_idx;
|
||||
unsigned int end = start + zones[zone].leds_count;
|
||||
bool use_direct_mode = modes[active_mode].value == CM_ARGB_GEN2_A1_DIRECT_MODE || modes[active_mode].value == CM_ARGB_GEN2_A1_CUSTOM_MODE;
|
||||
|
||||
std::vector<RGBColor> color_vector(colors.begin() + start, colors.begin() + start + end);
|
||||
|
||||
if(use_direct_mode)
|
||||
{
|
||||
if(zones[zone].segments.size() > 0)
|
||||
{
|
||||
start += zones[zone].segments[subchannel].start_idx;
|
||||
end += zones[zone].segments[subchannel].start_idx + zones[zone].segments[subchannel].leds_count;
|
||||
|
||||
color_vector = std::vector<RGBColor>(colors.begin() + start , colors.begin() + end);
|
||||
}
|
||||
|
||||
controller->SendChannelColors(zone, subchannel, color_vector);
|
||||
return;
|
||||
}
|
||||
|
||||
controller->SendChannelColors(zone, CM_ARGB_GEN2_A1_SUBCHANNEL_ALL, color_vector);
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::UpdateSingleLED(int /*led*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::DeviceUpdateMode()
|
||||
{
|
||||
const mode& active = modes[active_mode];
|
||||
|
||||
if(active.value == CM_ARGB_GEN2_A1_DIRECT_MODE)
|
||||
{
|
||||
controller->SetupDirectMode();
|
||||
}
|
||||
else
|
||||
{
|
||||
RGBColor color = active.color_mode == MODE_COLORS_MODE_SPECIFIC ?
|
||||
active.colors[0] : 0;
|
||||
|
||||
controller->SetMode
|
||||
(
|
||||
active.value,
|
||||
active.speed,
|
||||
active.brightness,
|
||||
color,
|
||||
active.color_mode == MODE_COLORS_RANDOM
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void RGBController_CMARGBGen2A1Controller::DeviceSaveMode()
|
||||
{
|
||||
controller->SaveToFlash();
|
||||
}
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_CMARGBGen2A1Controller.h |
|
||||
| |
|
||||
| Driver for Cooler Master ARGB Gen 2 A1 controller |
|
||||
| |
|
||||
| Morgan Guimard (morg) 26 Jun 2022 |
|
||||
| Fabian R (kderazorback) 11 Aug 2023 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include "RGBController.h"
|
||||
#include "CMARGBGen2A1Controller.h"
|
||||
|
||||
class RGBController_CMARGBGen2A1Controller : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_CMARGBGen2A1Controller(CMARGBGen2A1controller* controller_ptr);
|
||||
~RGBController_CMARGBGen2A1Controller();
|
||||
|
||||
void SetupZones();
|
||||
void ResizeZone(int zone, int new_size);
|
||||
void DeviceUpdateLEDs();
|
||||
void UpdateZoneLEDs(int zone);
|
||||
void UpdateSegmentLEDs(int zone, int subchannel);
|
||||
void UpdateSingleLED(int led);
|
||||
void DeviceUpdateMode();
|
||||
void DeviceSaveMode();
|
||||
|
||||
private:
|
||||
CMARGBGen2A1controller* controller;
|
||||
};
|
||||
Reference in New Issue
Block a user