Files
OpenRGB/Controllers/CoolerMasterController/CMARGBGen2A1controller.cpp

374 lines
12 KiB
C++

/*-------------------------------------------------------------------*\
| CMARGBGen2A1controller.cpp |
| |
| Driver for Coolermaster ARGB Gen 2 A1 USB Controller |
| |
| morg (Morgan Guimard) 6/26/2022 |
| |
\*-------------------------------------------------------------------*/
#include "CMARGBGen2A1controller.h"
#include <cstring>
CMARGBGen2A1controller::CMARGBGen2A1controller(hid_device* dev_handle, const hid_device_info& info)
{
dev = dev_handle;
location = info.path;
wchar_t serial_string[128];
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
serial_number = "";
}
else
{
std::wstring return_wstring = serial_string;
serial_number = std::string(return_wstring.begin(), return_wstring.end());
}
/*---------------------------------------------*\
| Setup direct mode on start |
\*---------------------------------------------*/
SetupDirectMode();
}
CMARGBGen2A1controller::~CMARGBGen2A1controller()
{
hid_close(dev);
}
std::string CMARGBGen2A1controller::GetDeviceLocation()
{
return("HID: " + location);
}
std::string CMARGBGen2A1controller::GetSerialString()
{
return(serial_number);
}
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(10));
}
void CMARGBGen2A1controller::SetupDirectMode()
{
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
/*---------------------------------------------*\
| Swith to direct 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_LIGHTNING_CONTROL;
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
usb_buf[4] = 0x01; // channel???
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
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(10));
}
void CMARGBGen2A1controller::SendDirectChannel(unsigned int zone_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;
unsigned char packet_start[CM_ARGB_GEN2_A1_PACKETS_PER_CHANNEL] =
{
0x00, 0x01, 0x82
};
/*---------------------------------------------*\
| Send 3 packets for the zone |
\*---------------------------------------------*/
for(unsigned int p = 0; p < CM_ARGB_GEN2_A1_PACKETS_PER_CHANNEL; p++)
{
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
usb_buf[1] = packet_start[p];
usb_buf[2] = 0x09;
if(p == 0)
{
usb_buf[3] = 1 << zone_id;
usb_buf[5] = 0x3C;
offset = 6;
}
else
{
offset = 3;
}
while(offset < CM_ARGB_GEN2_A1_PACKET_LENGTH && it != color_data.end())
{
usb_buf[offset] = *it;
offset++;
it++;
}
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
/*---------------------------------------------*\
| This device needs some delay before we send |
| any other packet |
\*---------------------------------------------*/
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
/*---------------------------------------------*\
| Next channel needs some delay as well |
\*---------------------------------------------*/
std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
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(10));
}
/*---------------------------------------------*\
| 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] = 0xFF;
usb_buf[5] = 0xFF;
usb_buf[6] = mode_value;
bool is_custom_mode = mode_value == CM_ARGB_GEN2_A1_CUSTOM_MODE;
if(is_custom_mode)
{
usb_buf[8] = 0xFF;
}
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(10));
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::SetCustomColors(unsigned int zone_id, std::vector<RGBColor> colors)
{
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
/*---------------------------------------------*\
| Create the color data array |
\*---------------------------------------------*/
std::vector<unsigned char> color_data = CreateColorData(colors);
std::vector<unsigned char>::iterator it = color_data.begin();
unsigned char packet_start[5] =
{
CM_ARGB_GEN2_A1_COMMAND, 0x00, 0x01, 0x02, 0x83
};
/*---------------------------------------------*\
| Send the 5 packets of colors |
\*---------------------------------------------*/
for(unsigned int p = 0; p < 5; p++)
{
memset(usb_buf, 0x00, CM_ARGB_GEN2_A1_PACKET_LENGTH);
usb_buf[1] = packet_start[p];
/*----------------------------------------------*\
| This part isnt well understood |
| 1st packet starts with CM_ARGB_GEN2_A1_COMMAND |
| Looks like it is a read command |
\*----------------------------------------------*/
usb_buf[2] = p == 0 ? 0x06 : 0x08; // 0x08 custom data, 0x06 sizes?
usb_buf[3] = p == 0 ? 0x01 : 0x02; // read/write has no meaning here
usb_buf[4] = 1 << zone_id;
unsigned int offset = 6;
while(p > 0 && offset < CM_ARGB_GEN2_A1_PACKET_LENGTH && it != color_data.end())
{
usb_buf[offset] = *it;
offset++;
it++;
}
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
std::this_thread::sleep_for(std::chrono::milliseconds(20));
}
}
void CMARGBGen2A1controller::SetCustomSequence(unsigned int zone_id)
{
unsigned char usb_buf[CM_ARGB_GEN2_A1_PACKET_LENGTH];
const unsigned char static_seq = 0x01;
/*---------------------------------------------*\
| Set the mode sequence to full static |
| (01 for static) |
\*---------------------------------------------*/
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_SEQUENCES;
usb_buf[3] = CM_ARGB_GEN2_A1_WRITE;
usb_buf[4] = 1 << zone_id;
usb_buf[5] = static_seq;
usb_buf[6] = static_seq;
usb_buf[7] = static_seq;
usb_buf[8] = static_seq;
usb_buf[9] = static_seq;
usb_buf[10] = static_seq;
hid_write(dev, usb_buf, CM_ARGB_GEN2_A1_PACKET_LENGTH);
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}