Publish LumaOps source

This commit is contained in:
LumaOps release export
2026-09-03 01:18:36 +02:00
commit 7f1c0e5f71
2363 changed files with 501543 additions and 0 deletions
@@ -0,0 +1,298 @@
/*---------------------------------------------------------*\
| CMARGBController.cpp |
| |
| Driver for Cooler Master ARGB controller |
| |
| Chris M (Dr_No) 10 Oct 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "CMARGBController.h"
#include "StringUtils.h"
/*---------------------------------------------------------*\
| Map to convert port index to port ID used in protocol |
\*---------------------------------------------------------*/
static unsigned char cm_argb_port_index_to_id[5] =
{
CM_ARGB_PORT_ARGB_1,
CM_ARGB_PORT_ARGB_2,
CM_ARGB_PORT_ARGB_3,
CM_ARGB_PORT_ARGB_4,
CM_ARGB_PORT_RGB
};
CMARGBController::CMARGBController(hid_device* dev_handle, char *path)
{
dev = dev_handle;
location = path;
/*-----------------------------------------------------*\
| Get device name from HID manufacturer and product |
| strings |
\*-----------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
}
CMARGBController::~CMARGBController()
{
hid_close(dev);
}
std::string CMARGBController::GetDeviceName()
{
return(device_name);
}
std::string CMARGBController::GetLocation()
{
return("HID: " + location);
}
std::string CMARGBController::GetVersion()
{
/*-----------------------------------------------------*\
| This device uses the serial value to determine the |
| version. It does not report a proper unique serial. |
\*-----------------------------------------------------*/
std::string serial_string = GetSerial();
if(serial_string == CM_ARGB_FW0023)
{
return("0023");
}
else if(serial_string == CM_ARGB_FW0028)
{
return("0028");
}
else
{
return("Unsupported");
}
}
std::string CMARGBController::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_serial_number_string(dev, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
void CMARGBController::GetPortStatus
(
unsigned char port_idx,
unsigned char* port_mode,
unsigned char* port_speed,
unsigned char* port_brightness,
bool* port_random,
unsigned char* port_red,
unsigned char* port_green,
unsigned char* port_blue
)
{
unsigned char buffer[CM_ARGB_PACKET_SIZE] = {0x00, 0x80, 0x0B, 0x01};
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
int rgb_offset = 0;
int zone;
/*-----------------------------------------------------*\
| RGB port is handled differently from ARGB ports |
\*-----------------------------------------------------*/
if(cm_argb_port_index_to_id[port_idx] != CM_ARGB_PORT_RGB)
{
zone = cm_argb_port_index_to_id[port_idx];
buffer[CM_ARGB_COMMAND_BYTE] = 0x0B;
}
else
{
zone = 0x00;
buffer[CM_ARGB_COMMAND_BYTE] = 0x0A;
rgb_offset = 1;
}
/*-----------------------------------------------------*\
| If this is the group then just return the first |
| status |
\*-----------------------------------------------------*/
buffer[CM_ARGB_ZONE_BYTE] = ( zone > 0x08 ) ? 0x01 : zone;
/*-----------------------------------------------------*\
| Send the command and read the response |
\*-----------------------------------------------------*/
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_ARGB_INTERRUPT_TIMEOUT);
/*-----------------------------------------------------*\
| Read data out of response |
\*-----------------------------------------------------*/
*port_mode = buffer[4 - rgb_offset];
*port_random = (buffer[5 - rgb_offset] == 0x00);
*port_speed = buffer[6 - rgb_offset];
*port_brightness = buffer[7 - rgb_offset];
*port_red = buffer[8 - rgb_offset];
*port_green = buffer[9 - rgb_offset];
*port_blue = buffer[10 - rgb_offset];
}
void CMARGBController::SetPortLEDCount(unsigned char port_idx, unsigned char led_count)
{
unsigned char buffer[CM_ARGB_PACKET_SIZE] = {0x00, 0x80, 0x0D, 0x02};
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
buffer[CM_ARGB_ZONE_BYTE] = cm_argb_port_index_to_id[port_idx];
buffer[CM_ARGB_MODE_BYTE] = led_count;
buffer[CM_ARGB_COLOUR_INDEX_BYTE] = 1;
/*-----------------------------------------------------*\
| Send the command |
\*-----------------------------------------------------*/
hid_write(dev, buffer, buffer_size);
}
void CMARGBController::SetPortMode
(
unsigned char port_idx,
unsigned char port_mode,
unsigned char port_speed,
unsigned char port_brightness,
bool port_random,
unsigned char port_red,
unsigned char port_green,
unsigned char port_blue
)
{
unsigned char buffer[CM_ARGB_PACKET_SIZE] = {0x00};
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
bool boolARGB_header = (cm_argb_port_index_to_id[port_idx] != CM_ARGB_PORT_RGB);
bool boolPassthru = (port_mode == CM_ARGB_MODE_PASSTHRU) || (port_mode == CM_RGB_MODE_PASSTHRU);
bool boolDirect = (port_mode == CM_ARGB_MODE_DIRECT);
unsigned char function = boolPassthru ? (boolARGB_header ? 0x02 : 0x04) : (boolARGB_header ? 0x01 : 0x03);
buffer[CM_ARGB_REPORT_BYTE] = 0x80;
buffer[CM_ARGB_COMMAND_BYTE] = 0x01;
if(boolDirect)
{
buffer[CM_ARGB_FUNCTION_BYTE] = 0x01;
buffer[CM_ARGB_ZONE_BYTE] = 0x02;
/*-------------------------------------------------*\
| Send the command |
\*-------------------------------------------------*/
hid_write(dev, buffer, buffer_size);
/*-------------------------------------------------*\
| Direct mode is now set up and no other mode |
| packet is required |
\*-------------------------------------------------*/
return;
}
buffer[CM_ARGB_FUNCTION_BYTE] = function;
/*-----------------------------------------------------*\
| Send the command |
\*-----------------------------------------------------*/
hid_write(dev, buffer, buffer_size);
/*-----------------------------------------------------*\
| ARGB ports send command 0x0B, RGB port sends 0x04 |
\*-----------------------------------------------------*/
if(boolARGB_header)
{
buffer[CM_ARGB_COMMAND_BYTE] = 0x0B;
buffer[CM_ARGB_FUNCTION_BYTE] = (false) ? 0x01 : 0x02;
buffer[CM_ARGB_ZONE_BYTE] = cm_argb_port_index_to_id[port_idx];
buffer[CM_ARGB_MODE_BYTE] = port_mode;
buffer[CM_ARGB_COLOUR_INDEX_BYTE] = port_random ? 0x00 : 0x10;
buffer[CM_ARGB_SPEED_BYTE] = port_speed;
buffer[CM_ARGB_BRIGHTNESS_BYTE] = port_brightness;
buffer[CM_ARGB_RED_BYTE] = port_red;
buffer[CM_ARGB_GREEN_BYTE] = port_green;
buffer[CM_ARGB_BLUE_BYTE] = port_blue;
}
else
{
buffer[CM_ARGB_COMMAND_BYTE] = boolPassthru ? 0x01 : 0x04;
buffer[CM_ARGB_MODE_BYTE + CM_RGB_OFFSET] = port_mode;
buffer[CM_ARGB_COLOUR_INDEX_BYTE + CM_RGB_OFFSET] = port_random ? 0x00 : 0x10;
buffer[CM_ARGB_SPEED_BYTE + CM_RGB_OFFSET] = port_speed;
buffer[CM_ARGB_BRIGHTNESS_BYTE + CM_RGB_OFFSET] = port_brightness;
buffer[CM_ARGB_RED_BYTE + CM_RGB_OFFSET] = port_red;
buffer[CM_ARGB_GREEN_BYTE + CM_RGB_OFFSET] = port_green;
buffer[CM_ARGB_BLUE_BYTE + CM_RGB_OFFSET] = port_blue;
}
/*-----------------------------------------------------*\
| Send the command and wait for response |
\*-----------------------------------------------------*/
hid_write(dev, buffer, buffer_size);
}
void CMARGBController::SetPortLEDsDirect(unsigned char port_idx, RGBColor *led_colours, unsigned int led_count)
{
const unsigned char buffer_size = CM_ARGB_PACKET_SIZE;
unsigned char buffer[buffer_size] = { 0x00, 0x00, 0x07, 0x02 };
unsigned char packet_count = 0;
std::vector<uint8_t> colours;
/*-----------------------------------------------------*\
| Set up the RGB triplets to send |
\*-----------------------------------------------------*/
for(unsigned int i = 0; i < led_count; i++)
{
RGBColor colour = led_colours[i];
colours.push_back(RGBGetRValue(colour));
colours.push_back(RGBGetGValue(colour));
colours.push_back(RGBGetBValue(colour));
}
buffer[CM_ARGB_FUNCTION_BYTE] = port_idx;
buffer[CM_ARGB_ZONE_BYTE] = led_count;
unsigned char buffer_idx = CM_ARGB_MODE_BYTE;
for(std::vector<unsigned char>::iterator it = colours.begin(); it != colours.end(); buffer_idx = CM_ARGB_COMMAND_BYTE)
{
/*-------------------------------------------------*\
| Fill the write buffer till its full or the |
| colour buffer is empty |
\*-------------------------------------------------*/
buffer[CM_ARGB_REPORT_BYTE] = packet_count;
while((buffer_idx < buffer_size) && (it != colours.end()))
{
buffer[buffer_idx] = *it;
buffer_idx++;
it++;
}
if(it == colours.end())
{
buffer[CM_ARGB_REPORT_BYTE] += 0x80;
}
/*-------------------------------------------------*\
| Send the buffer |
\*-------------------------------------------------*/
hid_write(dev, buffer, buffer_size);
/*-------------------------------------------------*\
| Reset the write buffer |
\*-------------------------------------------------*/
memset(buffer, 0x00, buffer_size );
packet_count++;
}
}
@@ -0,0 +1,136 @@
/*---------------------------------------------------------*\
| CMARGBController.h |
| |
| Driver for Cooler Master ARGB controller |
| |
| Chris M (Dr_No) 10 Oct 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <cstring>
#include <array>
#include <memory>
#include <hidapi.h>
#include "RGBController.h"
#define CM_ARGB_COLOUR_MODE_DATA_SIZE (sizeof(colour_mode_data[0]) / sizeof(colour_mode_data[0][0]))
#define CM_ARGB_HEADER_DATA_SIZE (sizeof(argb_header_data) / sizeof(argb_headers) )
#define CM_ARGB_INTERRUPT_TIMEOUT 250
#define CM_ARGB_PACKET_SIZE 65
#define CM_ARGB_DEVICE_NAME_SIZE (sizeof(device_name) / sizeof(device_name[ 0 ]))
#define CM_RGB_OFFSET -2
#define HID_MAX_STR 255
#define CM_ARGB_BRIGHTNESS_MAX 255
#define CM_ARGB_FW0000 std::string("A201804091608")
#define CM_ARGB_FW0023 std::string("A202011171238")
#define CM_ARGB_FW0028 std::string("A202105291658")
enum
{
CM_ARGB_REPORT_BYTE = 1,
CM_ARGB_COMMAND_BYTE = 2,
CM_ARGB_FUNCTION_BYTE = 3,
CM_ARGB_ZONE_BYTE = 4,
CM_ARGB_MODE_BYTE = 5,
CM_ARGB_COLOUR_INDEX_BYTE = 6,
CM_ARGB_SPEED_BYTE = 7,
CM_ARGB_BRIGHTNESS_BYTE = 8,
CM_ARGB_RED_BYTE = 9,
CM_ARGB_GREEN_BYTE = 10,
CM_ARGB_BLUE_BYTE = 11
};
enum
{
CM_ARGB_PORT_ARGB_1 = 0x01,
CM_ARGB_PORT_ARGB_2 = 0x02,
CM_ARGB_PORT_ARGB_3 = 0x04,
CM_ARGB_PORT_ARGB_4 = 0x08,
CM_ARGB_PORT_RGB = 0xFE,
};
enum
{
CM_RGB_MODE_MIRAGE = 0x01, //Mirage
CM_RGB_MODE_FLASH = 0x02, //Flash
CM_RGB_MODE_BREATHING = 0x03, //Breathing
CM_RGB_MODE_STATIC = 0x05, //Static
CM_RGB_MODE_OFF = 0x06, //Turn off
CM_RGB_MODE_PASSTHRU = 0xFF //Motherboard Pass Thru Mode
};
enum
{
CM_ARGB_MODE_OFF = 0x0B, //Turn off
CM_ARGB_MODE_SPECTRUM = 0x01, //Spectrum Mode
CM_ARGB_MODE_RELOAD = 0x02, //Reload Mode
CM_ARGB_MODE_RECOIL = 0x03, //Recoil Mode
CM_ARGB_MODE_BREATHING = 0x04, //Breathing Mode
CM_ARGB_MODE_REFILL = 0x05, //Refill Mode
CM_ARGB_MODE_DEMO = 0x06, //Demo Mode
CM_ARGB_MODE_FILLFLOW = 0x08, //Fill Flow Mode
CM_ARGB_MODE_RAINBOW = 0x09, //Rainbow Mode
CM_ARGB_MODE_STATIC = 0x0A, //Static Mode
CM_ARGB_MODE_DIRECT = 0xFE, //Direct Led Control
CM_ARGB_MODE_PASSTHRU = 0xFF //Motherboard Pass Thru Mode
};
enum
{
CM_ARGB_SPEED_SLOWEST = 0x00, // Slowest speed
CM_ARGB_SPEED_SLOW = 0x01, // Slower speed
CM_ARGB_SPEED_NORMAL = 0x02, // Normal speed
CM_ARGB_SPEED_FAST = 0x03, // Fast speed
CM_ARGB_SPEED_FASTEST = 0x04, // Fastest speed
};
class CMARGBController
{
public:
CMARGBController(hid_device* dev_handle, char* path);
~CMARGBController();
std::string GetDeviceName();
std::string GetSerial();
std::string GetLocation();
std::string GetVersion();
void GetPortStatus
(
unsigned char port_idx,
unsigned char* port_mode,
unsigned char* port_speed,
unsigned char* port_brightness,
bool* port_random,
unsigned char* port_red,
unsigned char* port_green,
unsigned char* port_blue
);
void SetPortLEDCount(unsigned char port_idx, unsigned char led_count);
void SetPortMode
(
unsigned char port_idx,
unsigned char port_mode,
unsigned char port_speed,
unsigned char port_brightness,
bool port_random,
unsigned char port_red,
unsigned char port_green,
unsigned char port_blue
);
void SetPortLEDsDirect(unsigned char port_idx, RGBColor *led_colours, unsigned int led_count);
private:
hid_device* dev;
std::string device_name;
std::string location;
};
@@ -0,0 +1,440 @@
/*---------------------------------------------------------*\
| RGBController_CMARGBController.cpp |
| |
| RGBController for Cooler Master ARGB controller |
| |
| Chris M (Dr_No) 14 Oct 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMARGBController.h"
/**------------------------------------------------------------------*\
@name Coolermaster ARGB
@category LEDStrip
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterARGB
@comment The Coolermaster ARGB device supports `Direct` mode from
firmware 0028 onwards. Check the serial number for the date
"A202105291658" or newer.
\*-------------------------------------------------------------------*/
RGBController_CMARGBController::RGBController_CMARGBController(CMARGBController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetDeviceName();
vendor = "Cooler Master";
type = DEVICE_TYPE_LEDSTRIP;
description = "Cooler Master ARGB Controller Device";
version = controller->GetVersion();
serial = controller->GetSerial();
location = controller->GetLocation();
/*-----------------------------------------------------*\
| The ARGB ports support more modes than the RGB port. |
| Define all of the modes the ARGB ports support and |
| map RGB modes to them as best as we can. Per-zone |
| support will be added in the future. |
\*-----------------------------------------------------*/
mode Off;
Off.name = "Off";
Off.value = CM_ARGB_MODE_OFF;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
mode Reload;
Reload.name = "Reload";
Reload.value = CM_ARGB_MODE_RELOAD;
Reload.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Reload.speed_min = CM_ARGB_SPEED_SLOWEST;
Reload.speed_max = CM_ARGB_SPEED_FASTEST;
Reload.speed = CM_ARGB_SPEED_NORMAL;
Reload.brightness_min = 0;
Reload.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Reload.brightness = CM_ARGB_BRIGHTNESS_MAX;
Reload.color_mode = MODE_COLORS_MODE_SPECIFIC;
Reload.colors_min = 1;
Reload.colors_max = 1;
Reload.colors.resize(Reload.colors_max);
modes.push_back(Reload);
mode Recoil;
Recoil.name = "Recoil";
Recoil.value = CM_ARGB_MODE_RECOIL;
Recoil.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Recoil.color_mode = MODE_COLORS_MODE_SPECIFIC;
Recoil.speed_min = CM_ARGB_SPEED_SLOWEST;
Recoil.speed_max = CM_ARGB_SPEED_FASTEST;
Recoil.speed = CM_ARGB_SPEED_NORMAL;
Recoil.brightness_min = 0;
Recoil.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Recoil.brightness = CM_ARGB_BRIGHTNESS_MAX;
Recoil.colors_min = 1;
Recoil.colors_max = 1;
Recoil.colors.resize(Recoil.colors_max);
modes.push_back(Recoil);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_ARGB_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.speed_min = CM_ARGB_SPEED_SLOWEST;
Breathing.speed_max = CM_ARGB_SPEED_FASTEST;
Breathing.speed = CM_ARGB_SPEED_NORMAL;
Breathing.brightness_min = 0;
Breathing.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Breathing.brightness = CM_ARGB_BRIGHTNESS_MAX;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(Breathing.colors_max);
modes.push_back(Breathing);
mode Refill;
Refill.name = "Refill";
Refill.value = CM_ARGB_MODE_REFILL;
Refill.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Refill.color_mode = MODE_COLORS_MODE_SPECIFIC;
Refill.speed_min = CM_ARGB_SPEED_SLOWEST;
Refill.speed_max = CM_ARGB_SPEED_FASTEST;
Refill.speed = CM_ARGB_SPEED_NORMAL;
Refill.brightness_min = 0;
Refill.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Refill.brightness = CM_ARGB_BRIGHTNESS_MAX;
Refill.colors_min = 1;
Refill.colors_max = 1;
Refill.colors.resize(Refill.colors_max);
modes.push_back(Refill);
mode Demo;
Demo.name = "Demo";
Demo.value = CM_ARGB_MODE_DEMO;
Demo.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Demo.color_mode = MODE_COLORS_NONE;
Demo.speed_min = CM_ARGB_SPEED_SLOWEST;
Demo.speed_max = CM_ARGB_SPEED_FASTEST;
Demo.speed = CM_ARGB_SPEED_NORMAL;
Demo.brightness_min = 0;
Demo.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Demo.brightness = CM_ARGB_BRIGHTNESS_MAX;
modes.push_back(Demo);
mode Spectrum;
Spectrum.name = "Rainbow Wave";
Spectrum.value = CM_ARGB_MODE_SPECTRUM;
Spectrum.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Spectrum.color_mode = MODE_COLORS_NONE;
Spectrum.speed_min = CM_ARGB_SPEED_SLOWEST;
Spectrum.speed_max = CM_ARGB_SPEED_FASTEST;
Spectrum.speed = CM_ARGB_SPEED_NORMAL;
Spectrum.brightness_min = 0;
Spectrum.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Spectrum.brightness = CM_ARGB_BRIGHTNESS_MAX;
modes.push_back(Spectrum);
mode FillFlow;
FillFlow.name = "Fill Flow";
FillFlow.value = CM_ARGB_MODE_FILLFLOW;
FillFlow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
FillFlow.color_mode = MODE_COLORS_NONE;
FillFlow.speed_min = CM_ARGB_SPEED_SLOWEST;
FillFlow.speed_max = CM_ARGB_SPEED_FASTEST;
FillFlow.speed = CM_ARGB_SPEED_NORMAL;
FillFlow.brightness_min = 0;
FillFlow.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
FillFlow.brightness = CM_ARGB_BRIGHTNESS_MAX;
modes.push_back(FillFlow);
mode Rainbow;
Rainbow.name = "Rainbow";
Rainbow.value = CM_ARGB_MODE_RAINBOW;
Rainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Rainbow.color_mode = MODE_COLORS_NONE;
Rainbow.speed_min = CM_ARGB_SPEED_SLOWEST;
Rainbow.speed_max = CM_ARGB_SPEED_FASTEST;
Rainbow.speed = CM_ARGB_SPEED_NORMAL;
Rainbow.brightness_min = 0;
Rainbow.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Rainbow.brightness = CM_ARGB_BRIGHTNESS_MAX;
modes.push_back(Rainbow);
mode Static;
Static.name = "Static";
Static.value = CM_ARGB_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.speed_min = CM_ARGB_SPEED_SLOWEST;
Static.speed_max = CM_ARGB_SPEED_FASTEST;
Static.speed = CM_ARGB_SPEED_NORMAL;
Static.brightness_min = 0;
Static.brightness_max = CM_ARGB_BRIGHTNESS_MAX;
Static.brightness = CM_ARGB_BRIGHTNESS_MAX;
Static.colors_min = 1;
Static.colors_max = 1;
Static.colors.resize(Static.colors_max);
modes.push_back(Static);
mode Direct;
Direct.name = (serial >= CM_ARGB_FW0028) ? "Direct" : "Custom";
Direct.value = CM_ARGB_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode PassThru;
PassThru.name = "Pass Thru";
PassThru.value = CM_ARGB_MODE_PASSTHRU;
PassThru.flags = 0;
PassThru.color_mode = MODE_COLORS_NONE;
modes.push_back(PassThru);
SetupZones();
/*-----------------------------------------------------*\
| Initialize the active mode to port 0 |
\*-----------------------------------------------------*/
unsigned char port_mode;
unsigned char port_speed;
unsigned char port_brightness;
bool port_random;
unsigned char port_red;
unsigned char port_green;
unsigned char port_blue;
controller->GetPortStatus(0, &port_mode, &port_speed, &port_brightness, &port_random, &port_red, &port_green, &port_blue);
for(std::size_t mode_idx = 0; mode_idx < modes.size(); mode_idx++)
{
if(modes[mode_idx].value == port_mode)
{
active_mode = (int)mode_idx;
if((modes[mode_idx].flags & MODE_FLAG_HAS_MODE_SPECIFIC_COLOR) && (modes[mode_idx].colors.size() > 0))
{
modes[mode_idx].colors[0] = ToRGBColor(port_red, port_green, port_blue);
}
if(modes[mode_idx].flags & MODE_FLAG_HAS_SPEED)
{
modes[mode_idx].speed = port_speed;
}
if(modes[mode_idx].flags & MODE_FLAG_HAS_BRIGHTNESS)
{
modes[mode_idx].brightness = port_brightness;
}
if(modes[mode_idx].flags & MODE_FLAG_HAS_RANDOM_COLOR)
{
if(port_random)
{
modes[mode_idx].color_mode = MODE_COLORS_RANDOM;
}
}
break;
}
}
}
RGBController_CMARGBController::~RGBController_CMARGBController()
{
delete controller;
}
void RGBController_CMARGBController::SetupZones()
{
/*-----------------------------------------------------*\
| Only set LED count on the first run |
\*-----------------------------------------------------*/
bool first_run = false;
if(zones.size() == 0)
{
first_run = true;
}
/*-----------------------------------------------------*\
| Clear any existing color/LED configuration |
\*-----------------------------------------------------*/
leds.clear();
colors.clear();
zones.resize(5);
/*-----------------------------------------------------*\
| Set up addressable zones |
\*-----------------------------------------------------*/
for(unsigned int channel_idx = 0; channel_idx < 4; channel_idx++)
{
char ch_idx_string[2];
snprintf(ch_idx_string, 2, "%d", channel_idx + 1);
zones[channel_idx].name = "Addressable RGB Header ";
zones[channel_idx].name.append(ch_idx_string);
zones[channel_idx].type = ZONE_TYPE_LINEAR;
zones[channel_idx].leds_min = 0;
zones[channel_idx].leds_max = 48;
if(first_run)
{
zones[channel_idx].leds_count = 0;
}
zones[channel_idx].matrix_map = NULL;
for(unsigned int led_ch_idx = 0; led_ch_idx < zones[channel_idx].leds_count; led_ch_idx++)
{
char led_idx_string[4];
snprintf(led_idx_string, 4, "%d", led_ch_idx + 1);
led new_led;
new_led.name = zones[channel_idx].name;
new_led.name.append(", LED ");
new_led.name.append(led_idx_string);
new_led.value = channel_idx;
leds.push_back(new_led);
}
}
/*-----------------------------------------------------*\
| Set up RGB zone |
\*-----------------------------------------------------*/
zones[4].name = "RGB Header";
zones[4].type = ZONE_TYPE_SINGLE;
zones[4].leds_min = 1;
zones[4].leds_max = 1;
zones[4].leds_count = 1;
zones[4].matrix_map = NULL;
led new_led;
new_led.name = "RGB Header";
new_led.value = 4;
leds.push_back(new_led);
SetupColors();
}
void RGBController_CMARGBController::ResizeZone(int zone, int new_size)
{
if((size_t) zone >= zones.size())
{
return;
}
if(((unsigned int)new_size >= zones[zone].leds_min) && ((unsigned int)new_size <= zones[zone].leds_max))
{
zones[zone].leds_count = new_size;
controller->SetPortLEDCount(zone, zones[zone].leds_count);
SetupZones();
}
}
void RGBController_CMARGBController::DeviceUpdateLEDs()
{
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
UpdateZoneLEDs((int)zone_idx);
}
}
void RGBController_CMARGBController::UpdateZoneLEDs(int zone)
{
/*-----------------------------------------------------*\
| The RGB zone doesn't have a separate Direct mode, so |
| use static mode with the per-LED color for it |
\*-----------------------------------------------------*/
if(zone < 4)
{
controller->SetPortLEDsDirect(zone, zones[zone].colors, zones[zone].leds_count);
}
else
{
controller->SetPortMode(zone, CM_RGB_MODE_STATIC, 0, 255, false, RGBGetRValue(zones[zone].colors[0]), RGBGetGValue(zones[zone].colors[0]), RGBGetBValue(zones[zone].colors[0]));
}
}
void RGBController_CMARGBController::UpdateSingleLED(int led)
{
unsigned int zone_idx = leds[led].value;
UpdateZoneLEDs(zone_idx);
}
void RGBController_CMARGBController::DeviceUpdateMode()
{
/*-----------------------------------------------------*\
| Determine mode parameters |
\*-----------------------------------------------------*/
bool random = (modes[active_mode].color_mode == MODE_COLORS_RANDOM);
RGBColor color = (modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC) ? modes[active_mode].colors[0] : 0;
int rgb_mode;
bool rgb_random = random;
/*-----------------------------------------------------*\
| Map ARGB modes with the equivalent RGB modes |
\*-----------------------------------------------------*/
switch(modes[active_mode].value)
{
case CM_ARGB_MODE_SPECTRUM:
case CM_ARGB_MODE_FILLFLOW:
case CM_ARGB_MODE_RAINBOW:
rgb_mode = CM_RGB_MODE_MIRAGE;
rgb_random = true;
break;
case CM_ARGB_MODE_RELOAD:
case CM_ARGB_MODE_RECOIL:
rgb_mode = CM_RGB_MODE_FLASH;
break;
case CM_ARGB_MODE_BREATHING:
rgb_mode = CM_RGB_MODE_BREATHING;
break;
case CM_ARGB_MODE_REFILL:
case CM_ARGB_MODE_STATIC:
rgb_mode = CM_RGB_MODE_STATIC;
break;
case CM_ARGB_MODE_DEMO:
rgb_mode = CM_RGB_MODE_FLASH;
rgb_random = true;
break;
case CM_ARGB_MODE_OFF:
default:
rgb_mode = CM_RGB_MODE_OFF;
break;
case CM_ARGB_MODE_PASSTHRU:
rgb_mode = CM_RGB_MODE_PASSTHRU;
break;
}
/*-----------------------------------------------------*\
| Apply mode to all zones |
\*-----------------------------------------------------*/
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
controller->SetPortMode
(
(unsigned char)zone_idx,
(zone_idx == 4) ? rgb_mode : modes[active_mode].value,
modes[active_mode].speed,
modes[active_mode].brightness,
(zone_idx == 4) ? rgb_random : random,
RGBGetRValue(color),
RGBGetGValue(color),
RGBGetBValue(color)
);
}
}
@@ -0,0 +1,36 @@
/*---------------------------------------------------------*\
| RGBController_CMARGBController.h |
| |
| RGBController for Cooler Master ARGB controller |
| |
| Chris M (Dr_No) 14 Oct 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <vector>
#include "CMARGBController.h"
#include "RGBController.h"
class RGBController_CMARGBController : public RGBController
{
public:
RGBController_CMARGBController(CMARGBController* controller_ptr);
~RGBController_CMARGBController();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
CMARGBController* controller;
std::vector<unsigned int> leds_channel;
};
@@ -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();
};
@@ -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();
}
@@ -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;
};
@@ -0,0 +1,216 @@
/*---------------------------------------------------------*\
| CMGD160Controller.cpp |
| |
| Driver for Cooler Master GD160 ARGB Gaming Desk |
| |
| Logan Phillips (Eclipse) 16 Oct 2025 |
| |
| This file is part of the OpenRGB project |
| Adapted from CMMonitor controller code |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "CMGD160Controller.h"
#include "StringUtils.h"
CMGD160Controller::CMGD160Controller(hid_device* dev_handle, const hid_device_info& info, const std::string& name)
{
dev = dev_handle;
device_name = name;
location = info.path;
ResetDevice();
}
CMGD160Controller::~CMGD160Controller()
{
hid_close(dev);
}
std::string CMGD160Controller::GetDeviceName()
{
return(device_name);
}
std::string CMGD160Controller::GetDeviceLocation()
{
return("HID: " + location);
}
std::string CMGD160Controller::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));
}
/*------------------------------------------------------------*\
| Desk requires 2 sets of packets sent for the front and back |
| Technically you could have both sides do something different |
| Not sure why you would though.... |
| Cooler Master's software doesn't allow that anyways |
\*------------------------------------------------------------*/
void CMGD160Controller::SetMode(uint8_t mode_value, uint8_t speed, uint8_t brightness, const RGBColor& color)
{
if(is_software_mode_enabled)
{
SetControlMode(false);
}
uint8_t usb_buf[CM_GD160_PACKET_LENGTH];
for(int side = 1; side <= 2; side++)
{
memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH);
usb_buf[1] = 0x80;
usb_buf[2] = (mode_value == CM_GD160_OFF_MODE) ? 0x0F : 0x0B;
usb_buf[3] = 0x02;
usb_buf[4] = side; // 0x01 for front, 0x02 for back
usb_buf[5] = mode_value;
usb_buf[6] = (mode_value == CM_GD160_OFF_MODE) ? 0x00 : 0x08;
usb_buf[7] = speed;
usb_buf[8] = brightness;
usb_buf[9] = RGBGetRValue(color);
usb_buf[10] = RGBGetGValue(color);
usb_buf[11] = RGBGetBValue(color);
hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH);
}
}
/*-------------------------------------------------*\
| How to request current color in custom mode. |
| Not like it matters since we default to direct |
| mode and it seems to clear the current colors... |
| |
| memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH); |
| usb_buf[1] = 0x80; |
| usb_buf[2] = 0x10; |
| usb_buf[3] = 0x01; or 0x02 |
| usb_buf[4] = 0x02; |
| usb_buf[5] = 0x80; |
| hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH); |
\*-------------------------------------------------*/
void CMGD160Controller::SendColorData(const std::vector<RGBColor>& colors, uint8_t command, uint8_t mode_byte, uint8_t brightness, bool desired_control_mode)
{
if(is_software_mode_enabled != desired_control_mode)
{
SetControlMode(desired_control_mode);
}
uint8_t color_data[CM_GD160_COLOR_DATA_LENGTH];
memset(color_data, 0x00, CM_GD160_COLOR_DATA_LENGTH);
for(unsigned int i = 0; i < colors.size() && i < (CM_GD160_LEDS_PER_SIDE * 2); i++)
{
unsigned int side = i / CM_GD160_LEDS_PER_SIDE;
unsigned int led_in_side = i % CM_GD160_LEDS_PER_SIDE;
unsigned int buffer_offset = (side * CM_GD160_SIDE_DATA_LENGTH) + (led_in_side * 3);
color_data[buffer_offset] = RGBGetRValue(colors[i]);
color_data[buffer_offset + 1] = RGBGetGValue(colors[i]);
color_data[buffer_offset + 2] = RGBGetBValue(colors[i]);
}
uint8_t usb_buf[CM_GD160_PACKET_LENGTH];
for(unsigned int side = 1; side <= 2; side++)
{
unsigned int offset = (side - 1) * CM_GD160_SIDE_DATA_LENGTH;
for(unsigned int packet = 0; packet < 7; packet++)
{
memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH);
usb_buf[1] = (packet < 6) ? packet : 0x86; // Last packet uses 0x86
/*---------------------------------------------------------*\
| First packet contains static data |
\*---------------------------------------------------------*/
if(packet == 0)
{
usb_buf[2] = command;
usb_buf[3] = 0x02;
usb_buf[4] = side; // 0x01 for front, 0x02 for back
usb_buf[5] = mode_byte;
usb_buf[6] = brightness;
memcpy(&usb_buf[7], &color_data[offset], CM_GD160_FIRST_PACKET_DATA_SIZE);
offset += CM_GD160_FIRST_PACKET_DATA_SIZE;
}
else
{
memcpy(&usb_buf[2], &color_data[offset], CM_GD160_PACKET_DATA_SIZE);
offset += CM_GD160_PACKET_DATA_SIZE;
}
hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH);
}
}
}
/*------------------------------------------------------*\
| True enables software mode |
| False enables hardware mode |
\*------------------------------------------------------*/
void CMGD160Controller::SetControlMode(bool software_mode)
{
uint8_t usb_buf[CM_GD160_PACKET_LENGTH];
for(int side = 1; side <= 2; side++)
{
memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH);
usb_buf[1] = 0x80;
usb_buf[2] = 0x07;
usb_buf[3] = 0x02;
usb_buf[4] = side; // 0x01 for front, 0x02 for back
usb_buf[6] = software_mode;
hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH);
}
is_software_mode_enabled = software_mode;
}
/*------------------------------------------------------*\
| Reset device on discovery in case it somehow landed |
| in a bad / unresponsive state |
\*------------------------------------------------------*/
void CMGD160Controller::ResetDevice()
{
uint8_t usb_buf[CM_GD160_PACKET_LENGTH];
memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH);
usb_buf[1] = 0x80;
usb_buf[2] = 0x11;
hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH);
memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH);
usb_buf[1] = 0x80;
usb_buf[2] = 0x0B;
usb_buf[3] = 0x01;
usb_buf[4] = 0x02;
hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH);
memset(usb_buf, 0x00, CM_GD160_PACKET_LENGTH);
usb_buf[1] = 0x80;
usb_buf[2] = 0x18;
usb_buf[3] = 0x01;
usb_buf[4] = 0x02;
hid_write(dev, usb_buf, CM_GD160_PACKET_LENGTH);
is_software_mode_enabled = false;
}
@@ -0,0 +1,67 @@
/*---------------------------------------------------------*\
| CMGD160Controller.h |
| |
| Driver for Cooler Master GD160 ARGB Gaming Desk |
| |
| Logan Phillips (Eclipse) 16 Oct 2025 |
| |
| This file is part of the OpenRGB project |
| Adapted from CMMonitor controller code |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#define CM_GD160_PACKET_LENGTH 65
#define CM_GD160_COLOR_DATA_LENGTH 872
#define CM_GD160_SIDE_DATA_LENGTH 436 // 96 LEDs * 3 bytes + header = 436 bytes per side
#define CM_GD160_LEDS_PER_SIDE 96
#define CM_GD160_FIRST_PACKET_DATA_SIZE 58 // CM_GD160_PACKET_LENGTH - 7 (header bytes)
#define CM_GD160_PACKET_DATA_SIZE 63 // CM_GD160_PACKET_LENGTH - 2 (header bytes)
enum
{
CM_GD160_DIRECT_MODE = 0xFF,
CM_GD160_CUSTOM_MODE = 0xFE,
CM_GD160_SPECTRUM_MODE = 0x00,
CM_GD160_RELOAD_MODE = 0x01,
CM_GD160_RECOIL_MODE = 0x02,
CM_GD160_BREATHING_MODE = 0x03,
CM_GD160_REFILL_MODE = 0x04,
CM_GD160_OFF_MODE = 0x06
};
enum
{
CM_GD160_BRIGHTNESS_MAX = 0xFF,
CM_GD160_BRIGHTNESS_MIN = 0x00,
CM_GD160_SPEED_MAX = 0x04,
CM_GD160_SPEED_MIN = 0x00,
};
class CMGD160Controller
{
public:
CMGD160Controller(hid_device* dev_handle, const hid_device_info& info, const std::string& name);
~CMGD160Controller();
std::string GetDeviceName();
std::string GetSerialString();
std::string GetDeviceLocation();
void SetMode(uint8_t mode_value, uint8_t speed, uint8_t brightness, const RGBColor& color);
void SendColorData(const std::vector<RGBColor>& colors, uint8_t command, uint8_t mode_byte, uint8_t brightness, bool enable_software_mode);
private:
std::string device_name;
std::string serial_number;
std::string location;
hid_device* dev;
bool is_software_mode_enabled = false;
void SetControlMode(bool value);
void ResetDevice();
};
@@ -0,0 +1,238 @@
/*---------------------------------------------------------*\
| RGBController_CMGD160Controller.cpp |
| |
| RGBController for Cooler Master GD160 ARGB Gaming Desk |
| |
| Logan Phillips (Eclipse) 16 Oct 2025 |
| |
| This file is part of the OpenRGB project |
| Adapted from CMMonitor controller code |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMGD160Controller.h"
/**------------------------------------------------------------------*\
@name Cooler Master GD160 ARGB Gaming Desk
@category Accessory
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterGD160
@comment
\*-------------------------------------------------------------------*/
RGBController_CMGD160Controller::RGBController_CMGD160Controller(CMGD160Controller* controller_ptr)
{
controller = controller_ptr;
name = controller->GetDeviceName();
vendor = "Cooler Master";
type = DEVICE_TYPE_ACCESSORY;
description = "Cooler Master GD160 Gaming Desk Device";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
mode Direct;
Direct.name = "Direct";
Direct.value = CM_GD160_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 Cycle";
Spectrum.value = CM_GD160_SPECTRUM_MODE;
Spectrum.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Spectrum.color_mode = MODE_COLORS_NONE;
Spectrum.speed_min = CM_GD160_SPEED_MIN;
Spectrum.speed_max = CM_GD160_SPEED_MAX;
Spectrum.speed = CM_GD160_SPEED_MAX/2;
Spectrum.brightness_min = CM_GD160_BRIGHTNESS_MIN;
Spectrum.brightness_max = CM_GD160_BRIGHTNESS_MAX;
Spectrum.brightness = CM_GD160_BRIGHTNESS_MAX;
modes.push_back(Spectrum);
mode Reload;
Reload.name = "Reload";
Reload.value = CM_GD160_RELOAD_MODE;
Reload.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Reload.color_mode = MODE_COLORS_MODE_SPECIFIC;
Reload.colors_min = 1;
Reload.colors_max = 1;
Reload.colors.resize(1);
Reload.speed_min = CM_GD160_SPEED_MIN;
Reload.speed_max = CM_GD160_SPEED_MAX;
Reload.speed = CM_GD160_SPEED_MAX/2;
Reload.brightness_min = CM_GD160_BRIGHTNESS_MIN;
Reload.brightness_max = CM_GD160_BRIGHTNESS_MAX;
Reload.brightness = CM_GD160_BRIGHTNESS_MAX;
modes.push_back(Reload);
mode Recoil;
Recoil.name = "Recoil";
Recoil.value = CM_GD160_RECOIL_MODE;
Recoil.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Recoil.color_mode = MODE_COLORS_MODE_SPECIFIC;
Recoil.colors_min = 1;
Recoil.colors_max = 1;
Recoil.colors.resize(1);
Recoil.speed_min = CM_GD160_SPEED_MIN;
Recoil.speed_max = CM_GD160_SPEED_MAX;
Recoil.speed = CM_GD160_SPEED_MAX/2;
Recoil.brightness_min = CM_GD160_BRIGHTNESS_MIN;
Recoil.brightness_max = CM_GD160_BRIGHTNESS_MAX;
Recoil.brightness = CM_GD160_BRIGHTNESS_MAX;
modes.push_back(Recoil);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_GD160_BREATHING_MODE;
Breathing.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(1);
Breathing.speed_min = CM_GD160_SPEED_MIN;
Breathing.speed_max = CM_GD160_SPEED_MAX;
Breathing.speed = CM_GD160_SPEED_MAX/2;
Breathing.brightness_min = CM_GD160_BRIGHTNESS_MIN;
Breathing.brightness_max = CM_GD160_BRIGHTNESS_MAX;
Breathing.brightness = CM_GD160_BRIGHTNESS_MAX;
modes.push_back(Breathing);
mode Refill;
Refill.name = "Refill";
Refill.value = CM_GD160_REFILL_MODE;
Refill.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Refill.color_mode = MODE_COLORS_MODE_SPECIFIC;
Refill.colors_min = 1;
Refill.colors_max = 1;
Refill.colors.resize(1);
Refill.speed_min = CM_GD160_SPEED_MIN;
Refill.speed_max = CM_GD160_SPEED_MAX;
Refill.speed = CM_GD160_SPEED_MAX/2;
Refill.brightness_min = CM_GD160_BRIGHTNESS_MIN;
Refill.brightness_max = CM_GD160_BRIGHTNESS_MAX;
Refill.brightness = CM_GD160_BRIGHTNESS_MAX;
modes.push_back(Refill);
mode Custom;
Custom.name = "Custom";
Custom.value = CM_GD160_CUSTOM_MODE;
Custom.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Custom.color_mode = MODE_COLORS_PER_LED;
Custom.brightness_min = CM_GD160_BRIGHTNESS_MIN;
Custom.brightness_max = CM_GD160_BRIGHTNESS_MAX;
Custom.brightness = CM_GD160_BRIGHTNESS_MAX;
modes.push_back(Custom);
mode Off;
Off.name = "Off";
Off.value = CM_GD160_OFF_MODE;
Off.flags = MODE_FLAG_AUTOMATIC_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
SetupZones();
}
RGBController_CMGD160Controller::~RGBController_CMGD160Controller()
{
delete controller;
}
void RGBController_CMGD160Controller::SetupZones()
{
zone front;
front.name = "Front Desk";
front.type = ZONE_TYPE_LINEAR;
front.leds_min = CM_GD160_LEDS_PER_SIDE;
front.leds_max = CM_GD160_LEDS_PER_SIDE;
front.leds_count = CM_GD160_LEDS_PER_SIDE;
front.matrix_map = NULL;
zones.push_back(front);
for(unsigned int i = 0; i < CM_GD160_LEDS_PER_SIDE; i++)
{
led l;
l.name = "Front LED " + std::to_string(i + 1);
l.value = i;
leds.push_back(l);
}
zone back;
back.name = "Back Desk";
back.type = ZONE_TYPE_LINEAR;
back.leds_min = CM_GD160_LEDS_PER_SIDE;
back.leds_max = CM_GD160_LEDS_PER_SIDE;
back.leds_count = CM_GD160_LEDS_PER_SIDE;
back.matrix_map = NULL;
zones.push_back(back);
for(unsigned int i = 0; i < CM_GD160_LEDS_PER_SIDE; i++)
{
led l;
l.name = "Back LED " + std::to_string(i + 1);
l.value = i;
leds.push_back(l);
}
SetupColors();
}
void RGBController_CMGD160Controller::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_CMGD160Controller::DeviceUpdateLEDs()
{
switch(modes[active_mode].value)
{
case CM_GD160_DIRECT_MODE:
controller->SendColorData(colors, 0x07, 0x01, 0xFF, true);
break;
case CM_GD160_CUSTOM_MODE:
controller->SendColorData(colors, 0x10, 0x80, modes[active_mode].brightness, false);
break;
default:
break;
}
}
void RGBController_CMGD160Controller::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMGD160Controller::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMGD160Controller::DeviceUpdateMode()
{
switch(modes[active_mode].value)
{
case CM_GD160_OFF_MODE:
case CM_GD160_SPECTRUM_MODE:
controller->SetMode(modes[active_mode].value, modes[active_mode].speed, modes[active_mode].brightness, 0);
break;
case CM_GD160_RELOAD_MODE:
case CM_GD160_RECOIL_MODE:
case CM_GD160_BREATHING_MODE:
case CM_GD160_REFILL_MODE:
controller->SetMode(modes[active_mode].value, modes[active_mode].speed, modes[active_mode].brightness, modes[active_mode].colors[0]);
break;
default:
break;
}
}
@@ -0,0 +1,36 @@
/*---------------------------------------------------------*\
| RGBController_CMGD160Controller.h |
| |
| RGBController for Cooler Master GD160 ARGB Gaming Desk |
| |
| Logan Phillips (Eclipse) 16 Oct 2025 |
| |
| This file is part of the OpenRGB project |
| Adapted from CMMonitor controller code |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CMGD160Controller.h"
class RGBController_CMGD160Controller : public RGBController
{
public:
RGBController_CMGD160Controller(CMGD160Controller* controller_ptr);
~RGBController_CMGD160Controller();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
CMGD160Controller* controller;
};
@@ -0,0 +1,197 @@
/*---------------------------------------------------------*\
| CMKeyboardAbstractController.cpp |
| |
| Driver for Cooler Master keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "CMKeyboardAbstractController.h"
#include "StringUtils.h"
CMKeyboardAbstractController::CMKeyboardAbstractController(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name)
{
wchar_t tmp[HID_MAX_STR];
m_pDev = dev_handle;
m_productId = dev_info->product_id;
m_sLocation = dev_info->path;
m_deviceName = dev_name;
hid_get_manufacturer_string(m_pDev, tmp, HID_MAX_STR);
m_vendorName = StringUtils::wstring_to_string(tmp);
hid_get_product_string(m_pDev, tmp, HID_MAX_STR);
m_serialNumber = StringUtils::wstring_to_string(tmp);
bool bNotFound = true;
for(uint16_t i = 0; i < COOLERMASTER_KEYBOARD_DEVICE_COUNT; i++)
{
if(cm_kb_device_list[i]->product_id == m_productId)
{
bNotFound = false;
m_deviceIndex = i;
break;
}
}
if(bNotFound)
{
LOG_ERROR("[%s] device capabilities not found. Please creata a new device request.", m_deviceName.c_str());
}
};
CMKeyboardAbstractController::~CMKeyboardAbstractController()
{
hid_close(m_pDev);
};
std::string CMKeyboardAbstractController::GetDeviceName()
{
return(m_deviceName);
}
std::string CMKeyboardAbstractController::GetDeviceVendor()
{
return(m_vendorName);
}
std::string CMKeyboardAbstractController::GetDeviceSerial()
{
return(m_serialNumber);
}
const cm_kb_device* CMKeyboardAbstractController::GetDeviceData()
{
return(cm_kb_device_list[m_deviceIndex]);
}
std::string CMKeyboardAbstractController::GetLocation()
{
return(m_sLocation);
}
std::string CMKeyboardAbstractController::GetFirmwareVersion()
{
return(m_sFirmwareVersion);
}
int CMKeyboardAbstractController::GetProductID()
{
return(m_productId);
}
std::vector<uint8_t> CMKeyboardAbstractController::SendCommand(std::vector<uint8_t> buf, uint8_t fill)
{
int status;
std::vector<uint8_t> read;
uint8_t data[CM_KEYBOARD_WRITE_SIZE];
memset(data, fill, CM_KEYBOARD_WRITE_SIZE);
size_t i = 1;
for(uint8_t b : buf)
{
data[i++] = b;
}
std::lock_guard<std::mutex> guard(m_mutexSendCommand);
status = hid_write(m_pDev, data, CM_KEYBOARD_WRITE_SIZE);
if(status < 0)
{
LOG_ERROR("[%s] SendCommand() failed code %d.", m_deviceName.c_str(), status);
return(read);
}
memset(data, 0, CM_KEYBOARD_WRITE_SIZE);
status = hid_read(m_pDev, data, CM_KEYBOARD_WRITE_SIZE);
if(status < 0)
{
LOG_ERROR("[%s] SendCommand() failed code %d.", m_deviceName.c_str(), status);
return(read);
}
for(i = 0; i < (size_t)status; i++)
{
read.push_back(data[i]);
}
return(read);
}
/*---------------------------------------------------------*\
| Enter/leave direct control mode |
\*---------------------------------------------------------*/
void CMKeyboardAbstractController::SetControlMode(uint8_t modeId)
{
SendCommand({0x41, (uint8_t)modeId});
};
/*---------------------------------------------------------*\
| Sets the currently active profile. |
| byte[0] = 0x51 0x00 0x00 0x00 |
| byte[4] = profileId |
| - corresponds to saved keyboard profile i.e. [1-4] |
| - 0x05 - Used on MK and CK style keyboards? |
\*---------------------------------------------------------*/
void CMKeyboardAbstractController::SetActiveProfile(uint8_t profileId)
{
SendCommand({0x51, 0x00, 0x00, 0x00, profileId});
};
uint8_t CMKeyboardAbstractController::GetActiveProfile()
{
std::vector<uint8_t> data = SendCommand({0x52, 0x00});
if(data.size() > 4)
{
return((int)data[4]);
}
return(0xFF); // error
}
/*---------------------------------------------------------*\
| Saves changes in currently used profile. |
| byte[1] = 0x52 |
\*---------------------------------------------------------*/
void CMKeyboardAbstractController::SaveActiveProfile()
{
SendCommand({0x50, 0x55});
}
void CMKeyboardAbstractController::SetActiveEffect(uint8_t effectId)
{
SendCommand({0x51, 0x28, 0x00, 0x00, effectId});
};
void CMKeyboardAbstractController::SaveProfile()
{
SendCommand({0x50, 0x55});
}
uint8_t CMKeyboardAbstractController::GetModeStatus()
{
std::vector<uint8_t> data = SendCommand({0x52, 0x28});
return(data[4]);
};
std::string CMKeyboardAbstractController::GetHexString(std::vector<uint8_t> buf)
{
std::stringstream hexss;
for(uint8_t b : buf)
{
hexss << std::hex << b << " ";
}
return(hexss.str());
}
@@ -0,0 +1,120 @@
/*---------------------------------------------------------*\
| CMKeyboardAbstractController.h |
| |
| Driver for Cooler Master keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <cstring>
#include <stdint.h>
#include <string>
#include <sstream>
#include <map>
#include <vector>
#include <hidapi.h>
#include "CMKeyboardDevices.h"
#include "KeyboardLayoutManager.h"
#include "RGBController.h"
#include "LogManager.h"
#define HID_MAX_STR 255
#define CM_KEYBOARD_WRITE_SIZE 65
#define CM_MAX_LEDS 255
#define CM_KEYBOARD_TIMEOUT 50
#define CM_KEYBOARD_TIMEOUT_SHORT 3
struct cm_keyboard_effect
{
uint8_t effectId;
uint8_t p1;
uint8_t p2;
uint8_t p3;
RGBColor color1;
RGBColor color2;
};
/*---------------------------------------------------------*\
| byte[0] = 0x41 |
| byte[1] = modeId |
\*---------------------------------------------------------*/
enum cm_keyboard_control_mode
{
MODE_FIRMWARE = 0x00,
MODE_EFFECT = 0x01,
MODE_MANUAL_V2 = 0x02,
MODE_CUSTOM_PROFILE = 0x03,
MODE_CUSTOM_PROFILE_V2 = 0x05,
MODE_DIRECT = 0x80
};
class CMKeyboardAbstractController
{
public:
CMKeyboardAbstractController(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name);
virtual ~CMKeyboardAbstractController();
/*---------------------------------------------------------*\
| Common USB controller fuctions |
\*---------------------------------------------------------*/
int GetProductID();
std::string GetDeviceName();
std::string GetDeviceVendor();
std::string GetDeviceSerial();
std::string GetLocation();
std::string GetFirmwareVersion();
const cm_kb_device* GetDeviceData();
/*---------------------------------------------------------*\
| Keyboard Layout Manager support funtions |
\*---------------------------------------------------------*/
/*---------------------------------------------------------*\
| Common keyboard driver functions |
\*---------------------------------------------------------*/
virtual void SetControlMode(uint8_t modeId);
virtual void SetActiveProfile(uint8_t profileId);
virtual uint8_t GetActiveProfile();
virtual void SaveActiveProfile();
virtual void SaveProfile();
virtual void SetActiveEffect(uint8_t effectId);
virtual uint8_t GetModeStatus();
virtual void InitializeModes(std::vector<mode> &modes) = 0;
virtual KEYBOARD_LAYOUT GetKeyboardLayout() = 0;
/*---------------------------------------------------------*\
| Protocol specific funtions to be implmented |
\*---------------------------------------------------------*/
virtual void SetLeds(std::vector<led> leds, std::vector<RGBColor> colors) = 0;
virtual void SetSingleLED(uint8_t in_led, RGBColor in_color) = 0;
virtual void Initialize() = 0;
virtual void Shutdown() = 0;
virtual void SetLEDControl(bool bManual) = 0; // FW or SW control
virtual void SetCustomMode() = 0;
virtual void SetMode(mode selectedMode) = 0;
protected:
/*---------------------------------------------------------*\
| Utility functions. |
\*---------------------------------------------------------*/
std::vector<std::uint8_t> SendCommand(std::vector<uint8_t> buf, uint8_t fill=0x00);
std::string GetHexString(std::vector<uint8_t> buf);
std::string m_sFirmwareVersion;
std::string m_deviceName;
hid_device* m_pDev;
uint16_t m_productId;
uint16_t m_deviceIndex;
std::string m_vendorName;
std::string m_sLocation;
std::string m_serialNumber;
KEYBOARD_LAYOUT m_keyboardLayout;
std::map<int, int> mapModeValueEffect;
std::mutex m_mutex;
std::mutex m_mutexSendCommand;
};
@@ -0,0 +1,902 @@
/*---------------------------------------------------------*\
| CMKeyboardDevices.cpp |
| |
| Device list for Cooler Master keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "CMKeyboardDevices.h"
/*-------------------------------------------------------------------------*\
| Coolermaster Key Values |
\*-------------------------------------------------------------------------*/
const std::vector<unsigned int> mk_pro_s_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
96, 97, 98, 99, 104, 105, 106, 112, 113, 114, 67, 68, 69, 102, 103, 107,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP */
0, 1, 8, 9, 16, 17, 24, 25, 32, 33, 40, 41, 48, 49, 56, 57, 64,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN */
2, 3, 10, 11, 18, 19, 26, 27, 34, 35, 42, 43, 50, 51, 58, 59, 66,
/* CPLK A S D F G H J K L ; " # ENTR */
4, 5, 12, 13, 20, 21, 28, 29, 36, 37, 44, 45, 89, 52,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU */
6, 100, 7, 14, 15, 22, 23, 30, 31, 38, 39, 46, 47, 61,
/* LCTL LWIN LALT SPC RALT RFNC RMNU RCTL ARWL ARWD ARWR */
91, 90, 92, 93, 94, 60, 95, 54, 63, 62, 70,
};
const std::vector<unsigned int> mk_pro_l_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK P1 P2 P3 P4 */
11, 22, 30, 25, 27, 7, 51, 57, 62, 86, 87, 83, 85, 79, 72, 0,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI */
14, 15, 23, 31, 39, 38, 46, 47, 55, 63, 71, 70, 54, 81, 3, 1, 2, 100, 108, 116, 118,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL */
9, 8, 16, 24, 32, 33, 41, 40, 48, 56, 64, 65, 49, 82, 94, 92, 88, 96, 104, 112, 110,
/* CPLK A S D F G H J K L ; ' \ ENTR NM4 NM5 NM6 */
17, 10, 18, 26, 34, 35, 43, 42, 50, 58, 66, 67, 68, 84, 97, 105, 113,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER */
73, 19, 12, 20, 28, 36, 37, 45, 44, 52, 60, 69, 74, 80, 98, 106, 114, 111,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
6, 90, 75, 91, 77, 78, 61, 4, 95, 93, 5, 107, 115,
};
const std::vector<unsigned int> mk850_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK AIM AIMU AIMD */
6, 27, 34, 41, 48, 62, 69, 76, 83, 90, 97, 104, 111, 118, 125, 132,
/* M1 BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI */
7, 21, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 98, 112, 119, 126, 133, 254, 147, 154, 161,
/* M2 TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL */
8, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99, 113, 120, 127, 134, 141, 148, 155, 162,
/* M3 CPLK A S D F G H J K L ; ' # ENTR NM4 NM5 NM6 */
9, 23, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 0, 114, 142, 149, 156,
/* M4 LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER */
10, 0, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 115, 129, 143, 150, 157, 164,
/* M5 LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
11, 18, 25, 53, 81, 88, 95, 116, 123, 130, 137, 144, 158,
};
/*-------------------------------------------------------------*\
| CoolerMaster SK (60%) |
\*-------------------------------------------------------------*/
const std::vector<unsigned int> sk620_keymap =
{
/* T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 */
/* L1 ESC 1 2 3 4 5 6 7 8 9 0 - = BPSC R1 */
8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 106,
/* L2 TAB Q W E R T Y U I O P [ ] R2 */
9, 23, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 100,
/* L3 CPLK A S D F G H J K L ; " \ ENTR R3 */
10, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94, 101, 108,
/* L4 LSFT ISO\ Z X C V B N M , . # RSFT ARWU DEL R$ */
11, 18, 25, 32, 39, 46, 53, 60, 67, 74, 81, 88, 95, 102, 109,
/* L5 LCTL LWIN LALT SPACE RALT RWFNC ARWL ARDN ARWR R5 */
12, 19, 26, 54, 82, 89, 96, 103, 110,
/* B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B15 */
};
/*-------------------------------------------------------------*\
| CoolerMaster SK (60%) |
\*-------------------------------------------------------------*/
const std::vector<unsigned int> sk622_keymap =
{
/* T1 T2 T3 T4 T5 T6 T7 T8 T9 T10 T11 T12 T13 T14 T15 */
/* L1 ESC 1 2 3 4 5 6 7 8 9 0 - = BPSC R1 */
8, 15, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 106,
/* L2 TAB Q W E R T Y U I O P [ ] R2 */
9, 23, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 100,
/* L3 CPLK A S D F G H J K L ; " \ ENTR R3 */
10, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94, 101, 108,
/* L4 LSFT ISO\ Z X C V B N M , . # RSFT ARWU DEL R$ */
11, 18, 25, 32, 39, 46, 53, 60, 67, 74, 81, 88, 95, 102, 109,
/* L5 LCTL LWIN LALT SPACE RALT RWFNC ARWL ARDN ARWR R5 */
12, 19, 26, 54, 82, 89, 96, 103, 110,
/* B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B13 B14 B15 B15 */
};
const std::vector<unsigned int> sk630_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
9, 33, 41, 49, 57, 73, 81, 89, 97, 105, 113, 121, 129, 137, 145, 153,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP */
10, 26, 34, 42, 50, 58, 66, 74, 82, 90, 98, 106, 114, 130, 138, 146, 154,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN */
11, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99, 107, 115, 131, 139, 147, 155,
/* CPLK A S D F G H J K L ; " # ENTR */
12, 28, 36, 44, 52, 60, 68, 76, 84, 92, 100, 108, 116, 132,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU */
13, 21, 29, 37, 45, 53, 61, 69, 77, 85, 93, 101, 133, 149,
/* LCTL LWIN LALT SPC RALT RFNC RMNU RCTL ARWL ARWD ARWR */
14, 22, 30, 62, 94, 102, 110, 134, 142, 150, 158,
};
const std::vector<unsigned int> sk650_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
0, 24, 32, 40, 48, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI */
1, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 121, 129, 137, 145, 153, 161, 169, 177,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL */
2, 18, 26, 34, 42, 50, 58, 66, 74, 82, 90, 98, 106, 122, 130, 138, 146, 154, 162, 170, 178,
/* CPLK A S D F G H J K L ; ' # ENTR NM4 NM5 NM6 */
3, 19, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99, 107, 123, 155, 163, 171,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER */
4, 20, 28, 36, 44, 52, 60, 68, 76, 84, 92, 100, 124, 140, 156, 164, 172, 180,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
5, 13, 21, 53, 85, 93, 101, 125, 133, 141, 149, 165, 173,
};
const std::vector<unsigned int> sk652_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
9, 33, 41, 49, 57, 73, 81, 89, 97, 105, 113, 121, 129, 137, 145, 153,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI */
10, 26, 34, 42, 50, 58, 66, 74, 82, 90, 98, 106, 114, 130, 138, 146, 154, 162, 170, 178, 186,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL */
11, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99, 107, 115, 131, 139, 147, 155, 163, 171, 179, 187,
/* CPLK A S D F G H J K L ; ' # ENTR NM4 NM5 NM6 */
12, 28, 36, 44, 52, 60, 68, 76, 84, 92, 100, 108, 116, 132, 164, 172, 180,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER */
13, 21, 29, 37, 45, 53, 61, 69, 77, 85, 93, 101, 133, 149, 165, 173, 181, 189,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
14, 22, 30, 62, 94, 102, 110, 134, 142, 150, 158, 174, 182,
};
const std::vector<unsigned int> sk653_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
0, 24, 32, 40, 48, 64, 72, 80, 88, 96, 104, 112, 120, 128, 136, 144,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI */
1, 17, 25, 33, 41, 49, 57, 65, 73, 81, 89, 97, 105, 121, 129, 137, 145, 153, 161, 169, 177,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL */
2, 18, 26, 34, 42, 50, 58, 66, 74, 82, 90, 98, 106, 122, 130, 138, 146, 154, 162, 170, 178,
/* CPLK A S D F G H J K L ; ' # ENTR NM4 NM5 NM6 */
3, 19, 27, 35, 43, 51, 59, 67, 75, 83, 91, 99, 107, 123, 155, 163, 171,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER */
4, 20, 28, 36, 44, 52, 60, 68, 76, 84, 92, 100, 124, 140, 156, 164, 172, 180,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
5, 13, 21, 53, 85, 93, 101, 125, 133, 141, 149, 165, 173,
};
const std::vector<unsigned int> mk730_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
7, 28, 35, 42, 49, 63, 70, 77, 84, 91, 98, 105, 112, 119, 126, 133,
/* L1 BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP R1 */
8, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99, 113, 120, 127, 134,
/* L2 TAB Q W E R T Y U I O P [ ] \ DEL END PGDN R2 */
9, 23, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 100, 114, 121, 128, 135,
/* L3 CPLK A S D F G H J K L ; ' # ENTR R3 */
10, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94, 108, 115,
/* L4 LSFT ISO\ Z X C V B N M , . / RSFT ARWU R4 */
11, 18, 25, 32, 39, 46, 53, 60, 67, 74, 81, 88, 116, 130,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR */
12, 19, 26, 54, 82, 89, 96, 117, 124, 131, 138,
/* B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B12 */
};
const std::vector<unsigned int> mk750_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK MUT PLA REW FFWD */
7, 28, 35, 42, 49, 63, 70, 77, 84, 91, 98, 105, 112, 119, 136, 133,
/* L1 BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI R1 */
8, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99, 113, 120, 127, 134, 0, 148, 155, 162,
/* L2 TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL R2 */
9, 23, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 100, 114, 121, 128, 135, 142, 149, 156, 163,
/* L3 CPLK A S D F G H J K L ; ' # ENTR NM4 NM5 NM6 R3 */
10, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94, 108, 115, 143, 150, 157,
/* L4 LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER R4 */
11, 18, 25, 32, 39, 46, 53, 60, 67, 74, 81, 88, 116, 130, 144, 151, 158, 165,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
12, 19, 26, 54, 82, 89, 96, 117, 124, 131, 138, 152, 159,
/* B1 B2 B3 B4 B5 B6 B7 B8 B9 B10 B11 B12 B12 B13 B14 B15 B16 B17 B18 */
};
const std::vector<unsigned int> ck530_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
6, 21, 27, 34, 41, 55, 62, 69, 76, 83, 90, 97, 104, 111, 118, 125,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP */
7, 15, 22, 28, 35, 42, 49, 56, 63, 70, 77, 84, 91, 105, 112, 119, 126,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN */
8, 16, 23, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 106, 113, 120, 127,
/* CPLK A S D F G H J K L ; " # ENTR */
9, 17, 24, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 107,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU */
10, 18, 25, 31, 38, 45, 52, 59, 66, 73, 80, 87, 108, 122,
/* LCTL LWIN LALT SPC RALT RFNC RMNU RCTL ARWL ARWD ARWR */
11, 12, 19, 46, 74, 81, 88, 109, 116, 123, 130,
};
const std::vector<unsigned int> ck530_v2_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
7, 28, 35, 42, 49, 63, 70, 77, 84, 91, 98, 105, 112, 119, 126, 133,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP */
8, 22, 29, 36, 43, 50, 57, 64, 71, 78, 85, 92, 99, 113, 120, 127, 134,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN */
9, 23, 30, 37, 44, 51, 58, 65, 72, 79, 86, 93, 100, 114, 121, 128, 135,
/* CPLK A S D F G H J K L ; " # ENTR */
10, 24, 31, 38, 45, 52, 59, 66, 73, 80, 87, 94, 108, 115,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU */
11, 18, 25, 32, 39, 46, 53, 60, 67, 74, 88, 81, 116, 130,
/* LCTL LWIN LALT SPC RALT RFNC RMNU RCTL ARWL ARWD ARWR */
12, 19, 26, 54, 82, 89, 96, 117, 124, 131, 138,
};
const std::vector<unsigned int> ck550_v2_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
0, 18, 24, 30, 36, 48, 54, 60, 66, 72, 78, 84, 90, 96, 102, 108,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI */
1, 13, 19, 25, 31, 37, 43, 49, 55, 61, 67, 73, 79, 91, 97, 103, 109, 115, 121, 127, 133,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL */
2, 14, 20, 26, 32, 38, 44, 50, 56, 62, 68, 74, 80, 92, 98, 104, 110, 116, 122, 128, 134,
/* CPLK A S D F G H J K L ; ' # ENTR NM4 NM5 NM6 */
3, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 87, 93, 117, 123, 129,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER */
4, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70,/*76,*/ 94, 106, 118, 124, 130, 136,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
5, 11, 17, 41, 65, 71, 77, 95, 101, 107, 113, 125, 131,
};
const std::vector<unsigned int> ck552_keymap =
{
/* ESC F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 PRSC SCLK PSBK */
0, 18, 24, 30, 36, 48, 54, 60, 66, 72, 78, 84, 90, 96, 102, 108,
/* BKTK 1 2 3 4 5 6 7 8 9 0 - = BPSC INS HOME PGUP NMLK NMDV NMTM NMMI */
1, 13, 19, 25, 31, 37, 43, 49, 55, 61, 67, 73, 79, 91, 97, 103, 109, 115, 121, 127, 133,
/* TAB Q W E R T Y U I O P [ ] \ DEL END PGDN NM7 NM8 NM9 NMPL */
2, 14, 20, 26, 32, 38, 44, 50, 56, 62, 68, 74, 80, 92, 98, 104, 110, 116, 122, 128, 134,
/* CPLK A S D F G H J K L ; ' # ENTR NM4 NM5 NM6 */
3, 15, 21, 27, 33, 39, 45, 51, 57, 63, 69, 75, 81, 93, 117, 123, 129,
/* LSFT ISO\ Z X C V B N M , . / RSFT ARWU NM1 NM2 NM3 NMER */
4, 10, 16, 22, 28, 34, 40, 46, 52, 58, 64, 70,/*76,*/ 94, 106, 118, 124, 130, 136,
/* LCTL LWIN LALT SPACE RALT RWFNC RMNU RCTRL ARWL ARDN ARWR NM0 NMPD */
5, 11, 17, 41, 65, 71, 77, 95, 101, 107, 113, 125, 131,
};
/*-------------------------------------------------------------------------*\
| KEYMAPS |
\*-------------------------------------------------------------------------*/
keyboard_keymap_overlay_values mk_pro_s_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_TKL,
{
mk_pro_s_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, Alternate Name, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
},
};
keyboard_keymap_overlay_values mk_pro_l_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
mk_pro_l_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Name, Alternate Name, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
{ 0, 0, 17, 101, "Key: P1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 18, 109, "Key: P2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 19, 117, "Key: P3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 20, 119, "Key: P4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
},
};
/*-------------------------------------------------------------*\
| CoolerMaster MK85O Keyboard |
| Unknown Keys: ISO\, ISO# set to 0 |
\*-------------------------------------------------------------*/
keyboard_keymap_overlay_values mk850_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
mk850_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Name, Alternate Name, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
{ 0, 0, 17, 146, "Key: Aim <|>", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, }, // aimpad <|>
{ 0, 0, 18, 153, "Key: Aim -", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, }, // aimpad +
{ 0, 0, 19, 160, "Key: Aim +", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, }, // aimpad -
{ 0, 1, 0, 0, "Key: M5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 0, 1, "Key: M4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 0, 2, "Key: M3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 0, 3, "Key: M2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 5, 0, 4, "Key: M1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
},
};
keyboard_keymap_overlay_values sk620_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_SIXTY,
{
sk620_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*-----------------------------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, Alternate Name, OpCode, |
\*-----------------------------------------------------------------------------------------------------------------------------*/
{ 0, 0, 0, 7, "Light: Top 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_ROW, },
{ 0, 0, 1, 14, "Light: Top 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 2, 21, "Light: Top 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 3, 28, "Light: Top 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 4, 35, "Light: Top 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 5, 42, "Light: Top 6", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 6, 49, "Light: Top 7", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 7, 56, "Light: Top 8", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 8, 63, "Light: Top 9", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 9, 70, "Light: Top 10", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 10, 77, "Light: Top 11", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 11, 84, "Light: Top 12", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 12, 91, "Light: Top 13", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 13, 98, "Light: Top 14", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 14, 105, "Light: Top 14", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 1, 0, 0, "Light: Left 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 0, 1, "Light: Left 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 0, 2, "Light: Left 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 0, 3, "Light: Left 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 5, 0, 4, "Light: Left 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 1, 16, 112, "Light: Right 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 16, 113, "Light: Right 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 16, 114, "Light: Right 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 16, 115, "Light: Right 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 5, 16, 116, "Light: Right 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 0, 6, "Light: Bottom 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_ROW, },
{ 0, 6, 1, 20, "Light: Bottom 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 2, 27, "Light: Bottom 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 3, 34, "Light: Bottom 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 4, 41, "Light: Bottom 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 5, 48, "Light: Bottom 6", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 6, 55, "Light: Bottom 7", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 7, 62, "Light: Bottom 8", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 8, 69, "Light: Bottom 9", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 9, 76, "Light: Bottom 10", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 10, 83, "Light: Bottom 11", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 11, 90, "Light: Bottom 12", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 12, 97, "Light: Bottom 13", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 13, 104, "Light: Bottom 14", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 14, 111, "Light: Bottom 15", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 14, 118, "Light: Bottom 16", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
},
};
keyboard_keymap_overlay_values sk622_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_SIXTY,
{
sk622_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Name, Alternate Name, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
{ 0, 0, 0, 7, "Light: Top 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_ROW, },
{ 0, 0, 1, 14, "Light: Top 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 2, 21, "Light: Top 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 3, 28, "Light: Top 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 4, 35, "Light: Top 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 5, 42, "Light: Top 6", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 6, 49, "Light: Top 7", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 7, 56, "Light: Top 8", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 8, 63, "Light: Top 9", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 9, 70, "Light: Top 10", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 10, 77, "Light: Top 11", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 11, 84, "Light: Top 12", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 12, 91, "Light: Top 13", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 13, 98, "Light: Top 14", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 14, 105, "Light: Top 14", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 1, 0, 0, "Light: Left 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 0, 1, "Light: Left 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 0, 2, "Light: Left 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 0, 3, "Light: Left 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 5, 0, 4, "Light: Left 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 1, 16, 112, "Light: Right 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 16, 113, "Light: Right 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 16, 114, "Light: Right 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 16, 115, "Light: Right 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 5, 16, 116, "Light: Right 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 0, 6, "Light: Bottom 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_ROW, },
{ 0, 6, 1, 20, "Light: Bottom 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 2, 27, "Light: Bottom 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 3, 34, "Light: Bottom 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 4, 41, "Light: Bottom 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 5, 48, "Light: Bottom 6", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 6, 55, "Light: Bottom 7", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 7, 62, "Light: Bottom 8", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 8, 69, "Light: Bottom 9", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 9, 76, "Light: Bottom 10", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 10, 83, "Light: Bottom 11", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 11, 90, "Light: Bottom 12", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 12, 97, "Light: Bottom 13", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 13, 104, "Light: Bottom 14", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 14, 111, "Light: Bottom 15", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 14, 118, "Light: Bottom 16", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
},
};
keyboard_keymap_overlay_values sk630_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_TKL,
{
sk630_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
}
};
keyboard_keymap_overlay_values sk650_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
sk650_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
}
};
keyboard_keymap_overlay_values sk652_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
sk652_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
}
};
keyboard_keymap_overlay_values sk653_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
sk653_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
}
};
/*-------------------------------------------------------------*\
| CoolerMaster MK730 Keyboard |
\*-------------------------------------------------------------*/
keyboard_keymap_overlay_values mk730_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_TKL,
{
mk730_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Name, Alternate Name, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
{ 0, 1, 0, 1, "Light: Left 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 0, 2, "Light: Left 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 0, 3, "Light: Left 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 0, 4, "Light: Left 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 1, 18, 141, "Light: Right 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 18, 142, "Light: Right 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 18, 143, "Light: Right 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 18, 144, "Light: Right 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 1, 13, "Light: Bottom 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_ROW, },
{ 0, 6, 2, 20, "Light: Bottom 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 3, 27, "Light: Bottom 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 4, 34, "Light: Bottom 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 5, 41, "Light: Bottom 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 6, 55, "Light: Bottom 6", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 7, 62, "Light: Bottom 7", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 8, 69, "Light: Logo", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 10, 76, "Light: Bottom 8", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 11, 90, "Light: Bottom 9", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 12, 104, "Light: Bottom 10", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 13, 111, "Light: Bottom 11", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 14, 118, "Light: Bottom 12", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 15, 125, "Light: Bottom 13", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
}
};
/*-------------------------------------------------------------*\
| CoolerMaster MK750 Keyboard |
| based on keymap defined in Signal. |
| The keymap needs the following adjustments |
| NMLK - Unknown set to 0 |
| SCLK - Unknown set to 0 |
| CAPS - Unknown set to 0 |
| Guesses on ISO\ and # |
\*-------------------------------------------------------------*/
keyboard_keymap_overlay_values mk750_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
mk750_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Name, Alternate Name, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
{ 0, 0, 17, 140, KEY_EN_MEDIA_MUTE, KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 18, 147, KEY_EN_MEDIA_PLAY_PAUSE, KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 19, 154, KEY_EN_MEDIA_PREVIOUS, KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 20, 161, KEY_EN_MEDIA_NEXT, KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 1, 0, 1, "Light: Left 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 0, 2, "Light: Left 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 0, 3, "Light: Left 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 0, 4, "Light: Left 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 1, 22, 170, "Light: Right 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 2, 22, 171, "Light: Right 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 3, 22, 172, "Light: Right 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 4, 22, 173, "Light: Right 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 1, 20, "Light: Bottom 1", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_ROW, },
{ 0, 6, 2, 27, "Light: Bottom 2", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 3, 34, "Light: Bottom 3", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 4, 41, "Light: Bottom 4", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 5, 55, "Light: Bottom 5", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 6, 62, "Light: Bottom 6", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 7, 69, "Light: Bottom 7", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 8, 76, "Light: Bottom 8", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 9, 83, "Light: Bottom 9", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 10, 90, "Light: Bottom 10", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 11, 104, "Light: Bottom 11", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 12, 111, "Light: Bottom 12", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 13, 118, "Light: Bottom 13", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 14, 125, "Light: Bottom 14", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 15, 132, "Light: Bottom 15", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 16, 146, "Light: Bottom 16", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 17, 153, "Light: Bottom 17", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 6, 18, 160, "Light: Bottom 18", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
}
};
keyboard_keymap_overlay_values ck530_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_TKL,
{
ck530_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
}
};
keyboard_keymap_overlay_values ck530_v2_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_TKL,
{
ck530_v2_keymap,
{
/* Add more regional layout fixes here */
}
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
}
};
keyboard_keymap_overlay_values ck550v2_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
ck550_v2_keymap,
{
{
/* Add more regional layout fixes here */
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
},
},
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Name, Alternate Name, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
{ 0, 0, 17, 120, "Indicator: N", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 18, 126, "Indicator: C", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
{ 0, 0, 19, 132, "Indicator: S", KEY_EN_UNUSED, KEYBOARD_OPCODE_INSERT_SHIFT_RIGHT, },
},
};
keyboard_keymap_overlay_values ck552_layout
{
KEYBOARD_SIZE::KEYBOARD_SIZE_FULL,
{
ck552_keymap,
{
{
/* Add more regional layout fixes here */
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
},
},
},
{
/*---------------------------------------------------------------------------------------------------------*\
| Edit Keys |
| Zone, Row, Column, Value, Key, OpCode, |
\*---------------------------------------------------------------------------------------------------------*/
},
};
static const cm_kb_zone cm_generic_zone =
{
ZONE_EN_KEYBOARD,
ZONE_TYPE_MATRIX,
};
cm_kb_device mk_pro_s_device
{
COOLERMASTER_KEYBOARD_PRO_S_PID,
{
&cm_generic_zone,
},
&mk_pro_s_layout,
};
cm_kb_device mk_pro_l_device
{
COOLERMASTER_KEYBOARD_PRO_L_PID,
{
&cm_generic_zone,
},
&mk_pro_l_layout,
};
cm_kb_device mk850_device
{
COOLERMASTER_KEYBOARD_MK850_PID,
{
&cm_generic_zone,
},
&mk850_layout,
};
cm_kb_device sk620w_device
{
COOLERMASTER_KEYBOARD_SK620W_PID,
{
&cm_generic_zone,
},
&sk620_layout,
};
cm_kb_device sk620b_device
{
COOLERMASTER_KEYBOARD_SK620B_PID,
{
&cm_generic_zone,
},
&sk620_layout,
};
cm_kb_device sk622w_device
{
COOLERMASTER_KEYBOARD_SK622W_PID,
{
&cm_generic_zone,
},
&sk622_layout,
};
cm_kb_device sk622b_device
{
COOLERMASTER_KEYBOARD_SK622B_PID,
{
&cm_generic_zone,
},
&sk622_layout,
};
cm_kb_device sk630_device
{
COOLERMASTER_KEYBOARD_SK630_PID,
{
&cm_generic_zone,
},
&sk630_layout,
};
cm_kb_device sk650_device
{
COOLERMASTER_KEYBOARD_SK650_PID,
{
&cm_generic_zone,
},
&sk650_layout,
};
cm_kb_device sk652_device
{
COOLERMASTER_KEYBOARD_SK652_PID,
{
&cm_generic_zone,
},
&sk652_layout,
};
cm_kb_device sk653_device
{
COOLERMASTER_KEYBOARD_SK653_PID,
{
&cm_generic_zone,
},
&sk652_layout,
};
/*---------------------------------------------------------*\
| TODO: Keymap is incomplete. Extra keys mode enabled to |
| aid in key discovery. |
\*---------------------------------------------------------*/
cm_kb_device mk730_device
{
COOLERMASTER_KEYBOARD_MK730_PID,
{
&cm_generic_zone,
},
&mk730_layout,
};
cm_kb_device mk750_device
{
COOLERMASTER_KEYBOARD_MK750_PID,
{
&cm_generic_zone,
},
&mk750_layout,
};
cm_kb_device ck530_device
{
COOLERMASTER_KEYBOARD_CK530_PID,
{
&cm_generic_zone,
},
&ck530_layout,
};
cm_kb_device ck530_v2_device
{
COOLERMASTER_KEYBOARD_CK530_V2_PID,
{
&cm_generic_zone,
},
&ck530_v2_layout,
};
cm_kb_device ck550_v2_device
{
COOLERMASTER_KEYBOARD_CK550_V2_PID,
{
&cm_generic_zone,
},
&ck550v2_layout,
};
cm_kb_device ck552_v2_device
{
COOLERMASTER_KEYBOARD_CK552_V2_PID,
{
&cm_generic_zone,
},
&ck552_layout,
};
cm_kb_device mk_pro_l_white_device
{
COOLERMASTER_KEYBOARD_PRO_L_WHITE_PID,
{
&cm_generic_zone,
},
&mk_pro_s_layout,
};
/*-----------------------------------------------------------------*\
| KEYBOARDS |
\*-----------------------------------------------------------------*/
const cm_kb_device* cm_kb_devices[] =
{
&mk_pro_s_device,
&mk_pro_l_device,
&mk850_device,
&sk620w_device,
&sk620b_device,
&sk622w_device,
&sk622b_device,
&sk630_device,
&sk650_device,
&sk652_device,
&sk653_device,
&mk730_device,
&mk750_device,
&ck530_device,
&ck530_v2_device,
&ck550_v2_device,
&ck552_v2_device,
&mk_pro_l_white_device,
};
const unsigned int COOLERMASTER_KEYBOARD_DEVICE_COUNT = (sizeof(cm_kb_devices) / sizeof(cm_kb_devices[ 0 ]));
const cm_kb_device** cm_kb_device_list = cm_kb_devices;
@@ -0,0 +1,123 @@
/*---------------------------------------------------------*\
| CMKeyboardDevices.h |
| |
| Device list for Cooler Master keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "KeyboardLayoutManager.h"
/*-----------------------------------------------------*\
| List of all supported effects by this controller. |
| All of these effects are firmware controlled, and |
| they types of effects supported will depend on the |
| Keyboard. |
| |
| To enable a command, the SetEffect(effectId) needs |
| to be called. The specific effectId->Effect mapping |
| depends on the keyboard. |
\*-----------------------------------------------------*/
enum cm_keyboard_effect_type
{
NONE = 0,
DIRECT,
SINGLE,
FULLY_LIT,
STATIC,
BREATHE,
CYCLE,
WAVE,
RIPPLE,
CROSS,
RAINDROPS,
STARS,
SNAKE,
CUSTOMIZED,
INDICATOR,
MULTILAYER,
REACTIVE_FADE,
REACTIVE_PUNCH,
REACTIVE_TORNADO,
HEARTBEAT,
FIREBALL,
SNOW,
CIRCLE_SPECTRUM,
WATER_RIPPLE,
OFF
};
#define CM_KB_ZONES_MAX 1
typedef struct
{
std::string name;
zone_type type;
} cm_kb_zone;
typedef struct
{
uint16_t product_id;
const cm_kb_zone * zones[CM_KB_ZONES_MAX];
keyboard_keymap_overlay_values* layout_new;
} cm_kb_device;
#define COOLERMASTER_VID 0x2516
#define CMKB_MAXKEYS 256
/*-----------------------------------------------------------------*\
| keyboard support status is indicated to the right of |
| the PID definition. Attribution to products is also |
| indicated. |
| |
| libcmmk |
| signal https://gitlab.com/signalrgb/signal-plugins |
| openrgb |
| ck550-macos https://github.com/vookimedlo/ck550-macos/tree/master |
| reversed |
| |
| issue tickets, open merge requests etc are provided |
| for developer references. |
| # denotes issue ticket |
| ! denotes merge/pull request |
\*-----------------------------------------------------------------*/
#define COOLERMASTER_KEYBOARD_CK351_PID 0x014F // unsupported
#define COOLERMASTER_KEYBOARD_CK530_PID 0x009F // [ck550-macos]
#define COOLERMASTER_KEYBOARD_CK530_V2_PID 0x0147 // [signal]
#define COOLERMASTER_KEYBOARD_CK550_V2_PID 0x0145 // [openrgb #800, #2863, signal]
#define COOLERMASTER_KEYBOARD_CK552_V2_PID 0x007F // [ck550-macos, signal]
#define COOLERMASTER_KEYBOARD_CK570_V2_PID 0x01E8 // unsupported
#define COOLERMASTER_KEYBOARD_CK720_PID 0x016B // unsupported
#define COOLERMASTER_KEYBOARD_CK721_PID 0x016D // unsupported
#define COOLERMASTER_KEYBOARD_CK721LINE_PID 0x01EE // unsupported
#define COOLERMASTER_KEYBOARD_PRO_L_PID 0x003B // [libcmmk !16]
#define COOLERMASTER_KEYBOARD_PRO_L_WHITE_PID 0x0047 // [libcmmk]
#define COOLERMASTER_KEYBOARD_PRO_S_PID 0x003C // [libcmmk #30 !31 !36, !37, !7, #5(closed), #3(closed)]
// MASTERKEYS PRO M [libcmmk #17]
#define COOLERMASTER_KEYBOARD_MK721_PID 0x016F // unsupported
#define COOLERMASTER_KEYBOARD_MK730_PID 0x008F // [openrgb #1630, libcmmk]
#define COOLERMASTER_KEYBOARD_MK750_PID 0x0067 // fw1.2 [libcmmk #25 !9, !14, signal]
#define COOLERMASTER_KEYBOARD_MK770_PID 0x01D5 // unsupported
#define COOLERMASTER_KEYBOARD_MK850_PID 0x0069 // [signal]
#define COOLERMASTER_KEYBOARD_SK620B_PID 0x0157 // [openrgb #4292]
#define COOLERMASTER_KEYBOARD_SK620W_PID 0x0159 // [openrgb #4292, signal]
#define COOLERMASTER_KEYBOARD_SK622B_PID 0x0149 // [openrgb #3110, signal #217(closed)]
#define COOLERMASTER_KEYBOARD_SK622W_PID 0x014B // [signal]
#define COOLERMASTER_KEYBOARD_SK630_PID 0x0089 // [openrgb #967, libcmmk !21]
#define COOLERMASTER_KEYBOARD_SK631B_PID 0x008B // unsupported
#define COOLERMASTER_KEYBOARD_SK631W_PID 0x0125 // [libcmmk]
#define COOLERMASTER_KEYBOARD_SK650_PID 0x008D // [openrgb #613, libcmmk #23 !37 !27 !28, signal]
#define COOLERMASTER_KEYBOARD_SK651B_PID 0x0091 // unsupported
#define COOLERMASTER_KEYBOARD_SK651W_PID 0x0127 // [signal]
#define COOLERMASTER_KEYBOARD_SK652_PID 0x015D // [signal]
#define COOLERMASTER_KEYBOARD_SK653_PID 0x01AB // [openrgb #3571, signal]
extern const unsigned int COOLERMASTER_KEYBOARD_DEVICE_COUNT;
extern const cm_kb_device** cm_kb_device_list;
@@ -0,0 +1,500 @@
/*---------------------------------------------------------*\
| CMKeyboardV1Controller.cpp |
| |
| Driver for Cooler Master MasterKeys (V1) keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cmath>
#include "CMKeyboardV1Controller.h"
#include "LogManager.h"
CMKeyboardV1Controller::CMKeyboardV1Controller(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name) : CMKeyboardAbstractController(dev_handle, dev_info, dev_name)
{
m_sFirmwareVersion = _GetFirmwareVersion();
}
CMKeyboardV1Controller::~CMKeyboardV1Controller()
{
}
void CMKeyboardV1Controller::Initialize()
{
SetLEDControl(true);
}
void CMKeyboardV1Controller::SetActiveEffect(uint8_t effectId)
{
SendCommand({0x51, 0x28, 0x00, 0x00, effectId});
}
uint8_t CMKeyboardV1Controller::GetActiveEffect()
{
std::vector<uint8_t> data = SendCommand({0x52, 0x28});
return data[4];
}
void CMKeyboardV1Controller::SetEffect(uint8_t effectId, uint8_t p1, uint8_t p2, uint8_t p3, RGBColor color1, RGBColor color2)
{
std::vector<uint8_t> data;
data.push_back(0x51);
data.push_back(0x2C);
data.push_back(0x00); // multilayer_mode - NOT SUPPORTED
data.push_back(0x00);
data.push_back(effectId);
data.push_back(p1);
data.push_back(p2);
data.push_back(p3);
data.push_back(0xFF);
data.push_back(0xFF);
data.push_back(RGBGetRValue(color1));
data.push_back(RGBGetGValue(color1));
data.push_back(RGBGetBValue(color1));
data.push_back(RGBGetRValue(color2));
data.push_back(RGBGetGValue(color2));
data.push_back(RGBGetBValue(color2));
/*-------------------------------------------*\
| Likely a bit mask for each LEDs. |
| 3 bits per LED x 127 possible LEDs ~48 bytes|
\*-------------------------------------------*/
for(size_t i = 0; i < 48; i++)
{
data.push_back(0xFF);
}
SetCustomMode();
SetActiveEffect(effectId);
SendCommand(data);
}
void CMKeyboardV1Controller::SetCustomMode()
{
SetControlMode(0x01);
}
void CMKeyboardV1Controller::SetMode(mode selectedMode)
{
RGBColor color1 = 0;
RGBColor color2 = 0;
uint8_t cSpeed = 0;
uint8_t cDirection = 0;
uint8_t effectId = selectedMode.value;
bool bModeRandom = false;
if(selectedMode.colors.size() >= 1)
{
color1 = selectedMode.colors[0];
}
if(selectedMode.colors.size() >= 2)
{
color2 = selectedMode.colors[1];
}
if(selectedMode.color_mode == MODE_COLORS_RANDOM)
{
bModeRandom = true;
}
int selectedEffect = mapModeValueEffect[effectId];
cSpeed = selectedMode.speed;
switch(selectedMode.direction)
{
case MODE_DIRECTION_LEFT:
case MODE_DIRECTION_HORIZONTAL:
cDirection = 0x00;
break;
case MODE_DIRECTION_RIGHT:
cDirection = 0x04;
break;
case MODE_DIRECTION_UP:
case MODE_DIRECTION_VERTICAL:
cDirection = 0x06;
break;
case MODE_DIRECTION_DOWN:
cDirection = 0x02;
break;
default:
break;
}
switch(selectedEffect)
{
case DIRECT:
case STATIC:
{
SetEffect(effectId, 0, 0, 0, color1, color2);
}
break;
case CROSS:
case BREATHE:
case REACTIVE_PUNCH:
case CIRCLE_SPECTRUM:
case SNAKE:
{
SetEffect(effectId, cSpeed, 0, 0xFF, color1, color2);
}
break;
case WAVE:
{
SetEffect(effectId, cSpeed, cDirection, 0xFF, color1, color2);
}
break;
case RIPPLE:
{
SetEffect(effectId, cSpeed, bModeRandom ? 0x80 : 0x00, 0xFF, color1, color2);
}
break;
case RAINDROPS:
{
SetEffect(effectId, 0x6a, 0x00, cSpeed, color1, color2);
}
break;
case STARS:
{
SetEffect(effectId, cSpeed, 0x00, 0x10, color1, color2);
}
break;
default:
break;
}
}
void CMKeyboardV1Controller::InitializeModes(std::vector<mode> &modes)
{
mode Direct;
Direct.name = "Direct";
Direct.value = 0x02;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mapModeValueEffect[0x02] = DIRECT;
mode Static;
Static.name = "Static";
Static.value = 0x00;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.colors_min = 1;
Static.colors_max = 1;
Static.colors.resize(1);
modes.push_back(Static);
mapModeValueEffect[0x00] = STATIC;
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = 0x01;
Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.speed_min = 0x46;
Breathing.speed_max = 0x27;
Breathing.speed = 0x36;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(1);
modes.push_back(Breathing);
mapModeValueEffect[0x01] = BREATHE;
mode Cycle;
Cycle.name = "Spectrum Cycle";
Cycle.value = 0x02;
Cycle.flags = MODE_FLAG_HAS_SPEED;
Cycle.color_mode = MODE_COLORS_NONE;
Cycle.speed_min = 0x96;
Cycle.speed_max = 0x68;
Cycle.speed = 0x7F;
modes.push_back(Cycle);
mapModeValueEffect[0x02] = CIRCLE_SPECTRUM;
mode Reactive;
Reactive.name = "Reactive";
Reactive.value = 0x03;
Reactive.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED;
Reactive.color_mode = MODE_COLORS_MODE_SPECIFIC;
Reactive.speed_min = 0x3C;
Reactive.speed_max = 0x2F;
Reactive.speed = 0x35;
Reactive.colors_min = 2;
Reactive.colors_max = 2;
Reactive.colors.resize(2);
modes.push_back(Reactive);
mapModeValueEffect[0x03] = REACTIVE_PUNCH;
mode Wave;
Wave.name = "Rainbow Wave";
Wave.value = 0x04;
Wave.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_DIRECTION_LR | MODE_FLAG_HAS_DIRECTION_UD;
Wave.color_mode = MODE_COLORS_MODE_SPECIFIC;
Wave.speed_min = 0x48;
Wave.speed_max = 0x2A;
Wave.speed = 0x29;
Wave.direction = MODE_DIRECTION_LEFT;
Wave.colors_min = 1;
Wave.colors_max = 1;
Wave.colors.resize(1);
modes.push_back(Wave);
mapModeValueEffect[0x04] = WAVE;
mode Ripple;
Ripple.name = "Ripple Effect";
Ripple.value = 0x05;
Ripple.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED;
Ripple.color_mode = MODE_COLORS_MODE_SPECIFIC;
Ripple.speed_min = 0x96;
Ripple.speed_max = 0x62;
Ripple.speed = 0x7C;
Ripple.colors_min = 2;
Ripple.colors_max = 2;
Ripple.colors.resize(2);
modes.push_back(Ripple);
mapModeValueEffect[0x05] = RIPPLE;
mode Cross;
Cross.name = "Cross";
Cross.value = 0x06;
Cross.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED;
Cross.color_mode = MODE_COLORS_MODE_SPECIFIC;
Cross.speed_min = 0x2A;
Cross.speed_max = 0x48;
Cross.speed = 0x39;
Cross.colors_min = 2;
Cross.colors_max = 2;
Cross.colors.resize(2);
modes.push_back(Cross);
mapModeValueEffect[0x06] = CROSS;
mode Raindrops;
Raindrops.name = "Raindrops";
Raindrops.value = 0x07;
Raindrops.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED;
Raindrops.color_mode = MODE_COLORS_MODE_SPECIFIC;
Raindrops.speed_min = 0x40;
Raindrops.speed_max = 0x08;
Raindrops.speed = 0x24;
Raindrops.colors_min = 2;
Raindrops.colors_max = 2;
Raindrops.colors.resize(2);
modes.push_back(Raindrops);
mapModeValueEffect[0x07] = RAINDROPS;
mode Stars;
Stars.name = "Starfield";
Stars.value = 0x08;
Stars.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_SPEED;
Stars.color_mode = MODE_COLORS_MODE_SPECIFIC;
Stars.speed_min = 0x46;
Stars.speed_max = 0x32;
Stars.speed = 0x3C;
Stars.colors_min = 2;
Stars.colors_max = 2;
Stars.colors.resize(2);
modes.push_back(Stars);
mapModeValueEffect[0x08] = STARS;
mode Snake;
Snake.name = "Snake";
Snake.value = 0x09;
Snake.flags = MODE_FLAG_HAS_SPEED;
Snake.color_mode = MODE_COLORS_NONE;
Snake.speed_min = 0x48;
Snake.speed_max = 0x2A;
Snake.speed = 0x39;
modes.push_back(Snake);
mapModeValueEffect[0x09] = SNAKE;
}
struct cm_keyboard_effect CMKeyboardV1Controller::GetEffect(uint8_t effectId)
{
std::vector<uint8_t> data;
data.push_back(0x52);
data.push_back(0x2C);
data.push_back(0x00);
data.push_back(0x00);
data.push_back(effectId);
data = SendCommand(data);
struct cm_keyboard_effect response;
response.effectId = effectId;
response.p1 = data[5];
response.p2 = data[6];
response.p3 = data[7];
response.color1 = ToRGBColor(data[10], data[11], data[12]);
response.color2 = ToRGBColor(data[13], data[14], data[15]);
return response;
}
std::vector<uint8_t> CMKeyboardV1Controller::GetEnabledEffects()
{
std::vector<uint8_t> data;
data = SendCommand({0x52, 0x29});
std::vector<uint8_t> effects;
for(size_t i = 4; data[i] != 0xFF; i++)
{
effects.push_back(data[i]);
}
return effects;
}
void CMKeyboardV1Controller::SetLEDControl(bool bManual)
{
uint8_t modeId = 0; // firmware
if(bManual)
{
modeId = 0x02; // manual
}
SetControlMode(modeId);
};
void CMKeyboardV1Controller::SetLeds(std::vector<led> leds, std::vector<RGBColor> colors)
{
SetLEDControl(true);
RGBColor rgbColorMap[CM_MAX_LEDS];
memset(rgbColorMap, 0, sizeof(RGBColor)*CM_MAX_LEDS);
for(size_t i = 0; i < leds.size(); i++)
{
rgbColorMap[leds[i].value] = colors[i];
}
RGBColor * pRGBColor = rgbColorMap;
std::lock_guard<std::mutex> guard(m_mutex);
for(size_t i = 0; i < 8; i++)
{
std::vector<uint8_t> data;
data.push_back(0xC0);
data.push_back(0x02);
data.push_back((uint8_t)(i * 2));
data.push_back(0x00);
for(size_t j = 0; j < 16; j++)
{
data.push_back(RGBGetRValue(*pRGBColor));
data.push_back(RGBGetGValue(*pRGBColor));
data.push_back(RGBGetBValue(*pRGBColor));
++pRGBColor;
}
SendCommand(data);
}
}
void CMKeyboardV1Controller::SetSingleLED(uint8_t in_led, RGBColor in_color)
{
std::vector<uint8_t> data;
data.push_back(0xC0);
data.push_back(0x01);
data.push_back(0x01);
data.push_back(0x00);
data.push_back(in_led);
data.push_back(RGBGetRValue(in_color));
data.push_back(RGBGetGValue(in_color));
data.push_back(RGBGetBValue(in_color));
SendCommand(data);
}
/*-------------------------------------------------------------------*\
| Detect the Firmware Version |
| |
| Firmware version string is in the format: |
| <layout>.<minor>.<major> |
| Where <layout> is: |
| UNK = 0, ANSI/US = 1, ISO/EU = 2, JP = 3 |
| Examples: |
| 1.2.1 = ANSI/US Keyboard (PRO S) |
| 2.2.1 = ISO/EU Keyboard (PRO L) |
\*-------------------------------------------------------------------*/
std::string CMKeyboardV1Controller::_GetFirmwareVersion()
{
std::vector<uint8_t> read;
SetControlMode(MODE_FIRMWARE);
read = SendCommand({0x01, 0x02});
char cVersionStr[CM_KEYBOARD_WRITE_SIZE];
for(size_t i = 0; i < read.size(); i++)
{
cVersionStr[i] = read[i];
}
cVersionStr[CM_KEYBOARD_WRITE_SIZE - 1] = 0;
std::string sFirmwareVersion;
sFirmwareVersion = std::string(cVersionStr+4);
LOG_VERBOSE("[%s] GetFirmwareVersion(): [%s]", m_deviceName.c_str(), sFirmwareVersion.c_str());
return sFirmwareVersion;
}
void CMKeyboardV1Controller::Shutdown()
{
}
KEYBOARD_LAYOUT CMKeyboardV1Controller::GetKeyboardLayout()
{
KEYBOARD_LAYOUT layout = KEYBOARD_LAYOUT_DEFAULT;
if(m_sFirmwareVersion.empty())
{
LOG_WARNING("[%s] GetKeyboardLayout() empty firmware string detected. Unable to detect firmware layout. Assuming defaults.", m_deviceName.c_str());
layout = KEYBOARD_LAYOUT_ANSI_QWERTY;
return layout;
}
switch(m_sFirmwareVersion.c_str()[0])
{
case '0':
default:
case '1':
layout = KEYBOARD_LAYOUT_ANSI_QWERTY;
break;
case '2':
layout = KEYBOARD_LAYOUT_ISO_QWERTY;
break;
case '3':
layout = KEYBOARD_LAYOUT_JIS;
break;
}
return layout;
}
@@ -0,0 +1,43 @@
/*---------------------------------------------------------*\
| CMKeyboardV1Controller.h |
| |
| Driver for Cooler Master MasterKeys (V1) keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "CMKeyboardAbstractController.h"
class CMKeyboardV1Controller : public CMKeyboardAbstractController
{
public:
CMKeyboardV1Controller(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name);
~CMKeyboardV1Controller();
/*---------------------------------------------------------*\
| Protocol specific funtions to be implmented |
\*---------------------------------------------------------*/
void SetLeds(std::vector<led> leds, std::vector<RGBColor> colors);
void SetSingleLED(uint8_t in_led, RGBColor in_color);
void Initialize();
void Shutdown();
void SetLEDControl(bool bManual);
void SetActiveEffect(uint8_t effectId);
uint8_t GetActiveEffect();
void SetEffect(uint8_t effectId, uint8_t p1, uint8_t p2, uint8_t p3, RGBColor color1, RGBColor color2);
struct cm_keyboard_effect GetEffect(uint8_t effectId);
void SetCustomMode();
void SetMode(mode selectedMode);
std::vector<uint8_t> GetEnabledEffects();
void InitializeModes(std::vector<mode> &modes);
KEYBOARD_LAYOUT GetKeyboardLayout();
private:
std::string _GetFirmwareVersion();
};
@@ -0,0 +1,59 @@
/*---------------------------------------------------------*\
| CMKeyboardV2Controller.h |
| |
| Driver for Cooler Master V2 keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "CMKeyboardAbstractController.h"
struct stCMKeyboardV2_mode
{
const char *name;
unsigned int value;
unsigned int speed_min;
unsigned int speed_max;
unsigned int speed;
unsigned int brightness;
unsigned int direction;
unsigned int nColors;
unsigned int color_mode;
unsigned int flags;
};
class CMKeyboardV2Controller : public CMKeyboardAbstractController
{
public:
CMKeyboardV2Controller(hid_device* dev_handle, hid_device_info* dev_info, std::string dev_name);
~CMKeyboardV2Controller();
/*---------------------------------------------------------*\
| Protocol specific funtions to be implmented |
\*---------------------------------------------------------*/
void SetLeds(std::vector<led> leds, std::vector<RGBColor> colors);
void SetSingleLED(uint8_t in_led, RGBColor in_color);
void Initialize();
void Shutdown();
void SetLEDControl(bool bManual);
void SendApplyPacket(uint8_t mode);
void MagicStartupPacket();
void MagicCommand(uint8_t profileId);
void SetCustomMode();
void SetMode(mode selectedMode);
void SetEffect(uint8_t effectId, uint8_t p1, uint8_t p2, uint8_t p3, RGBColor color1, RGBColor color2);
void InitializeModes(std::vector<mode> &modes);
KEYBOARD_LAYOUT GetKeyboardLayout();
private:
void _SetEffectMode(uint8_t effectId);
void _UpdateSpeed(mode selectedMode, uint8_t &cSpeed1, uint8_t &cSpeed2);
std::string _GetFirmwareVersion();
bool m_bMoreFFs;
};
@@ -0,0 +1,197 @@
/*---------------------------------------------------------*\
| RGBController_CMKeyboardController.cpp |
| |
| RGBController for Cooler Master keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMKeyboardController.h"
#include "CMKeyboardDevices.h"
/**------------------------------------------------------------------*\
@name Coolermaster Masterkeys Keyboards
@category Keyboard
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterV1Keyboards,DetectCoolerMasterV2Keyboards
@comment
In CMKeyboardV1Controller brightness control not supported.
Supported effects differ between CMKeyboardV1Controller and
CMKeyboardV2Controller.
\*-------------------------------------------------------------------*/
RGBController_CMKeyboardController::RGBController_CMKeyboardController(CMKeyboardAbstractController* pController)
{
m_pController = pController;
vendor = m_pController->GetDeviceVendor();
type = DEVICE_TYPE_KEYBOARD;
description = "Cooler Master Keyboard Device";
version = m_pController->GetFirmwareVersion();
/*----------------------------------------------------------------*\
| Coolermaster uses the name field to store the serial number in |
| many of their keyboards. |
\*----------------------------------------------------------------*/
serial = m_pController->GetDeviceSerial();
location = m_pController->GetLocation();
m_keyboardLayout = m_pController->GetKeyboardLayout();
name = m_pController->GetDeviceName();
m_pController->InitializeModes(modes);
SetupZones();
}
RGBController_CMKeyboardController::~RGBController_CMKeyboardController()
{
/*---------------------------------------------------------*\
| Delete the matrix map |
\*---------------------------------------------------------*/
for(unsigned int zone_index = 0; zone_index < zones.size(); zone_index++)
{
if(zones[zone_index].matrix_map != NULL)
{
if(zones[zone_index].matrix_map->map != NULL)
{
delete zones[zone_index].matrix_map->map;
}
delete zones[zone_index].matrix_map;
}
}
if(m_pController)
{
delete m_pController;
}
}
#define COOLERMASTER_ZONES_MAX 1
void RGBController_CMKeyboardController::SetupZones()
{
std::string physical_size;
unsigned int max_led_value = 0;
const cm_kb_device* coolermaster = m_pController->GetDeviceData();
/*---------------------------------------------------------*\
| Fill in zones from the device data |
\*---------------------------------------------------------*/
for(size_t i = 0; i < COOLERMASTER_ZONES_MAX; i++)
{
if(coolermaster->zones[i] == NULL)
{
break;
}
else
{
zone new_zone;
new_zone.name = coolermaster->zones[i]->name;
new_zone.type = coolermaster->zones[i]->type;
if(new_zone.type == ZONE_TYPE_MATRIX)
{
KeyboardLayoutManager new_kb(m_keyboardLayout, coolermaster->layout_new->base_size, coolermaster->layout_new->key_values);
matrix_map_type * new_map = new matrix_map_type;
new_zone.matrix_map = new_map;
if(coolermaster->layout_new->base_size != KEYBOARD_SIZE_EMPTY)
{
/*---------------------------------------------------------*\
| Minor adjustments to keyboard layout |
\*---------------------------------------------------------*/
keyboard_keymap_overlay_values* temp = coolermaster->layout_new;
new_kb.ChangeKeys(*temp);
new_map->height = new_kb.GetRowCount();
new_map->width = new_kb.GetColumnCount();
new_map->map = new unsigned int[new_map->height * new_map->width];
/*---------------------------------------------------------*\
| Matrix map still uses declared zone rows and columns |
| as the packet structure depends on the matrix map |
\*---------------------------------------------------------*/
new_kb.GetKeyMap(new_map->map, KEYBOARD_MAP_FILL_TYPE_COUNT, new_map->height, new_map->width);
/*---------------------------------------------------------*\
| Create LEDs for the Matrix zone |
| Place keys in the layout to populate the matrix |
\*---------------------------------------------------------*/
new_zone.leds_count = new_kb.GetKeyCount();
LOG_DEBUG("[%s] Created KB matrix with %d rows and %d columns containing %d keys",
m_pController->GetDeviceName().c_str(), new_kb.GetRowCount(), new_kb.GetColumnCount(), new_zone.leds_count);
for(unsigned int led_idx = 0; led_idx < new_zone.leds_count; led_idx++)
{
led new_led;
new_led.name = new_kb.GetKeyNameAt(led_idx);
new_led.value = new_kb.GetKeyValueAt(led_idx);
max_led_value = std::max(max_led_value, new_led.value);
leds.push_back(new_led);
}
}
/*---------------------------------------------------------*\
| Add 1 the max_led_value to account for the 0th index |
\*---------------------------------------------------------*/
max_led_value++;
}
/*---------------------------------------------------------*\
| name is not set yet so description is used instead |
\*---------------------------------------------------------*/
LOG_DEBUG("[%s] Creating a %s zone: %s with %d LEDs", description.c_str(),
((new_zone.type == ZONE_TYPE_MATRIX) ? "matrix": "linear"),
new_zone.name.c_str(), new_zone.leds_count);
new_zone.leds_min = new_zone.leds_count;
new_zone.leds_max = new_zone.leds_count;
zones.push_back(new_zone);
}
}
SetupColors();
}
void RGBController_CMKeyboardController::ResizeZone(int /*zone*/, int /*new_size*/)
{
}
void RGBController_CMKeyboardController::DeviceUpdateLEDs()
{
m_pController->SetLeds(leds, colors);
}
void RGBController_CMKeyboardController::UpdateSingleLED(int led, RGBColor color)
{
uint8_t key_value = m_pLayoutManager->GetKeyValueAt(led);
m_pController->SetSingleLED(key_value, color);
}
void RGBController_CMKeyboardController::UpdateSingleLED(int led)
{
m_pController->SetSingleLED(led, colors[led]);
}
void RGBController_CMKeyboardController::UpdateZoneLEDs(int /*zone_idx*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMKeyboardController::DeviceUpdateMode()
{
m_pController->SetMode(modes[active_mode]);
}
void RGBController_CMKeyboardController::SetCustomMode()
{
}
@@ -0,0 +1,42 @@
/*---------------------------------------------------------*\
| RGBController_CMKeyboardController.h |
| |
| RGBController for Cooler Master keyboards |
| |
| Tam D (too.manyhobbies) 30 Nov 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CMKeyboardAbstractController.h"
#include "CMKeyboardV1Controller.h"
#include "CMKeyboardV2Controller.h"
#include "CMKeyboardDevices.h"
class RGBController_CMKeyboardController : public RGBController
{
public:
RGBController_CMKeyboardController(CMKeyboardAbstractController* pController);
~RGBController_CMKeyboardController();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateSingleLED(int led, RGBColor color);
void UpdateSingleLED(int led);
void UpdateZoneLEDs(int zone_idx);
void SetCustomMode();
void DeviceUpdateMode();
private:
CMKeyboardAbstractController* m_pController;;
KeyboardLayoutManager* m_pLayoutManager;
KEYBOARD_LAYOUT m_keyboardLayout;
layout_values m_layoutValues;
};
@@ -0,0 +1,206 @@
/*---------------------------------------------------------*\
| CMMM711Controller.cpp |
| |
| Driver for Cooler Master M711 mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "CMMM711Controller.h"
#include "StringUtils.h"
CMMM711Controller::CMMM711Controller(hid_device* dev_handle, char *_path)
{
dev = dev_handle;
location = _path;
current_speed = CM_MM711_SPEED_NORMAL;
/*---------------------------------------------------------*\
| Get device name from HID manufacturer and product strings |
\*---------------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
SendInitPacket();
GetColourStatus();
GetCustomStatus();
GetModeStatus();
}
CMMM711Controller::~CMMM711Controller()
{
hid_close(dev);
}
void CMMM711Controller::GetColourStatus()
{
uint8_t buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x52, 0x2B };
hid_write(dev, buffer, CM_MM711_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM711_PACKET_SIZE, CM_MM711_INTERRUPT_TIMEOUT);
current_brightness = buffer[CM_MM711_BRIGHTNESS_BYTE - 1];
current_red = buffer[CM_MM711_RED_BYTE - 1];
current_green = buffer[CM_MM711_GREEN_BYTE - 1];
current_blue = buffer[CM_MM711_BLUE_BYTE - 1];
}
void CMMM711Controller::GetCustomStatus()
{
uint8_t buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x52, 0xA8 };
int read_size = CM_MM711_PACKET_SIZE - 1;
int result = 0;
hid_write(dev, buffer, CM_MM711_PACKET_SIZE);
do
{
result = hid_read_timeout(dev, buffer, read_size, CM_MM711_INTERRUPT_TIMEOUT);
}while(buffer[1] != 0xA8 && result == read_size);
if(result == read_size)
{
wheel_colour = ToRGBColor(buffer[4], buffer[5], buffer[6]);
logo_colour = ToRGBColor(buffer[7], buffer[8], buffer[9]);
}
}
void CMMM711Controller::GetModeStatus()
{
uint8_t buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x52, 0x28 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_MM711_INTERRUPT_TIMEOUT);
current_mode = buffer[CM_MM711_MODE_BYTE - 1];
}
std::string CMMM711Controller::GetDeviceName()
{
return(device_name);
}
std::string CMMM711Controller::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_serial_number_string(dev, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string CMMM711Controller::GetLocation()
{
return("HID: " + location);
}
unsigned char CMMM711Controller::GetMode()
{
return(current_mode);
}
unsigned char CMMM711Controller::GetLedRed()
{
return(current_red);
}
unsigned char CMMM711Controller::GetLedGreen()
{
return(current_green);
}
unsigned char CMMM711Controller::GetLedBlue()
{
return(current_blue);
}
unsigned char CMMM711Controller::GetLedSpeed()
{
return(current_speed);
}
RGBColor CMMM711Controller::GetWheelColour()
{
return(wheel_colour);
}
RGBColor CMMM711Controller::GetLogoColour()
{
return(logo_colour);
}
void CMMM711Controller::SetLedsDirect(RGBColor wheel_colour, RGBColor logo_colour)
{
unsigned char buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x51, 0xA8, 0x00, 0x00 };
buffer[CM_MM711_MODE_BYTE] = RGBGetRValue(wheel_colour);
buffer[CM_MM711_SPEED_BYTE] = RGBGetGValue(wheel_colour);
buffer[CM_MM711_NFI_1] = RGBGetBValue(wheel_colour);
buffer[CM_MM711_NFI_2] = RGBGetRValue(logo_colour);
buffer[CM_MM711_NFI_3] = RGBGetGValue(logo_colour);
buffer[CM_MM711_BRIGHTNESS_BYTE] = RGBGetBValue(logo_colour);
hid_write(dev, buffer, CM_MM711_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM711_PACKET_SIZE, CM_MM711_INTERRUPT_TIMEOUT);
//SendApplyPacket(0xB0); //Apply custom mode
}
void CMMM711Controller::SendUpdate(uint8_t mode, uint8_t speed, RGBColor colour, uint8_t brightness)
{
unsigned char buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x51, 0x2B, 0x00, 0x00 };
buffer[CM_MM711_MODE_BYTE] = mode;
buffer[CM_MM711_SPEED_BYTE] = speed;
buffer[CM_MM711_NFI_1] = 0x20;
buffer[CM_MM711_NFI_2] = 0xFF;
buffer[CM_MM711_NFI_3] = 0xFF;
buffer[CM_MM711_BRIGHTNESS_BYTE] = brightness;
buffer[CM_MM711_RED_BYTE] = RGBGetRValue(colour);
buffer[CM_MM711_GREEN_BYTE] = RGBGetGValue(colour);
buffer[CM_MM711_BLUE_BYTE] = RGBGetBValue(colour);
hid_write(dev, buffer, CM_MM711_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM711_PACKET_SIZE, CM_MM711_INTERRUPT_TIMEOUT);
SendApplyPacket(mode);
}
void CMMM711Controller::SendInitPacket()
{
unsigned char buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x41, 0x80 };
hid_write(dev, buffer, CM_MM711_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM711_PACKET_SIZE, CM_MM711_INTERRUPT_TIMEOUT);
}
void CMMM711Controller::SendApplyPacket(uint8_t mode)
{
unsigned char buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x51, 0x28, 0x00, 0x00 };
buffer[CM_MM711_MODE_BYTE] = mode;
hid_write(dev, buffer, CM_MM711_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM711_PACKET_SIZE, CM_MM711_INTERRUPT_TIMEOUT);
}
void CMMM711Controller::SendSavePacket()
{
unsigned char buffer[CM_MM711_PACKET_SIZE] = { 0x00, 0x50, 0x55 };
hid_write(dev, buffer, CM_MM711_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM711_PACKET_SIZE, CM_MM711_INTERRUPT_TIMEOUT);
}
@@ -0,0 +1,103 @@
/*---------------------------------------------------------*\
| CMMM711Controller.h |
| |
| Driver for Cooler Master M711 mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <array>
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#define CM_MM711_PACKET_SIZE 65
#define CM_MM711_COLOUR_MODE_DATA_SIZE (sizeof(colour_mode_data[0]) / sizeof(colour_mode_data[0][0]))
#define CM_MM711_HEADER_DATA_SIZE (sizeof(argb_header_data) / sizeof(argb_headers) )
#define CM_MM711_INTERRUPT_TIMEOUT 250
#define CM_MM711_DEVICE_NAME_SIZE (sizeof(device_name) / sizeof(device_name[ 0 ]))
#define HID_MAX_STR 255
enum
{
CM_MM711_REPORT_BYTE = 1,
CM_MM711_COMMAND_BYTE = 2,
CM_MM711_FUNCTION_BYTE = 3,
CM_MM711_ZONE_BYTE = 4,
CM_MM711_MODE_BYTE = 5,
CM_MM711_SPEED_BYTE = 6,
CM_MM711_NFI_1 = 7,
CM_MM711_NFI_2 = 8,
CM_MM711_NFI_3 = 9,
CM_MM711_BRIGHTNESS_BYTE = 10,
CM_MM711_RED_BYTE = 11,
CM_MM711_GREEN_BYTE = 12,
CM_MM711_BLUE_BYTE = 13,
};
enum
{
CM_MM711_MODE_STATIC = 0, //Static Mode
CM_MM711_MODE_BREATHING = 1, //Breathing Mode
CM_MM711_MODE_SPECTRUM_CYCLE = 2, //Spectrum Cycle Mode
CM_MM711_MODE_INDICATOR = 4, //Indicator Mode
CM_MM711_MODE_CUSTOM = 176, //Custom LED Control
CM_MM711_MODE_OFF = 254 //Turn Off
};
enum
{
CM_MM711_SPEED_SLOWEST = 0x5F, // Slowest speed
CM_MM711_SPEED_NORMAL = 0x38, // Normal speed
CM_MM711_SPEED_FASTEST = 0x20, // Fastest speed
};
class CMMM711Controller
{
public:
CMMM711Controller(hid_device* dev_handle, char *_path);
~CMMM711Controller();
std::string GetDeviceName();
std::string GetSerial();
std::string GetLocation();
uint8_t GetZoneIndex();
uint8_t GetMode();
uint8_t GetLedRed();
uint8_t GetLedGreen();
uint8_t GetLedBlue();
uint8_t GetLedSpeed();
RGBColor GetWheelColour();
RGBColor GetLogoColour();
void SendUpdate(uint8_t mode, uint8_t speed, RGBColor colour, uint8_t brightness);
void SetLedsDirect(RGBColor wheel_colour, RGBColor logo_colour);
void SendSavePacket();
private:
std::string device_name;
std::string serial;
std::string location;
hid_device* dev;
uint8_t current_mode;
uint8_t current_speed;
uint8_t current_brightness;
uint8_t current_red;
uint8_t current_green;
uint8_t current_blue;
RGBColor wheel_colour;
RGBColor logo_colour;
void GetColourStatus();
void GetCustomStatus();
void GetModeStatus();
void SendInitPacket();
void SendApplyPacket(uint8_t mode);
};
@@ -0,0 +1,206 @@
/*---------------------------------------------------------*\
| RGBController_CMMM711Controller.cpp |
| |
| RGBController for Cooler Master M711 mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMMM711Controller.h"
#define applyBrightness(c, bright) ((RGBColor) ((RGBGetBValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT) << 16 | (RGBGetGValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT) << 8 | (RGBGetRValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT)))
/**------------------------------------------------------------------*\
@name Coolermaster Master Mouse
@category Mouse
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterMouse
@comment
\*-------------------------------------------------------------------*/
RGBController_CMMM711Controller::RGBController_CMMM711Controller(CMMM711Controller* controller_ptr)
{
controller = controller_ptr;
name = controller->GetDeviceName();
vendor = "Cooler Master";
type = DEVICE_TYPE_MOUSE;
description = controller->GetDeviceName();
serial = controller->GetSerial();
location = controller->GetLocation();
mode Custom;
Custom.name = "Direct";
Custom.value = CM_MM711_MODE_CUSTOM;
Custom.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Custom.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Custom.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Custom.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Custom.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Custom);
mode Static;
Static.name = "Static";
Static.value = CM_MM711_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Static.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Static.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Static.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Static.colors_min = 1;
Static.colors_max = 1;
Static.colors.resize(Static.colors_max);
Static.speed_min = CM_MM711_SPEED_SLOWEST;
Static.speed_max = CM_MM711_SPEED_FASTEST;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.speed = CM_MM711_SPEED_NORMAL;
modes.push_back(Static);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_MM711_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Breathing.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Breathing.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Breathing.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(Breathing.colors_max);
Breathing.speed_min = CM_MM711_SPEED_SLOWEST;
Breathing.speed_max = CM_MM711_SPEED_FASTEST;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.speed = CM_MM711_SPEED_NORMAL;
modes.push_back(Breathing);
mode Spectrum_Cycle;
Spectrum_Cycle.name = "Spectrum Cycle";
Spectrum_Cycle.value = CM_MM711_MODE_SPECTRUM_CYCLE;
Spectrum_Cycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Spectrum_Cycle.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Spectrum_Cycle.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM;
Spectrum_Cycle.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM;
Spectrum_Cycle.speed_min = CM_MM711_SPEED_SLOWEST;
Spectrum_Cycle.speed_max = CM_MM711_SPEED_FASTEST;
Spectrum_Cycle.color_mode = MODE_COLORS_NONE;
Spectrum_Cycle.speed = CM_MM711_SPEED_NORMAL;
modes.push_back(Spectrum_Cycle);
mode Indicator;
Indicator.name = "Indicator";
Indicator.value = CM_MM711_MODE_INDICATOR;
Indicator.flags = MODE_FLAG_MANUAL_SAVE;
Indicator.color_mode = MODE_COLORS_NONE;
modes.push_back(Indicator);
mode Off;
Off.name = "Turn Off";
Off.value = CM_MM711_MODE_OFF;
Off.flags = MODE_FLAG_MANUAL_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
Init_Controller(); //Only processed on first run
SetupZones();
uint8_t temp_mode = controller->GetMode();
for(int mode_index = 0; mode_index < (int)modes.size(); mode_index++)
{
if(modes[mode_index].value == temp_mode)
{
active_mode = mode_index;
break;
}
}
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC)
{
modes[active_mode].colors[0] = ToRGBColor(controller->GetLedRed(),controller->GetLedGreen(),controller->GetLedBlue());
}
colors[0] = controller->GetWheelColour();
colors[1] = controller->GetLogoColour();
}
RGBController_CMMM711Controller::~RGBController_CMMM711Controller()
{
delete controller;
}
void RGBController_CMMM711Controller::Init_Controller()
{
zone mouse_zone;
mouse_zone.name = name;
mouse_zone.type = ZONE_TYPE_LINEAR;
mouse_zone.leds_min = 2;
mouse_zone.leds_max = 2;
mouse_zone.leds_count = 2;
mouse_zone.matrix_map = NULL;
zones.push_back(mouse_zone);
led wheel_led;
wheel_led.name = "Scroll Wheel LED";
wheel_led.value = 0;
leds.push_back(wheel_led);
led logo_led;
logo_led.name = "Logo LED";
logo_led.value = 1;
leds.push_back(logo_led);
}
void RGBController_CMMM711Controller::SetupZones()
{
SetupColors();
}
void RGBController_CMMM711Controller::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_CMMM711Controller::DeviceUpdateLEDs()
{
RGBColor wheel = applyBrightness(colors[0], modes[active_mode].brightness);
RGBColor logo = applyBrightness(colors[1], modes[active_mode].brightness);
controller->SetLedsDirect( wheel, logo);
}
void RGBController_CMMM711Controller::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMM711Controller::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMM711Controller::DeviceUpdateMode()
{
RGBColor colour = 0;
if(modes[active_mode].value != CM_MM711_MODE_CUSTOM)
{
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC )
{
colour = modes[active_mode].colors[0];
}
controller->SendUpdate(modes[active_mode].value, modes[active_mode].speed, colour, modes[active_mode].brightness);
}
}
void RGBController_CMMM711Controller::DeviceSaveMode()
{
DeviceUpdateMode();
controller->SendSavePacket();
}
@@ -0,0 +1,42 @@
/*---------------------------------------------------------*\
| RGBController_CMMM711Controller.h |
| |
| RGBController for Cooler Master M711 mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <vector>
#include "RGBController.h"
#include "CMMM711Controller.h"
#define CM_MM_ARGB_BRIGHTNESS_MIN 0x00
#define CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT 0xFF
#define CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM 0x7F
class RGBController_CMMM711Controller : public RGBController
{
public:
RGBController_CMMM711Controller(CMMM711Controller* controller_ptr);
~RGBController_CMMM711Controller();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
void DeviceSaveMode();
private:
void Init_Controller();
int GetDeviceMode();
CMMM711Controller* controller;
};
@@ -0,0 +1,192 @@
/*---------------------------------------------------------*\
| CMMM712Controller.cpp |
| |
| Driver for Cooler Master MM712 mouse |
| Derived from CMMM711Controller.cpp |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Frans Meulenbroeks 08 Dec 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "CMMM712Controller.h"
#include "StringUtils.h"
#define CM_MM712_PACKET_SIZE 65
#define CM_MM712_INTERRUPT_TIMEOUT 250
#define HID_MAX_STR 255
enum
{
CM_MM712_MODE_BYTE = 4,
CM_MM712_BRIGHTNESS_BYTE = 6,
CM_MM712_SPEED_BYTE = 7,
CM_MM712_RED_BYTE = 8,
CM_MM712_GREEN_BYTE = 9,
CM_MM712_BLUE_BYTE = 10,
};
CMMM712Controller::CMMM712Controller(hid_device* dev_handle, char *_path)
{
dev = dev_handle;
location = _path;
/*---------------------------------------------------------*\
| Get device name from HID manufacturer and product strings |
\*---------------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
SendInitPacket();
GetModeStatus();
GetColorStatus(current_mode);
}
CMMM712Controller::~CMMM712Controller()
{
hid_close(dev);
}
void CMMM712Controller::SendBuffer(uint8_t *buffer, uint8_t buffer_size)
{
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_MM712_INTERRUPT_TIMEOUT);
}
void CMMM712Controller::GetColorStatus(uint8_t mode)
{
uint8_t buffer[CM_MM712_PACKET_SIZE] = { 0x00, 0x4C, 0x81, 0x03, mode };
SendBuffer(buffer, CM_MM712_PACKET_SIZE);
initial_color = ToRGBColor(buffer[CM_MM712_RED_BYTE - 2], buffer[CM_MM712_GREEN_BYTE - 2], buffer[CM_MM712_BLUE_BYTE - 2]);
}
void CMMM712Controller::GetModeStatus()
{
uint8_t buffer[CM_MM712_PACKET_SIZE] = { 0x00, 0x4C, 0x81, 0x07 };
SendBuffer(buffer, CM_MM712_PACKET_SIZE);
current_mode = buffer[CM_MM712_MODE_BYTE - 1];
SetMode(current_mode);
}
std::string CMMM712Controller::GetDeviceName()
{
return(device_name);
}
std::string CMMM712Controller::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_serial_number_string(dev, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string CMMM712Controller::GetLocation()
{
return("HID: " + location);
}
unsigned char CMMM712Controller::GetMode()
{
return(current_mode);
}
RGBColor CMMM712Controller::GetInitialLedColor()
{
return initial_color;
}
void CMMM712Controller::SetLedsDirect(RGBColor color)
{
unsigned char buffer[CM_MM712_PACKET_SIZE] =
{
0x00, 0x5A, 0x81, 0x03,
(unsigned char)RGBGetRValue(color),
(unsigned char)RGBGetGValue(color),
(unsigned char)RGBGetBValue(color)
};
if(current_mode!=CM_MM712_MODE_DIRECT)
{
SetDirectMode(true);
}
hid_write(dev, buffer, CM_MM712_PACKET_SIZE);
// SendBuffer(buffer, CM_MM712_PACKET_SIZE);
}
void CMMM712Controller::SendUpdate(uint8_t mode, uint8_t speed, RGBColor color, uint8_t brightness)
{
unsigned char buffer[CM_MM712_PACKET_SIZE] =
{
0x00, 0x4C, 0x81, 0x04, mode, 0xFF, brightness, speed,
(unsigned char)RGBGetRValue(color),
(unsigned char)RGBGetGValue(color),
(unsigned char)RGBGetBValue(color),
0xFF
};
if(current_mode==CM_MM712_MODE_DIRECT)
{
SetDirectMode(false);
SendInitPacket();
}
SendBuffer(buffer, CM_MM712_PACKET_SIZE);
SetMode(mode);
}
void CMMM712Controller::SendInitPacket()
{
unsigned char buffer[CM_MM712_PACKET_SIZE] = { 0x00, 0x44, 0x81, 0x02 };
SendBuffer(buffer, CM_MM712_PACKET_SIZE);
}
void CMMM712Controller::SetDirectMode(bool onoff)
{
unsigned char buffer[CM_MM712_PACKET_SIZE] = { 0x00, 0x5a, 0x81, (unsigned char)(0x01+onoff) };
hid_write(dev, buffer, CM_MM712_PACKET_SIZE);
}
void CMMM712Controller::SetMode(uint8_t mode)
{
unsigned char buffer[CM_MM712_PACKET_SIZE] = { 0x00, 0x4C, 0x81, 0x08, mode};
if(current_mode==CM_MM712_MODE_DIRECT)
{
SendInitPacket();
}
SendBuffer(buffer, CM_MM712_PACKET_SIZE);
current_mode = mode;
}
void CMMM712Controller::SetProfile(uint8_t profile)
{
unsigned char buffer[CM_MM712_PACKET_SIZE] = { 0x00, 0x44, 0x81, 0x01, profile};
SendBuffer(buffer, CM_MM712_PACKET_SIZE);
}
void CMMM712Controller::SaveStatus()
{
unsigned char buffer[CM_MM712_PACKET_SIZE] = { 0x54, 0x81, 1};
SendBuffer(buffer, CM_MM712_PACKET_SIZE);
}
@@ -0,0 +1,69 @@
/*---------------------------------------------------------*\
| CMMM712Controller.h |
| |
| Driver for Cooler Master MM712 mouse |
| Derived from CMMM711Controller.h |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Frans Meulenbroeks 08 Dec 2024 |
| |
| 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"
enum
{
CM_MM712_MODE_STATIC = 0, //Static Mode
CM_MM712_MODE_BREATHING = 1, //Breathing Mode
CM_MM712_MODE_SPECTRUM_CYCLE = 2, //Spectrum Cycle Mode
CM_MM712_MODE_OFF = 3, //Turn Off
CM_MM712_MODE_DIRECT = 4, //Direct LED Control
};
enum
{
CM_MM712_SPEED_SLOWEST = 0x0, //Slowest speed
CM_MM712_SPEED_NORMAL = 0x2, //Normal speed
CM_MM712_SPEED_FASTEST = 0x4, //Fastest speed
};
class CMMM712Controller
{
public:
CMMM712Controller(hid_device* dev_handle, char *_path);
~CMMM712Controller();
std::string GetDeviceName();
std::string GetSerial();
std::string GetLocation();
uint8_t GetMode();
RGBColor GetInitialLedColor();
void SendUpdate(uint8_t mode, uint8_t speed, RGBColor color, uint8_t brightness);
void SetMode(uint8_t mode);
void SetDirectMode(bool onoff);
void SetLedsDirect(RGBColor color);
void SaveStatus();
private:
std::string device_name;
std::string serial;
std::string location;
hid_device* dev;
uint8_t current_mode;
RGBColor initial_color;
void GetColorStatus(uint8_t mode);
void GetModeStatus();
void SendInitPacket();
void SetProfile(uint8_t profile);
void SendBuffer(uint8_t *buffer, uint8_t buffer_size);
};
@@ -0,0 +1,108 @@
Analysis of the MM712 protocol
By Frans Meulenbroeks
PID 0x2516, VID 0x0169
We must use interface 3
C = Command, R = Response
Init:
=====
C: 0x00 0x44 0x81 0x02
R: 0x45 0x81 0x02 0x02 0x01
First byte is second byte of command+1, 2nd and 3rd byte are the 3rd and 4th byte of the command
No idea what the last two bytes are.
This init command inits to normal state.
After that one can submit all normal commands. These give a response.
C: 0x00 0x5a 0x81 0x02
R: 0x5b 0x81 0x02
This init command inits to direct state.
After that one can submit all direct state commands. These give no response
Note that you can always change between the two states by giving the appropriate init command.
I have also seen
C: 0x00, 0x46, 0x81
0x46 is command code
R: 47 81 50 03 00 00 f2 9b 1e 00 64 02 00 00 00 ff 03 06 00 ...
No idea what the response data is
This also brought the device to type-4 state.
NORMAL COMMANDS
===============
Query stored colors:
====================
C: 0x00 0x4c 0x81 0x03 0
R: 0x4d 0x81 0x03 0x06 0xff 0x00 0xff 0xff 0x00
Brig Spee Red Gree Blue Speed is not really relevant
These are the settings for the static mode
C: 0x00 0x4c 0x81 0x03 1
R: 0x4d 0x81 0x03 0xff 0xff 0x04 0xff 0x00 0x00 0xff
Brig Spee Red Gree Blue
These are the settings for the breathing mode
C: 0x00 0x4c 0x81 0x03 2
R: 0x81 0x03 0x06 0x7f 0x02
Brig Spee
These are the settings for the cycling mode
C: 0x00 0x4c 0x81 0x03 3
R: 0x4d 0x81 0x03 0x06 0x00
This is the response for the off mode
Other/higher numbers also return this value
Detecting the mode:
===================
C: 0x00 0x4c 0x81 0x07
R: 0x4d 0x81 0x07 0x01
^ actual mode
Setting the mode:
=================
C: 0x00 0x4c 0x81 0x08 0x01
^ new mode 0=static,1=breathing,2=cycling,3 or higher=off
R: 0x4d 0x81 0x07 0x01
can't explain the 0x07; later calls returned 0x08 in this field
C: 0x00 0x4c 0x81 0x08 0x02
R: 0x4d 0x81 0x08 0x02
Setting the color:
==================
C: 0x00 0x4c 0x81 0x04 0x00 0xff 0xff 0x02 0x00 0xff 0x00
cmd mode ???? brig spee red gree blue Speed is only relevant for breathing and cyclic, color is not relevant for cyclic
This sets the color, speed and brightness for the specific mode.
Note that this does not imply a mode switch
The first 0xff byte does not seem to do anything. I've changed to a different number but saw no result
R: 0x47 0x81 0x50 0x03 0x00 0x00 0xf2 0x9b 0x1e 0x00 0x64 0x02 0x00 0x00 0x00 0xff 0x01 0xff 0x00 0x00
No idea what this means, Reply seems independent of color set
Saving values:
==============
C: 0x00 0x54 0x81 0x01
This saves the actual color for all modes and the mode itself to internal flash
R: 0x55 0x81 0x01 0x00
Change Profile
==============
C: 0x00 0x44 0x81 0x01 0x02
^ new profile must be in [0..4] otherwise this is a no-op
R: 0x45 0x81 0x01 0x02 0x01
^ it is unclear what this value is, values 0, 1 and 2 are observed
DIRECT COMMANDS
==============
C: 0x00 0x5a 0x81 0x01
Leave direct state (return to normal, note that a new init for normal is needed)
C: 0x00 0x5a 0x81 0x03 0xff 0x00 0x25
red gree blue This changes the color right away. No response is generated.
CoolerMaster MasterPlus software uses this to dynamically generate animations
Final notes:
It is possible to change the mode on the mouse (see mouse doc).
This also changes the value in flash
It is also possible to change the colors in mode 0 and 1 using the mouse.
8 different colors can be selected. I did not find a way to define these colors from software so I suspect these are hardcoded
@@ -0,0 +1,199 @@
/*---------------------------------------------------------*\
| RGBController_CMMM712Controller.cpp |
| |
| RGBController for Cooler Master MM712 mouse |
| Derived from RGBController_CMMM712Controller.cpp |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Frans Meulenbroeks 08 Dec 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMMM712Controller.h"
#define applyBrightness(c, bright) ((RGBColor) ((RGBGetBValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT) << 16 | (RGBGetGValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT) << 8 | (RGBGetRValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT)))
/**------------------------------------------------------------------*\
@name Coolermaster Master Mouse
@category Mouse
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterMouse
@comment
\*-------------------------------------------------------------------*/
RGBController_CMMM712Controller::RGBController_CMMM712Controller(CMMM712Controller* controller_ptr)
{
controller = controller_ptr;
name = controller->GetDeviceName();
vendor = "Cooler Master";
type = DEVICE_TYPE_MOUSE;
description = controller->GetDeviceName();
serial = controller->GetSerial();
location = controller->GetLocation();
mode Direct;
Direct.name = "Direct";
Direct.value = CM_MM712_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Direct.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Direct.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
mode Static;
Static.name = "Static";
Static.value = CM_MM712_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Static.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Static.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Static.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Static.colors_min = 1;
Static.colors_max = 1;
Static.colors.resize(Static.colors_max);
Static.speed_min = CM_MM712_SPEED_SLOWEST;
Static.speed_max = CM_MM712_SPEED_FASTEST;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.speed = CM_MM712_SPEED_NORMAL;
modes.push_back(Static);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_MM712_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Breathing.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Breathing.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Breathing.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(Breathing.colors_max);
Breathing.speed_min = CM_MM712_SPEED_SLOWEST;
Breathing.speed_max = CM_MM712_SPEED_FASTEST;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.speed = CM_MM712_SPEED_NORMAL;
modes.push_back(Breathing);
mode Spectrum_Cycle;
Spectrum_Cycle.name = "Spectrum Cycle";
Spectrum_Cycle.value = CM_MM712_MODE_SPECTRUM_CYCLE;
Spectrum_Cycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Spectrum_Cycle.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Spectrum_Cycle.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM;
Spectrum_Cycle.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM;
Spectrum_Cycle.speed_min = CM_MM712_SPEED_SLOWEST;
Spectrum_Cycle.speed_max = CM_MM712_SPEED_FASTEST;
Spectrum_Cycle.color_mode = MODE_COLORS_NONE;
Spectrum_Cycle.speed = CM_MM712_SPEED_NORMAL;
modes.push_back(Spectrum_Cycle);
mode Off;
Off.name = "Off";
Off.value = CM_MM712_MODE_OFF;
Off.flags = MODE_FLAG_MANUAL_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
Init_Controller(); //Only processed on first run
SetupZones();
uint8_t temp_mode = controller->GetMode();
for(int mode_index = 0; mode_index < (int)modes.size(); mode_index++)
{
if(modes[mode_index].value == temp_mode)
{
active_mode = mode_index;
break;
}
}
colors[0] = controller->GetInitialLedColor();
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC)
{
modes[active_mode].colors[0] = colors[0];
}
}
RGBController_CMMM712Controller::~RGBController_CMMM712Controller()
{
delete controller;
}
void RGBController_CMMM712Controller::Init_Controller()
{
zone mouse_zone;
mouse_zone.name = name;
mouse_zone.type = ZONE_TYPE_SINGLE;
mouse_zone.leds_min = 1;
mouse_zone.leds_max = 1;
mouse_zone.leds_count = 1;
mouse_zone.matrix_map = NULL;
zones.push_back(mouse_zone);
led logo_led;
logo_led.name = "Logo LED";
logo_led.value = 0;
leds.push_back(logo_led);
}
void RGBController_CMMM712Controller::SetupZones()
{
SetupColors();
}
void RGBController_CMMM712Controller::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_CMMM712Controller::DeviceUpdateLEDs()
{
modes[active_mode].brightness=255;
RGBColor logo = applyBrightness(colors[0], modes[active_mode].brightness);
controller->SetLedsDirect(logo);
}
void RGBController_CMMM712Controller::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMM712Controller::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMM712Controller::DeviceUpdateMode()
{
if(modes[active_mode].value==CM_MM712_MODE_DIRECT)
{
controller->SetDirectMode(true);
}
else
{
controller->SetDirectMode(false);
RGBColor colour = 0;
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC )
{
colour = modes[active_mode].colors[0];
}
controller->SendUpdate(modes[active_mode].value, modes[active_mode].speed, colour, modes[active_mode].brightness);
}
}
void RGBController_CMMM712Controller::DeviceSaveMode()
{
DeviceUpdateMode();
controller->SaveStatus();
}
@@ -0,0 +1,42 @@
/*---------------------------------------------------------*\
| RGBController_CMMM712Controller.h |
| |
| RGBController for Cooler Master M712 mouse |
| Derived from RGBController_CMMM712Controller.h |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Frans Meulenbroeks 08 Dec 2024 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CMMM712Controller.h"
#define CM_MM_ARGB_BRIGHTNESS_MIN 0x00
#define CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT 0xFF
#define CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM 0x7F
class RGBController_CMMM712Controller : public RGBController
{
public:
RGBController_CMMM712Controller(CMMM712Controller* controller_ptr);
~RGBController_CMMM712Controller();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
void DeviceSaveMode();
private:
void Init_Controller();
CMMM712Controller* controller;
};
@@ -0,0 +1,346 @@
/*---------------------------------------------------------*\
| CMMMController.cpp |
| |
| Driver for Cooler Master mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Dracrius 12 Mar 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "CMMMController.h"
#include "StringUtils.h"
CMMMController::CMMMController(hid_device* dev_handle, char *_path, uint16_t pid, std::string dev_name)
{
dev = dev_handle;
location = _path;
name = dev_name;
current_speed = CM_MM_SPEED_3;
product_id = pid;
if(product_id == CM_MM530_PID || product_id == CM_MM531_PID)
{
command_code = CM_MM5XX_COMMAND;
if(pid == CM_MM530_PID)
{
buttons_bytes[0] = CM_MM_MODE_BYTE;
buttons_bytes[1] = CM_MM_SPEED_BYTE;
buttons_bytes[2] = CM_MM_NFI_1;
wheel_bytes[0] = CM_MM_RED_BYTE;
wheel_bytes[1] = CM_MM_GREEN_BYTE;
wheel_bytes[2] = CM_MM_BLUE_BYTE;
}
else if(product_id == CM_MM531_PID) //Still Need Captures for Proper Mapping From a MM531 User
{
buttons_bytes[0] = CM_MM_MODE_BYTE;
buttons_bytes[1] = CM_MM_SPEED_BYTE;
buttons_bytes[2] = CM_MM_NFI_1;
wheel_bytes[0] = CM_MM_RED_BYTE;
wheel_bytes[1] = CM_MM_GREEN_BYTE;
wheel_bytes[2] = CM_MM_BLUE_BYTE;
}
}
else
{
command_code = CM_MM7XX_COMMAND;
buttons_bytes[0] = CM_MM_RED_BYTE;
buttons_bytes[1] = CM_MM_GREEN_BYTE;
buttons_bytes[2] = CM_MM_BLUE_BYTE;
wheel_bytes[0] = CM_MM_MODE_BYTE;
wheel_bytes[1] = CM_MM_SPEED_BYTE;
wheel_bytes[2] = CM_MM_NFI_1;
}
logo_bytes[0] = CM_MM_NFI_2;
logo_bytes[1] = CM_MM_NFI_3;
logo_bytes[2] = CM_MM_BRIGHTNESS_BYTE;
SendInitPacket();
GetColourStatus();
GetCustomStatus();
GetModeStatus();
}
CMMMController::~CMMMController()
{
hid_close(dev);
}
void CMMMController::GetColourStatus()
{
uint8_t buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x52, command_code };
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
current_brightness = buffer[CM_MM_BRIGHTNESS_BYTE - 1];
current_red = buffer[CM_MM_RED_BYTE - 1];
current_green = buffer[CM_MM_GREEN_BYTE - 1];
current_blue = buffer[CM_MM_BLUE_BYTE - 1];
}
void CMMMController::GetCustomStatus()
{
uint8_t buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x52, 0xA8 };
int read_size = CM_MM_PACKET_SIZE - 1;
int result = 0;
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
do
{
result = hid_read_timeout(dev, buffer, read_size, CM_MM_INTERRUPT_TIMEOUT);
}while(buffer[1] != 0xA8 && result == read_size);
if(result == read_size)
{
buttons_colour = ToRGBColor(buffer[4], buffer[5], buffer[6]);
logo_colour = ToRGBColor(buffer[7], buffer[8], buffer[9]);
wheel_colour = ToRGBColor(buffer[10], buffer[11], buffer[12]);
}
}
void CMMMController::GetModeStatus()
{
uint8_t buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x52, 0x28 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_MM_INTERRUPT_TIMEOUT);
current_mode = buffer[CM_MM_MODE_BYTE - 1];
}
std::string CMMMController::GetDeviceVendor()
{
wchar_t vendor_string[HID_MAX_STR];
int ret = hid_get_manufacturer_string(dev, vendor_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(vendor_string));
}
std::string CMMMController::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_indexed_string(dev, 2, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string CMMMController::GetLocation()
{
return("HID: " + location);
}
std::string CMMMController::GetName()
{
return(name);
}
uint16_t CMMMController::GetProductID()
{
return product_id;
}
unsigned char CMMMController::GetMode()
{
return current_mode;
}
unsigned char CMMMController::GetLedRed()
{
return current_red;
}
unsigned char CMMMController::GetLedGreen()
{
return current_green;
}
unsigned char CMMMController::GetLedBlue()
{
return current_blue;
}
unsigned char CMMMController::GetLedSpeed()
{
return current_speed;
}
RGBColor CMMMController::GetWheelColour()
{
return wheel_colour;
}
RGBColor CMMMController::GetButtonsColour()
{
return buttons_colour;
}
RGBColor CMMMController::GetLogoColour()
{
return logo_colour;
}
void CMMMController::SetLedsDirect(RGBColor wheel_colour, RGBColor buttons_colour, RGBColor logo_colour)
{
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x51, 0xA8, 0x00, 0x00 };
buffer[buttons_bytes[0]] = RGBGetRValue(buttons_colour);
buffer[buttons_bytes[1]] = RGBGetGValue(buttons_colour);
buffer[buttons_bytes[2]] = RGBGetBValue(buttons_colour);
buffer[logo_bytes[0]] = RGBGetRValue(logo_colour);
buffer[logo_bytes[1]] = RGBGetGValue(logo_colour);
buffer[logo_bytes[2]] = RGBGetBValue(logo_colour);
buffer[wheel_bytes[0]] = RGBGetRValue(wheel_colour);
buffer[wheel_bytes[1]] = RGBGetGValue(wheel_colour);
buffer[wheel_bytes[2]] = RGBGetBValue(wheel_colour);
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
void CMMMController::SendUpdate(uint8_t mode, uint8_t speed, RGBColor colour, uint8_t brightness)
{
if (mode == CM_MM_MODE_CUSTOM || mode == CM_MM_MODE_MULTILAYER)
{
SendUsingZonesPacket(mode);
}
else
{
SendInitPacket();
SendApplyPacket(mode);
}
uint8_t nfi_1 = 0x20;
if (mode == CM_MM_MODE_STATIC || mode == CM_MM_MODE_SPECTRUM_CYCLE)
{
nfi_1 = 0x00;
}
if (mode != CM_MM_MODE_OFF)
{
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x51, command_code, 0x00, 0x00 };
buffer[CM_MM_MODE_BYTE] = mode;
buffer[CM_MM_SPEED_BYTE] = speed;
buffer[CM_MM_NFI_1] = nfi_1;
buffer[CM_MM_NFI_2] = 0xFF;
buffer[CM_MM_NFI_3] = 0xFF;
buffer[CM_MM_BRIGHTNESS_BYTE] = brightness;
buffer[CM_MM_RED_BYTE] = RGBGetRValue(colour);
buffer[CM_MM_GREEN_BYTE] = RGBGetGValue(colour);
buffer[CM_MM_BLUE_BYTE] = RGBGetBValue(colour);
buffer[CM_MM_SKY_RED_BYTE] = 0x00;
buffer[CM_MM_SKY_GREEN_BYTE] = 0x00;
buffer[CM_MM_SKY_BLUE_BYTE] = 0x00;
for (int i = 17; i < CM_MM_PACKET_SIZE; i++)
{
buffer[i] = 0xFF;
}
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
if (mode == CM_MM_MODE_CUSTOM || mode == CM_MM_MODE_MULTILAYER)
{
SendApplyPacket(mode); //Post Apply for Zoned Modes
}
}
void CMMMController::SendUpdate(uint8_t mode, uint8_t speed, RGBColor mode_one, RGBColor mode_two, uint8_t brightness)
{
SendApplyPacket(mode);
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x51, command_code, 0x00, 0x00 };
buffer[CM_MM_MODE_BYTE] = mode;
buffer[CM_MM_SPEED_BYTE] = speed;
buffer[CM_MM_NFI_1] = 0x00;
buffer[CM_MM_NFI_2] = 0x21;
buffer[CM_MM_NFI_3] = 0xFF;
buffer[CM_MM_BRIGHTNESS_BYTE] = brightness;
buffer[CM_MM_RED_BYTE] = RGBGetRValue(mode_one);
buffer[CM_MM_GREEN_BYTE] = RGBGetGValue(mode_one);
buffer[CM_MM_BLUE_BYTE] = RGBGetBValue(mode_one);
buffer[CM_MM_SKY_RED_BYTE] = RGBGetRValue(mode_two);
buffer[CM_MM_SKY_GREEN_BYTE] = RGBGetGValue(mode_two);
buffer[CM_MM_SKY_BLUE_BYTE] = RGBGetBValue(mode_two);
for (int i = 17; i < CM_MM_PACKET_SIZE; i++)
{
buffer[i] = 0xFF;
}
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
void CMMMController::SendInitPacket()
{
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x41, 0x80 };
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
void CMMMController::SendUsingZonesPacket(uint8_t mode)
{
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x51, 0x30, 0x00, 0x00 };
if (mode == CM_MM_MODE_MULTILAYER)
{
buffer[CM_MM_MODE_BYTE] = 0x01;
}
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
void CMMMController::SendApplyPacket(uint8_t mode)
{
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x51, 0x28, 0x00, 0x00 };
buffer[CM_MM_MODE_BYTE] = mode;
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
void CMMMController::SendMultilayerPacket(uint8_t zones[3])
{
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x51, 0xA0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00 };
buffer[CM_MM_NFI_3] = zones[0];
buffer[CM_MM_BRIGHTNESS_BYTE] = zones[1];
buffer[CM_MM_RED_BYTE] = zones[2];
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
void CMMMController::SendSavePacket()
{
unsigned char buffer[CM_MM_PACKET_SIZE] = { 0x00, 0x50, 0x55 };
hid_write(dev, buffer, CM_MM_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_MM_PACKET_SIZE, CM_MM_INTERRUPT_TIMEOUT);
}
@@ -0,0 +1,149 @@
/*---------------------------------------------------------*\
| CMMMController.h |
| |
| Driver for Cooler Master mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Dracrius 12 Mar 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <array>
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#define CM_MM_PACKET_SIZE 65
#define CM_MM_COLOUR_MODE_DATA_SIZE (sizeof(colour_mode_data[0]) / sizeof(colour_mode_data[0][0]))
#define CM_MM_HEADER_DATA_SIZE (sizeof(argb_header_data) / sizeof(argb_headers) )
#define CM_MM_INTERRUPT_TIMEOUT 250
#define CM_MM_DEVICE_NAME_SIZE (sizeof(device_name) / sizeof(device_name[ 0 ]))
#define HID_MAX_STR 255
enum
{
CM_MM530_PID = 0x0065,
CM_MM531_PID = 0x0097,
CM_MM711_PID = 0x0101,
CM_MM720_PID = 0x0141,
CM_MM730_PID = 0x0165,
};
enum
{
CM_MM_REPORT_BYTE = 1,
CM_MM_COMMAND_BYTE = 2,
CM_MM_FUNCTION_BYTE = 3,
CM_MM_ZONE_BYTE = 4,
CM_MM_MODE_BYTE = 5,
CM_MM_SPEED_BYTE = 6,
CM_MM_NFI_1 = 7,
CM_MM_NFI_2 = 8,
CM_MM_NFI_3 = 9,
CM_MM_BRIGHTNESS_BYTE = 10,
CM_MM_RED_BYTE = 11,
CM_MM_GREEN_BYTE = 12,
CM_MM_BLUE_BYTE = 13,
CM_MM_SKY_RED_BYTE = 14,
CM_MM_SKY_GREEN_BYTE = 15,
CM_MM_SKY_BLUE_BYTE = 16
};
enum
{
CM_MM5XX_COMMAND = 0x2C,
CM_MM7XX_COMMAND = 0x2B
};
enum
{
CM_MM_CUSTOM_APPLY = 0x30, //Also Used for Multilayer Mode
CM_MM_APPLY = 0x28 //Sent Before Update, Unless using a Zoned Mode then UsingZones Before and Apply After
};
enum
{
CM_MM_MODE_STATIC = 0, //Static Mode
CM_MM_MODE_BREATHING = 1, //Breathing Mode
CM_MM_MODE_SPECTRUM_CYCLE = 2, //Spectrum Cycle Mode
CM_MM_MODE_STARS = 3, //Stars Mode
CM_MM_MODE_INDICATOR = 4, //Indicator Mode
CM_MM_MODE_CUSTOM = 176, //Custom LED Control
CM_MM_MODE_MULTILAYER = 224, //Multilayer Mode, i.e. Effect per Zone.
CM_MM_MODE_OFF = 254 //Turn Off
};
enum
{
CM_MM_SPEED_1 = 0x3C, // Slowest speed
CM_MM_SPEED_2 = 0x37,
CM_MM_SPEED_3 = 0x31, // Normal speed
CM_MM_SPEED_4 = 0x2C,
CM_MM_SPEED_5 = 0x26 // Fastest speed
};
class CMMMController
{
public:
CMMMController(hid_device* dev_handle, char *_path, uint16_t pid, std::string dev_name);
~CMMMController();
std::string GetDeviceVendor();
std::string GetSerial();
std::string GetLocation();
std::string GetName();
uint16_t GetProductID();
uint8_t GetZoneIndex();
uint8_t GetMode();
uint8_t GetLedRed();
uint8_t GetLedGreen();
uint8_t GetLedBlue();
uint8_t GetLedSpeed();
RGBColor GetWheelColour();
RGBColor GetButtonsColour();
RGBColor GetLogoColour();
void SendUpdate(uint8_t mode, uint8_t speed, RGBColor colour, uint8_t brightness);
void SendUpdate(uint8_t mode, uint8_t speed, RGBColor mode_one, RGBColor mode_two, uint8_t brightness);
void SetLedsDirect(RGBColor wheel_colour, RGBColor buttons_colour, RGBColor logo_colour);
void SendSavePacket();
private:
std::string name;
std::string location;
hid_device* dev;
uint16_t product_id;
uint8_t command_code;
uint8_t current_mode;
uint8_t current_speed;
uint8_t current_brightness;
uint8_t current_red;
uint8_t current_green;
uint8_t current_blue;
uint8_t buttons_bytes[3];
uint8_t logo_bytes[3];
uint8_t wheel_bytes[3];
RGBColor buttons_colour;
RGBColor logo_colour;
RGBColor wheel_colour;
void GetColourStatus();
void GetCustomStatus();
void GetModeStatus();
void SendInitPacket();
void SendUsingZonesPacket(uint8_t mode);
void SendApplyPacket(uint8_t mode);
void SendMultilayerPacket(uint8_t zones[3]);
};
@@ -0,0 +1,285 @@
/*---------------------------------------------------------*\
| RGBController_CMMMController.cpp |
| |
| RGBController for Cooler Master mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Dracrius 12 Mar 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMMMController.h"
#define applyBrightness(c, bright) ((RGBColor) ((RGBGetBValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT) << 16 | (RGBGetGValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT) << 8 | (RGBGetRValue(c) * bright / CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT)))
/**------------------------------------------------------------------*\
@name Coolermaster Master Mouse
@category Mouse
@type USB
@save :white_check_mark:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterMouse
@comment
\*-------------------------------------------------------------------*/
RGBController_CMMMController::RGBController_CMMMController(CMMMController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetName();
vendor = controller->GetDeviceVendor();
type = DEVICE_TYPE_MOUSE;
description = "Cooler Master MasterMouse Device";
serial = controller->GetSerial();
location = controller->GetLocation();
mode Custom;
Custom.name = "Direct";
Custom.value = CM_MM_MODE_CUSTOM;
Custom.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Custom.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Custom.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Custom.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Custom.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Custom);
mode Static;
Static.name = "Static";
Static.value = CM_MM_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Static.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Static.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Static.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Static.colors_min = 1;
Static.colors_max = 1;
Static.colors.resize(Static.colors_max);
Static.speed_min = CM_MM_SPEED_1;
Static.speed_max = CM_MM_SPEED_5;
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.speed = CM_MM_SPEED_3;
modes.push_back(Static);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_MM_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Breathing.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Breathing.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Breathing.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(Breathing.colors_max);
Breathing.speed_min = CM_MM_SPEED_1;
Breathing.speed_max = CM_MM_SPEED_5;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.speed = CM_MM_SPEED_3;
modes.push_back(Breathing);
mode Spectrum_Cycle;
Spectrum_Cycle.name = "Spectrum Cycle";
Spectrum_Cycle.value = CM_MM_MODE_SPECTRUM_CYCLE;
Spectrum_Cycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Spectrum_Cycle.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Spectrum_Cycle.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM;
Spectrum_Cycle.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM;
Spectrum_Cycle.speed_min = CM_MM_SPEED_1;
Spectrum_Cycle.speed_max = CM_MM_SPEED_5;
Spectrum_Cycle.color_mode = MODE_COLORS_NONE;
Spectrum_Cycle.speed = CM_MM_SPEED_3;
modes.push_back(Spectrum_Cycle);
mode Stars;
Stars.name = "Stars";
Stars.value = CM_MM_MODE_STARS;
Stars.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
Stars.brightness_min = CM_MM_ARGB_BRIGHTNESS_MIN;
Stars.brightness_max = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Stars.brightness = CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT;
Stars.colors_min = 2;
Stars.colors_max = 2;
Stars.colors.resize(Stars.colors_max);
Stars.speed_min = CM_MM_SPEED_1;
Stars.speed_max = CM_MM_SPEED_5;
Stars.color_mode = MODE_COLORS_MODE_SPECIFIC;
Stars.speed = CM_MM_SPEED_3;
modes.push_back(Stars);
mode Indicator;
Indicator.name = "Indicator";
Indicator.value = CM_MM_MODE_INDICATOR;
Indicator.flags = MODE_FLAG_MANUAL_SAVE;
Indicator.color_mode = MODE_COLORS_NONE;
modes.push_back(Indicator);
mode Off;
Off.name = "Turn Off";
Off.value = CM_MM_MODE_OFF;
Off.flags = MODE_FLAG_MANUAL_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
uint16_t pid = controller->GetProductID();
if(pid == 0x0065 || pid == 0x0097)
{
leds_count = 3;
}
else
{
leds_count = 2;
}
Init_Controller(); //Only processed on first run
SetupZones();
uint8_t temp_mode = controller->GetMode();
for(int mode_index = 0; mode_index < (int)modes.size(); mode_index++)
{
if(modes[mode_index].value == temp_mode)
{
active_mode = mode_index;
break;
}
}
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC)
{
modes[active_mode].colors[0] = ToRGBColor(controller->GetLedRed(),controller->GetLedGreen(),controller->GetLedBlue());
}
if(pid == 0x0065 || pid == 0x0097)
{
colors[0] = controller->GetWheelColour();
colors[1] = controller->GetButtonsColour();
colors[2] = controller->GetLogoColour();
}
else
{
colors[0] = controller->GetWheelColour();
colors[1] = controller->GetLogoColour();
}
}
RGBController_CMMMController::~RGBController_CMMMController()
{
delete controller;
}
void RGBController_CMMMController::Init_Controller()
{
zone mouse_zone;
mouse_zone.name = name;
mouse_zone.type = ZONE_TYPE_LINEAR;
mouse_zone.leds_min = leds_count;
mouse_zone.leds_max = leds_count;
mouse_zone.leds_count = leds_count;
mouse_zone.matrix_map = NULL;
zones.push_back(mouse_zone);
int value = 0;
uint16_t pid = controller->GetProductID();
led wheel_led;
wheel_led.name = "Scroll Wheel";
wheel_led.value = value;
leds.push_back(wheel_led);
value++;
if(pid == 0x0065 || pid == 0x0097)
{
led buttons_led;
buttons_led.name = "Buttons";
buttons_led.value = value;
leds.push_back(buttons_led);
value++;
}
led logo_led;
logo_led.name = "Logo";
logo_led.value = value;
leds.push_back(logo_led);
}
void RGBController_CMMMController::SetupZones()
{
SetupColors();
}
void RGBController_CMMMController::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_CMMMController::DeviceUpdateLEDs()
{
int value = 0;
uint16_t pid = controller->GetProductID();
RGBColor wheel = applyBrightness(colors[value], modes[active_mode].brightness);
RGBColor buttons = ToRGBColor(0, 0, 0);
value++;
if(pid == 0x0065 || pid == 0x0097)
{
buttons = applyBrightness(colors[value], modes[active_mode].brightness);
value++;
}
RGBColor logo = applyBrightness(colors[value], modes[active_mode].brightness);
controller->SetLedsDirect(wheel, buttons, logo);
}
void RGBController_CMMMController::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMMController::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMMController::DeviceUpdateMode()
{
RGBColor mode_one = 0;
RGBColor mode_two = 0;
if(modes[active_mode].value != CM_MM_MODE_CUSTOM)
{
if(modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC )
{
mode_one = modes[active_mode].colors[0];
if(modes[active_mode].colors.size() > 1)
{
mode_two = modes[active_mode].colors[1];
}
}
}
if(modes[active_mode].value == CM_MM_MODE_STARS)
{
controller->SendUpdate(modes[active_mode].value, modes[active_mode].speed, mode_one, mode_two, modes[active_mode].brightness);
}
else
{
controller->SendUpdate(modes[active_mode].value, modes[active_mode].speed, mode_one, modes[active_mode].brightness);
}
}
void RGBController_CMMMController::DeviceSaveMode()
{
DeviceUpdateMode();
controller->SendSavePacket();
}
@@ -0,0 +1,46 @@
/*---------------------------------------------------------*\
| RGBController_CMMMController.h |
| |
| RGBController for Cooler Master mouse |
| |
| Chris M (Dr_No) 14 Feb 2021 |
| Dracrius 12 Mar 2022 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <vector>
#include "RGBController.h"
#include "CMMMController.h"
#define CM_MM_ARGB_BRIGHTNESS_MIN 0x00
#define CM_MM_ARGB_BRIGHTNESS_MAX_DEFAULT 0xFF
#define CM_MM_ARGB_BRIGHTNESS_MAX_SPECTRUM 0x7F
class RGBController_CMMMController : public RGBController
{
public:
RGBController_CMMMController(CMMMController* controller_ptr);
~RGBController_CMMMController();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
void DeviceSaveMode();
private:
void Init_Controller();
int GetDeviceMode();
int leds_count;
CMMMController* controller;
};
@@ -0,0 +1,176 @@
/*---------------------------------------------------------*\
| CMMP750Controller.cpp |
| |
| Driver for Cooler Master MP750 mousemat |
| |
| Chris M (Dr_No) 16 Apr 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "CMMP750Controller.h"
#include "StringUtils.h"
static unsigned char colour_mode_data[][6] =
{
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* Off */
{ 0x01, 0x04, 0xFF, 0x00, 0xFF, 0x00 }, /* Static */
{ 0x02, 0x04, 0xFF, 0x00, 0xFF, 0x80 }, /* Blinking */
{ 0x03, 0x04, 0xFF, 0x00, 0xFF, 0x80 }, /* Breathing */
{ 0x04, 0x04, 0x80, 0x00, 0x00, 0x00 }, /* Colour Cycle */
{ 0x05, 0x04, 0x80, 0x00, 0x00, 0x00 } /* Colour Breath */
};
static unsigned char speed_mode_data[9] =
{
0xFF, 0xE0, 0xC0, 0xA0, 0x80, 0x60, 0x40, 0x20, 0x00 /* Speed Definition */
};
CMMP750Controller::CMMP750Controller(hid_device* dev_handle, char *_path)
{
dev = dev_handle;
location = _path;
/*---------------------------------------------------------*\
| Get device name from HID manufacturer and product strings |
\*---------------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
GetStatus(); //When setting up device get current status
}
CMMP750Controller::~CMMP750Controller()
{
hid_close(dev);
}
void CMMP750Controller::GetStatus()
{
unsigned char buffer[0x41] = { 0x00 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
buffer[1] = 0x07;
hid_write(dev, buffer, buffer_size);
hid_read(dev, buffer, buffer_size);
if((buffer[0] == 0x80) && (buffer[1] == 0x05))
{
current_mode = buffer[2];
current_red = buffer[3];
current_green = buffer[4];
current_blue = buffer[5];
for(int i = 0; (speed_mode_data[i] >= buffer[6] && i <= MP750_SPEED_FASTEST); i++)
{
current_speed = i;
}
}
else
{
//Code should never reach here however just in case there is a failure set something
current_mode = CM_MP750_MODE_COLOR_CYCLE; //Unicorn Spew
current_red = 0xFF;
current_green = 0xFF;
current_blue = 0xFF;
current_speed = MP750_SPEED_NORMAL;
}
}
std::string CMMP750Controller::GetDeviceName()
{
return(device_name);
}
std::string CMMP750Controller::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_serial_number_string(dev, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string CMMP750Controller::GetLocation()
{
return("HID: " + location);
}
unsigned char CMMP750Controller::GetMode()
{
return(current_mode);
}
unsigned char CMMP750Controller::GetLedRed()
{
return(current_red);
}
unsigned char CMMP750Controller::GetLedGreen()
{
return(current_green);
}
unsigned char CMMP750Controller::GetLedBlue()
{
return(current_blue);
}
unsigned char CMMP750Controller::GetLedSpeed()
{
return(current_speed);
}
void CMMP750Controller::SetMode(unsigned char mode, unsigned char speed)
{
current_mode = mode;
current_speed = speed;
SendUpdate();
}
void CMMP750Controller::SetColor(unsigned char red, unsigned char green, unsigned char blue)
{
current_red = red;
current_green = green;
current_blue = blue;
SendUpdate();
}
void CMMP750Controller::SendUpdate()
{
unsigned char buffer[0x41] = { 0x00 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
for(std::size_t i = 0; i < CM_COLOUR_MODE_DATA_SIZE; i++)
{
buffer[i+1] = colour_mode_data[current_mode][i];
}
if(current_mode > CM_MP750_MODE_BREATHING)
{
//If the mode is random colours set SPEED at BYTE2
buffer[CM_RED_BYTE] = speed_mode_data[current_speed];
}
else
{
//Otherwise SPEED is BYTE5
buffer[CM_RED_BYTE] = current_red;
buffer[CM_GREEN_BYTE] = current_green;
buffer[CM_BLUE_BYTE] = current_blue;
buffer[CM_SPEED_BYTE] = speed_mode_data[current_speed];
}
hid_write(dev, buffer, buffer_size);
}
@@ -0,0 +1,99 @@
/*---------------------------------------------------------*\
| CMMP750Controller.h |
| |
| Driver for Cooler Master MP750 mousemat |
| |
| Chris M (Dr_No) 16 Apr 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <array>
#include <string>
#include <hidapi.h>
#define CM_COLOUR_MODE_DATA_SIZE (sizeof(colour_mode_data[0]) / sizeof(colour_mode_data[0][0]))
#define CM_INTERRUPT_TIMEOUT 250
#define CM_DEVICE_NAME_SIZE (sizeof(device_name) / sizeof(device_name[ 0 ]))
#define CM_SERIAL_SIZE (sizeof(serial) / sizeof(serial[ 0 ]))
#define HID_MAX_STR 255
/*-------------------------------------------------------------------*\
| Simple RGB device with 5 modes |
| BYTE0 = Mode (0x01 thru 0x05 |
| BYTE1 = ?? Must be set to 0x04 for colour modes otherwise ignored |
| BYTE2 = Colour Modes: RED else Cycle SPEED |
| BYTE3 = Colour Modes: GREEN else ignored |
| BYTE4 = Colour Modes: BLUE else ignored |
| BYTE5 = Colour Modes: SPEED else ignored |
\*-------------------------------------------------------------------*/
enum
{
CM_MODE_BYTE = 1,
CM_LENGTH_BYTE = 2,
CM_RED_BYTE = 3,
CM_GREEN_BYTE = 4,
CM_BLUE_BYTE = 5,
CM_SPEED_BYTE = 6
};
enum
{
CM_MP750_MODE_OFF = 0x00, //Off
CM_MP750_MODE_STATIC = 0x01, //Static Mode
CM_MP750_MODE_BLINK = 0x02, //Blinking Mode
CM_MP750_MODE_BREATHING = 0x03, //Breathing Mode
CM_MP750_MODE_COLOR_CYCLE = 0x04, //Color Cycle Mode
CM_MP750_MODE_BREATH_CYCLE = 0x05 //Breathing Cycle Mode
};
enum
{
MP750_SPEED_SLOWEST = 0x00, /* Slowest speed */
MP750_SPEED_SLOWER = 0x01, /* Slower speed */
MP750_SPEED_SLOW = 0x02, /* Slow speed */
MP750_SPEED_SLOWISH = 0x03, /* Slowish speed */
MP750_SPEED_NORMAL = 0x04, /* Normal speed */
MP750_SPEED_FASTISH = 0x05, /* Fastish speed */
MP750_SPEED_FAST = 0x06, /* Fast speed */
MP750_SPEED_FASTER = 0x07, /* Faster speed */
MP750_SPEED_FASTEST = 0x08, /* Fastest speed */
};
class CMMP750Controller
{
public:
CMMP750Controller(hid_device* dev_handle, char *_path);
~CMMP750Controller();
std::string GetDeviceName();
std::string GetSerial();
std::string GetLocation();
unsigned char GetMode();
unsigned char GetLedRed();
unsigned char GetLedGreen();
unsigned char GetLedBlue();
unsigned char GetLedSpeed();
void SetMode(unsigned char mode, unsigned char speed);
void SetColor(unsigned char red, unsigned char green, unsigned char blue);
private:
std::string device_name;
std::string location;
hid_device* dev;
unsigned char current_mode;
unsigned char current_speed;
unsigned char current_red;
unsigned char current_green;
unsigned char current_blue;
void GetStatus();
void SendUpdate();
};
@@ -0,0 +1,181 @@
/*---------------------------------------------------------*\
| RGBController_CMMP750Controller.cpp |
| |
| RGBController for Cooler Master MP750 mousemat |
| |
| Chris M (Dr_No) 18 Apr 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMMP750Controller.h"
/**------------------------------------------------------------------*\
@name Coolermaster Mouse Pad
@category Mousemat
@type USB
@save :robot:
@direct :x:
@effects :white_check_mark:
@detectors DetectCoolerMasterMousemats
@comment
\*-------------------------------------------------------------------*/
RGBController_CMMP750Controller::RGBController_CMMP750Controller(CMMP750Controller* controller_ptr)
{
controller = controller_ptr;
unsigned char speed = controller->GetLedSpeed();
name = controller->GetDeviceName();
vendor = "Cooler Master";
type = DEVICE_TYPE_MOUSEMAT;
description = controller->GetDeviceName();
serial = controller->GetSerial();
location = controller->GetLocation();
mode Static;
Static.name = "Static";
Static.value = CM_MP750_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Static.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Static);
mode Blink;
Blink.name = "Blink";
Blink.value = CM_MP750_MODE_BLINK;
Blink.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Blink.speed_min = MP750_SPEED_SLOWEST;
Blink.speed_max = MP750_SPEED_FASTEST;
Blink.color_mode = MODE_COLORS_PER_LED;
Blink.speed = speed;
modes.push_back(Blink);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_MP750_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR;
Breathing.speed_min = MP750_SPEED_SLOWEST;
Breathing.speed_max = MP750_SPEED_FASTEST;
Breathing.color_mode = MODE_COLORS_PER_LED;
Breathing.speed = speed;
modes.push_back(Breathing);
mode ColorCycle;
ColorCycle.name = "Color Cycle";
ColorCycle.value = CM_MP750_MODE_COLOR_CYCLE;
ColorCycle.flags = MODE_FLAG_HAS_SPEED;
ColorCycle.speed_min = MP750_SPEED_SLOWEST;
ColorCycle.speed_max = MP750_SPEED_FASTEST;
ColorCycle.color_mode = MODE_COLORS_NONE;
ColorCycle.speed = speed;
modes.push_back(ColorCycle);
mode BreathCycle;
BreathCycle.name = "Breath Cycle";
BreathCycle.value = CM_MP750_MODE_BREATH_CYCLE;
BreathCycle.flags = MODE_FLAG_HAS_SPEED;
BreathCycle.speed_min = MP750_SPEED_SLOWEST;
BreathCycle.speed_max = MP750_SPEED_FASTEST;
BreathCycle.color_mode = MODE_COLORS_NONE;
BreathCycle.speed = speed;
modes.push_back(BreathCycle);
mode Off;
Off.name = "Turn Off";
Off.value = CM_MP750_MODE_OFF;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
SetupZones();
active_mode = GetDeviceMode();
}
RGBController_CMMP750Controller::~RGBController_CMMP750Controller()
{
delete controller;
}
int RGBController_CMMP750Controller::GetDeviceMode()
{
int temp_mode = controller->GetMode();
for(unsigned int i = 0; i < modes.size(); i++)
{
if (temp_mode == modes[i].value)
{
return i;
}
}
/*---------------------------------------------------------*\
| If not found return 0 |
\*---------------------------------------------------------*/
return 0;
}
void RGBController_CMMP750Controller::SetupZones()
{
zone MP_zone;
MP_zone.name = "Mousepad";
MP_zone.type = ZONE_TYPE_SINGLE;
MP_zone.leds_min = 1;
MP_zone.leds_max = 1;
MP_zone.leds_count = 1;
MP_zone.matrix_map = NULL;
zones.push_back(MP_zone);
led MP_led;
MP_led.name = "Mousepad LED";
leds.push_back(MP_led);
SetupColors();
/*---------------------------------------------------------*\
| Initialize colors for each LED |
\*---------------------------------------------------------*/
for(std::size_t led_idx = 0; led_idx < leds.size(); led_idx++)
{
unsigned char red = controller->GetLedRed();
unsigned char grn = controller->GetLedGreen();
unsigned char blu = controller->GetLedBlue();
colors[led_idx] = ToRGBColor(red, grn, blu);
}
}
void RGBController_CMMP750Controller::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_CMMP750Controller::DeviceUpdateLEDs()
{
unsigned char red = RGBGetRValue(colors[0]);
unsigned char grn = RGBGetGValue(colors[0]);
unsigned char blu = RGBGetBValue(colors[0]);
controller->SetColor(red, grn, blu);
}
void RGBController_CMMP750Controller::UpdateZoneLEDs(int zone)
{
RGBColor color = colors[zone];
unsigned char red = RGBGetRValue(color);
unsigned char grn = RGBGetGValue(color);
unsigned char blu = RGBGetBValue(color);
controller->SetColor(red, grn, blu);
}
void RGBController_CMMP750Controller::UpdateSingleLED(int led)
{
UpdateZoneLEDs(led);
}
void RGBController_CMMP750Controller::DeviceUpdateMode()
{
controller->SetMode(modes[active_mode].value, modes[active_mode].speed);
}
@@ -0,0 +1,36 @@
/*---------------------------------------------------------*\
| RGBController_CMMP750Controller.h |
| |
| RGBController for Cooler Master MP750 mousemat |
| |
| Chris M (Dr_No) 18 Apr 2020 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CMMP750Controller.h"
class RGBController_CMMP750Controller : public RGBController
{
public:
RGBController_CMMP750Controller(CMMP750Controller* controller_ptr);
~RGBController_CMMP750Controller();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
CMMP750Controller* controller;
int GetDeviceMode();
};
@@ -0,0 +1,208 @@
/*---------------------------------------------------------*\
| CMMonitorController.cpp |
| |
| Driver for Cooler Master monitor |
| |
| Morgan Guimard (morg) 18 Sep 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "CMMonitorController.h"
#include "StringUtils.h"
using namespace std::chrono_literals;
CMMonitorController::CMMonitorController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name)
{
dev = dev_handle;
location = info.path;
name = dev_name;
}
CMMonitorController::~CMMonitorController()
{
hid_close(dev);
}
std::string CMMonitorController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string CMMonitorController::GetNameString()
{
return(name);
}
std::string CMMonitorController::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 CMMonitorController::SetMode(uint8_t mode_value, const RGBColor& color, uint8_t speed, uint8_t brightness)
{
if(software_mode_enabled)
{
SetSoftwareModeEnabled(false);
}
uint8_t usb_buf[CM_MONITOR_PACKET_LENGTH];
memset(usb_buf, 0x00, CM_MONITOR_PACKET_LENGTH);
usb_buf[1] = 0x80;
usb_buf[2] = (mode_value == CM_MONITOR_OFF_MODE) ? 0x0F : 0x0B;
usb_buf[3] = 0x02;
usb_buf[4] = 0x02;
usb_buf[5] = mode_value;
usb_buf[6] = (mode_value == CM_MONITOR_OFF_MODE) ? 0x00 : 0x08;
usb_buf[7] = speed;
usb_buf[8] = brightness;
usb_buf[9] = RGBGetRValue(color);
usb_buf[10] = RGBGetGValue(color);
usb_buf[11] = RGBGetBValue(color);
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
}
void CMMonitorController::SetCustomMode(const std::vector<RGBColor>& colors, uint8_t brightnesss)
{
if(software_mode_enabled)
{
SetSoftwareModeEnabled(false);
}
/*---------------------------------------------------------*\
| Creates the color buffer |
\*---------------------------------------------------------*/
uint8_t color_data[CM_MONITOR_COLOR_DATA_LENGTH];
memset(color_data, 0x00, CM_MONITOR_COLOR_DATA_LENGTH);
uint8_t offset = 0;
for(const RGBColor& color: colors)
{
color_data[offset++] = RGBGetRValue(color);
color_data[offset++] = RGBGetGValue(color);
color_data[offset++] = RGBGetBValue(color);
}
/*---------------------------------------------------------*\
| Sends the 7 sequence packets |
\*---------------------------------------------------------*/
uint8_t usb_buf[CM_MONITOR_PACKET_LENGTH];
offset = 0;
for(unsigned int i = 0; i < 7; i++)
{
memset(usb_buf, 0x00, CM_MONITOR_PACKET_LENGTH);
usb_buf[1] = i < 6 ? i : 0x86;
/*---------------------------------------------------------*\
| First packet contains static data |
\*---------------------------------------------------------*/
if(i == 0)
{
usb_buf[2] = 0x10;
usb_buf[3] = 0x02;
usb_buf[4] = 0x02;
usb_buf[5] = 0x80;
usb_buf[6] = brightnesss;
memcpy(&usb_buf[7], &color_data[offset], CM_MONITOR_PACKET_LENGTH - 7);
offset += CM_MONITOR_PACKET_LENGTH - 7;
}
else
{
memcpy(&usb_buf[2], &color_data[offset], CM_MONITOR_PACKET_LENGTH - 2);
offset += (CM_MONITOR_PACKET_LENGTH - 2);
}
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
}
}
void CMMonitorController::SendDirect(const std::vector<RGBColor>& colors)
{
if(!software_mode_enabled)
{
SetSoftwareModeEnabled(true);
}
/*---------------------------------------------------------*\
| Creates the color buffer |
\*---------------------------------------------------------*/
uint8_t color_data[CM_MONITOR_COLOR_DATA_LENGTH];
memset(color_data, 0x00, CM_MONITOR_COLOR_DATA_LENGTH);
unsigned int offset = 0;
for(const RGBColor& color: colors)
{
color_data[offset++] = RGBGetRValue(color);
color_data[offset++] = RGBGetGValue(color);
color_data[offset++] = RGBGetBValue(color);
}
/*---------------------------------------------------------*\
| Sends the 7 sequence packets |
\*---------------------------------------------------------*/
uint8_t usb_buf[CM_MONITOR_PACKET_LENGTH];
offset = 0;
for(unsigned int i = 0; i < 7; i++)
{
memset(usb_buf, 0x00, CM_MONITOR_PACKET_LENGTH);
usb_buf[1] = i < 6 ? i : 0x86;
if(i == 0)
{
usb_buf[2] = 0x07;
usb_buf[3] = 0x02;
usb_buf[4] = 0x02;
usb_buf[5] = 0x01;
usb_buf[6] = 0x80;
memcpy(&usb_buf[7], &color_data[offset], CM_MONITOR_PACKET_LENGTH - 7);
offset += CM_MONITOR_PACKET_LENGTH - 7;
}
else
{
memcpy(&usb_buf[2], &color_data[offset], CM_MONITOR_PACKET_LENGTH - 2);
offset += (CM_MONITOR_PACKET_LENGTH - 2);
}
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
}
}
void CMMonitorController::SetSoftwareModeEnabled(bool value)
{
uint8_t usb_buf[CM_MONITOR_PACKET_LENGTH];
memset(usb_buf, 0x00, CM_MONITOR_PACKET_LENGTH);
usb_buf[1] = 0x80;
usb_buf[2] = 0x07;
usb_buf[3] = 0x02;
usb_buf[4] = 0x02;
usb_buf[6] = value;
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
software_mode_enabled = value;
}
@@ -0,0 +1,61 @@
/*---------------------------------------------------------*\
| CMMonitorController.h |
| |
| Driver for Cooler Master monitor |
| |
| Morgan Guimard (morg) 18 Sep 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_MONITOR_PACKET_LENGTH 65
#define CM_MONITOR_COLOR_DATA_LENGTH 436
enum
{
CM_MONITOR_DIRECT_MODE = 0xFF,
CM_MONITOR_CUSTOM_MODE = 0xFE,
CM_MONITOR_SPECTRUM_MODE = 0x00,
CM_MONITOR_RELOAD_MODE = 0x01,
CM_MONITOR_RECOIL_MODE = 0x02,
CM_MONITOR_BREATHING_MODE = 0x03,
CM_MONITOR_REFILL_MODE = 0x04,
CM_MONITOR_OFF_MODE = 0x06
};
enum
{
CM_MONITOR_BRIGHTNESS_MAX = 0xFF,
CM_MONITOR_BRIGHTNESS_MIN = 0x00,
CM_MONITOR_SPEED_MAX = 0x04,
CM_MONITOR_SPEED_MIN = 0x00,
};
class CMMonitorController
{
public:
CMMonitorController(hid_device* dev_handle, const hid_device_info& info, std::string dev_name);
~CMMonitorController();
std::string GetDeviceLocation();
std::string GetNameString();
std::string GetSerialString();
void SendDirect(const std::vector<RGBColor>& colors);
void SetMode(uint8_t mode_value, const RGBColor& color, uint8_t speed, uint8_t brightness);
void SetCustomMode(const std::vector<RGBColor>& colors, uint8_t brightnesss);
private:
std::string location;
std::string name;
hid_device* dev;
bool software_mode_enabled = false;
void SetSoftwareModeEnabled(bool value);
};
@@ -0,0 +1,221 @@
/*---------------------------------------------------------*\
| RGBController_CMMonitorController.cpp |
| |
| RGBController for Cooler Master monitor |
| |
| Morgan Guimard (morg) 18 Sep 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <chrono>
#include <thread>
#include "RGBController_CMMonitorController.h"
/**------------------------------------------------------------------*\
@name Coolermaster Gaming Monitor
@category Accessory
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterMonitor
@comment
\*-------------------------------------------------------------------*/
RGBController_CMMonitorController::RGBController_CMMonitorController(CMMonitorController* controller_ptr)
{
controller = controller_ptr;
name = controller->GetNameString();
vendor = "CoolerMaster";
type = DEVICE_TYPE_MONITOR;
description = "CoolerMaster Monitor Device";
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
mode Direct;
Direct.name = "Direct";
Direct.value = CM_MONITOR_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 cycle";
Spectrum.value = CM_MONITOR_SPECTRUM_MODE;
Spectrum.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Spectrum.color_mode = MODE_COLORS_NONE;
Spectrum.speed_min = CM_MONITOR_SPEED_MIN;
Spectrum.speed_max = CM_MONITOR_SPEED_MAX;
Spectrum.speed = CM_MONITOR_SPEED_MAX/2;
Spectrum.brightness_min = CM_MONITOR_BRIGHTNESS_MIN;
Spectrum.brightness_max = CM_MONITOR_BRIGHTNESS_MAX;
Spectrum.brightness = CM_MONITOR_BRIGHTNESS_MAX;
modes.push_back(Spectrum);
mode Reload;
Reload.name = "Reload";
Reload.value = CM_MONITOR_RELOAD_MODE;
Reload.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Reload.color_mode = MODE_COLORS_MODE_SPECIFIC;
Reload.colors_min = 1;
Reload.colors_max = 1;
Reload.colors.resize(1);
Reload.speed_min = CM_MONITOR_SPEED_MIN;
Reload.speed_max = CM_MONITOR_SPEED_MAX;
Reload.speed = CM_MONITOR_SPEED_MAX/2;
Reload.brightness_min = CM_MONITOR_BRIGHTNESS_MIN;
Reload.brightness_max = CM_MONITOR_BRIGHTNESS_MAX;
Reload.brightness = CM_MONITOR_BRIGHTNESS_MAX;
modes.push_back(Reload);
mode Recoil;
Recoil.name = "Recoil";
Recoil.value = CM_MONITOR_RECOIL_MODE;
Recoil.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Recoil.color_mode = MODE_COLORS_MODE_SPECIFIC;
Recoil.colors_min = 1;
Recoil.colors_max = 1;
Recoil.colors.resize(1);
Recoil.speed_min = CM_MONITOR_SPEED_MIN;
Recoil.speed_max = CM_MONITOR_SPEED_MAX;
Recoil.speed = CM_MONITOR_SPEED_MAX/2;
Recoil.brightness_min = CM_MONITOR_BRIGHTNESS_MIN;
Recoil.brightness_max = CM_MONITOR_BRIGHTNESS_MAX;
Recoil.brightness = CM_MONITOR_BRIGHTNESS_MAX;
modes.push_back(Recoil);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_MONITOR_BREATHING_MODE;
Breathing.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(1);
Breathing.speed_min = CM_MONITOR_SPEED_MIN;
Breathing.speed_max = CM_MONITOR_SPEED_MAX;
Breathing.speed = CM_MONITOR_SPEED_MAX/2;
Breathing.brightness_min = CM_MONITOR_BRIGHTNESS_MIN;
Breathing.brightness_max = CM_MONITOR_BRIGHTNESS_MAX;
Breathing.brightness = CM_MONITOR_BRIGHTNESS_MAX;
modes.push_back(Breathing);
mode Refill;
Refill.name = "Refill";
Refill.value = CM_MONITOR_REFILL_MODE;
Refill.flags = MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Refill.color_mode = MODE_COLORS_MODE_SPECIFIC;
Refill.colors_min = 1;
Refill.colors_max = 1;
Refill.colors.resize(1);
Refill.speed_min = CM_MONITOR_SPEED_MIN;
Refill.speed_max = CM_MONITOR_SPEED_MAX;
Refill.speed = CM_MONITOR_SPEED_MAX/2;
Refill.brightness_min = CM_MONITOR_BRIGHTNESS_MIN;
Refill.brightness_max = CM_MONITOR_BRIGHTNESS_MAX;
Refill.brightness = CM_MONITOR_BRIGHTNESS_MAX;
modes.push_back(Refill);
mode Custom;
Custom.name = "Custom";
Custom.value = CM_MONITOR_CUSTOM_MODE;
Custom.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_AUTOMATIC_SAVE | MODE_FLAG_HAS_BRIGHTNESS;
Custom.color_mode = MODE_COLORS_PER_LED;
Custom.brightness_min = CM_MONITOR_BRIGHTNESS_MIN;
Custom.brightness_max = CM_MONITOR_BRIGHTNESS_MAX;
Custom.brightness = CM_MONITOR_BRIGHTNESS_MAX;
modes.push_back(Custom);
mode Off;
Off.name = "Off";
Off.value = CM_MONITOR_SPECTRUM_MODE;
Off.flags = MODE_FLAG_AUTOMATIC_SAVE;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
SetupZones();
}
RGBController_CMMonitorController::~RGBController_CMMonitorController()
{
delete controller;
}
void RGBController_CMMonitorController::SetupZones()
{
zone z;
z.name = "Monitor";
z.type = ZONE_TYPE_LINEAR;
z.leds_min = 47;
z.leds_max = 47;
z.leds_count = 47;
z.matrix_map = NULL;
zones.push_back(z);
for(unsigned int i = 0; i < 47; i++)
{
led l;
l.name = std::to_string(i + 1);
l.value = i;
leds.push_back(l);
}
SetupColors();
}
void RGBController_CMMonitorController::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_CMMonitorController::DeviceUpdateLEDs()
{
if(modes[active_mode].value == CM_MONITOR_DIRECT_MODE)
{
controller->SendDirect(colors);
}
else if(modes[active_mode].value == CM_MONITOR_CUSTOM_MODE)
{
controller->SetCustomMode(colors, modes[active_mode].brightness);
}
}
void RGBController_CMMonitorController::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMonitorController::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMMonitorController::DeviceUpdateMode()
{
switch(modes[active_mode].value)
{
case CM_MONITOR_OFF_MODE:
case CM_MONITOR_SPECTRUM_MODE:
controller->SetMode(modes[active_mode].value, 0, modes[active_mode].speed, modes[active_mode].brightness);
break;
case CM_MONITOR_RELOAD_MODE:
case CM_MONITOR_RECOIL_MODE:
case CM_MONITOR_BREATHING_MODE:
case CM_MONITOR_REFILL_MODE:
controller->SetMode(modes[active_mode].value, modes[active_mode].colors[0], modes[active_mode].speed, modes[active_mode].brightness);
break;
case CM_MONITOR_CUSTOM_MODE:
DeviceUpdateLEDs();
break;
default: break;
}
}
@@ -0,0 +1,35 @@
/*---------------------------------------------------------*\
| RGBController_CMMonitorController.h |
| |
| RGBController for Cooler Master monitor |
| |
| Morgan Guimard (morg) 18 Sep 2023 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CMMonitorController.h"
class RGBController_CMMonitorController : public RGBController
{
public:
RGBController_CMMonitorController(CMMonitorController* controller_ptr);
~RGBController_CMMonitorController();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
CMMonitorController* controller;
};
@@ -0,0 +1,214 @@
/*---------------------------------------------------------*\
| CMR6000Controller.cpp |
| |
| Driver for Cooler Master AMD Radeon 6000 series GPU |
| |
| Eric S (edbgon) 02 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "CMR6000Controller.h"
#include "StringUtils.h"
CMR6000Controller::CMR6000Controller(hid_device* dev_handle, char *_path, uint16_t _pid)
{
dev = dev_handle;
location = _path;
pid = _pid;
/*---------------------------------------------------------*\
| Get device name from HID manufacturer and product strings |
\*---------------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
}
CMR6000Controller::~CMR6000Controller()
{
if(dev)
{
hid_close(dev);
}
}
std::string CMR6000Controller::GetDeviceName()
{
return(device_name);
}
std::string CMR6000Controller::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_serial_number_string(dev, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string CMR6000Controller::GetLocation()
{
return("HID: " + location);
}
unsigned char CMR6000Controller::GetMode()
{
return(current_mode);
}
unsigned char CMR6000Controller::GetLedSpeed()
{
return(current_speed);
}
unsigned char CMR6000Controller::GetBrightness()
{
return(current_brightness);
}
bool CMR6000Controller::GetRandomColours()
{
return(current_random);
}
uint16_t CMR6000Controller::GetPID()
{
return(pid);
}
void CMR6000Controller::SetMode(unsigned char mode, unsigned char speed, RGBColor color1, RGBColor color2, unsigned char random, unsigned char brightness)
{
current_mode = mode;
current_speed = speed;
primary = color1;
secondary = color2;
current_random = random;
current_brightness = brightness;
SendUpdate();
}
void CMR6000Controller::SendUpdate()
{
if(current_mode == CM_MR6000_MODE_OFF)
{
unsigned char buffer[CM_6K_PACKET_SIZE] = { 0x00, 0x41, 0x43 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
hid_write(dev, buffer, buffer_size);
}
else
{
SendEnableCommand();
if(pid == COOLERMASTER_RADEON_6900_PID)
{
SendSecondColour();
}
unsigned char buffer[CM_6K_PACKET_SIZE] = { 0x00 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
memset(buffer, 0xFF, buffer_size);
buffer[0x00] = 0x00;
buffer[0x01] = 0x51;
buffer[0x02] = 0x2C;
buffer[0x03] = 0x01;
buffer[0x04] = 0x00;
buffer[0x05] = current_mode;
buffer[0x06] = current_speed;
buffer[0x07] = current_random; //random (A0)
//buffer[0x09] = 0xFF;
buffer[0x0A] = current_brightness;
buffer[0x0B] = (current_mode == CM_MR6000_MODE_COLOR_CYCLE) ? 0xFF : RGBGetRValue(primary);
buffer[0x0C] = (current_mode == CM_MR6000_MODE_COLOR_CYCLE) ? 0xFF : RGBGetGValue(primary);
buffer[0x0D] = (current_mode == CM_MR6000_MODE_COLOR_CYCLE) ? 0xFF : RGBGetBValue(primary);
buffer[0x0E] = 0x00;
buffer[0x0F] = 0x00;
buffer[0x10] = 0x00;
/*-----------------------------------------------------------------*\
| Index 0x08 looks to be mode specific flags / options |
\*-----------------------------------------------------------------*/
switch(current_mode)
{
case CM_MR6000_MODE_BREATHE:
buffer[0x08] = 0x03;
break;
case CM_MR6000_MODE_RAINBOW:
buffer[0x08] = 0x05;
break;
case CM_MR6000_MODE_CHASE:
buffer[0x08] = 0xC3;
break;
case CM_MR6000_MODE_SWIRL:
buffer[0x08] = 0x4A;
break;
default:
buffer[0x08] = 0xFF;
}
hid_write(dev, buffer, buffer_size);
SendColourConfig();
SendApplyCommand();
}
}
void CMR6000Controller::SendEnableCommand()
{
unsigned char buffer[CM_6K_PACKET_SIZE] = { 0x00, 0x41, 0x80 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_6K_INTERRUPT_TIMEOUT);
}
void CMR6000Controller::SendApplyCommand()
{
unsigned char buffer[CM_6K_PACKET_SIZE] = { 0x00, 0x51, 0x28, 0x00, 0x00, 0xE0 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_6K_INTERRUPT_TIMEOUT);
}
void CMR6000Controller::SendColourConfig()
{
unsigned char buffer[CM_6K_PACKET_SIZE] = { 0x00, 0x51, 0xA0, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x05, 0x06 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
for(int i = 0x0B; i < 0x1A; i++)
{
buffer[i] = current_mode;
}
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_6K_INTERRUPT_TIMEOUT);
}
void CMR6000Controller::SendSecondColour()
{
unsigned char buffer[CM_6K_PACKET_SIZE] = { 0x00, 0x51, 0x9C, 0x01, 0x00 };
buffer[5] = RGBGetRValue(primary);
buffer[6] = RGBGetGValue(primary);
buffer[7] = RGBGetBValue(primary);
buffer[8] = RGBGetRValue(secondary);
buffer[9] = RGBGetGValue(secondary);
buffer[10] = RGBGetBValue(secondary);
hid_write(dev, buffer, CM_6K_PACKET_SIZE);
hid_read_timeout(dev, buffer, CM_6K_PACKET_SIZE, CM_6K_INTERRUPT_TIMEOUT);
}
@@ -0,0 +1,98 @@
/*---------------------------------------------------------*\
| CMR6000Controller.h |
| |
| Driver for Cooler Master AMD Radeon 6000 series GPU |
| |
| Eric S (edbgon) 02 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <array>
#include <string>
#include <hidapi.h>
#include "RGBController.h"
#define COOLERMASTER_RADEON_6000_PID 0x014D
#define COOLERMASTER_RADEON_6900_PID 0x015B
#define CM_6K_PACKET_SIZE 65 //Includes extra first byte for non HID Report packets
#define CM_6K_INTERRUPT_TIMEOUT 250
#define CM_6K_DEVICE_NAME_SIZE (sizeof(device_name) / sizeof(device_name[ 0 ]))
#define CM_6K_SERIAL_SIZE (sizeof(serial) / sizeof(serial[ 0 ]))
#define HID_MAX_STR 255
enum
{
CM_MR6000_MODE_DIRECT = 0x00, //Direct Mode
CM_MR6000_MODE_BREATHE = 0x01, //Breathe Mode
CM_MR6000_MODE_COLOR_CYCLE = 0x02, //Color cycle
CM_MR6000_MODE_RAINBOW = 0x07, //Rainbow
CM_MR6000_MODE_BOUNCE = 0x08, //Bounce
CM_MR6000_MODE_CHASE = 0x09, //Chase
CM_MR6000_MODE_SWIRL = 0x0A, //Swirl
CM_MR6000_MODE_OFF = 0xFF, //Off
};
enum
{
MR6000_CYCLE_SPEED_SLOWEST = 0x96, /* Slowest speed */
MR6000_CYCLE_SPEED_SLOW = 0x8C, /* Slow speed */
MR6000_CYCLE_SPEED_NORMAL = 0x80, /* Normal speed */
MR6000_CYCLE_SPEED_FAST = 0x6E, /* Fast speed */
MR6000_CYCLE_SPEED_FASTEST = 0x68, /* Fastest speed */
MR6000_RAINBOW_SPEED_SLOWEST = 0x78, /* Slowest speed */
MR6000_RAINBOW_SPEED_NORMAL = 0x6B, /* Normal speed */
MR6000_RAINBOW_SPEED_FASTEST = 0x60, /* Fastest speed */
MR6000_BREATHE_SPEED_SLOWEST = 0x3C, /* Slowest speed */
MR6000_BREATHE_SPEED_SLOW = 0x37, /* Slow speed */
MR6000_BREATHE_SPEED_NORMAL = 0x31, /* Normal speed */
MR6000_BREATHE_SPEED_FAST = 0x2C, /* Fast speed */
MR6000_BREATHE_SPEED_FASTEST = 0x26, /* Fastest speed */
};
class CMR6000Controller
{
public:
CMR6000Controller(hid_device* dev_handle, char *_path, uint16_t _pid);
~CMR6000Controller();
std::string GetDeviceName();
std::string GetSerial();
std::string GetLocation();
unsigned char GetMode();
unsigned char GetLedSpeed();
unsigned char GetBrightness();
bool GetRandomColours();
uint16_t GetPID();
void SetMode(unsigned char mode, unsigned char speed, RGBColor color1, RGBColor color2, unsigned char random, unsigned char brightness);
private:
std::string device_name;
std::string location;
hid_device* dev;
uint16_t pid;
unsigned char current_mode;
unsigned char current_speed;
unsigned char current_random;
unsigned char current_brightness;
RGBColor primary;
RGBColor secondary;
void SendUpdate();
void SendEnableCommand();
void SendApplyCommand();
void SendColourConfig();
void SendSecondColour();
};
@@ -0,0 +1,228 @@
/*---------------------------------------------------------*\
| RGBController_CMR6000Controller.cpp |
| |
| RGBController for Cooler Master AMD Radeon 6000 series |
| GPU |
| |
| Eric S (edbgon) 02 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMR6000Controller.h"
/**------------------------------------------------------------------*\
@name AMD Radeon 6000
@category GPU
@type USB
@save :x:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterGPU
@comment Similar to the Wraith Spire before it the AMD branded Radeon
GPUs have an RGB controller provided by Coolermaster.
\*-------------------------------------------------------------------*/
RGBController_CMR6000Controller::RGBController_CMR6000Controller(CMR6000Controller* controller_ptr)
{
controller = controller_ptr;
name = "AMD RX 6xxx GPU";
vendor = "Cooler Master";
type = DEVICE_TYPE_GPU;
description = controller->GetDeviceName();
serial = controller->GetSerial();
location = controller->GetLocation();
mode Off;
Off.name = "Off";
Off.flags = 0;
Off.value = CM_MR6000_MODE_OFF;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
mode Direct;
Direct.name = "Direct";
Direct.value = CM_MR6000_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR| MODE_FLAG_HAS_BRIGHTNESS;
Direct.color_mode = MODE_COLORS_PER_LED;
Direct.speed = 0xFF;
Direct.brightness_min = 0x00;
Direct.brightness_max = 0xFF;
Direct.brightness = 0xFF;
modes.push_back(Direct);
mode ColorCycle;
ColorCycle.name = "Spectrum Cycle";
ColorCycle.value = CM_MR6000_MODE_COLOR_CYCLE;
ColorCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
ColorCycle.speed_min = MR6000_CYCLE_SPEED_SLOWEST;
ColorCycle.speed = MR6000_CYCLE_SPEED_NORMAL;
ColorCycle.speed_max = MR6000_CYCLE_SPEED_FASTEST;
ColorCycle.color_mode = MODE_COLORS_NONE;
ColorCycle.speed = MR6000_CYCLE_SPEED_NORMAL;
ColorCycle.brightness_min = 0x00;
ColorCycle.brightness_max = 0xFF;
ColorCycle.brightness = 0x7F;
modes.push_back(ColorCycle);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_MR6000_MODE_BREATHE;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR;
Breathing.speed_min = MR6000_BREATHE_SPEED_SLOWEST;
Breathing.speed = MR6000_BREATHE_SPEED_NORMAL;
Breathing.speed_max = MR6000_BREATHE_SPEED_FASTEST;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(1);
Breathing.speed = MR6000_BREATHE_SPEED_NORMAL;
modes.push_back(Breathing);
if(controller->GetPID() == COOLERMASTER_RADEON_6900_PID)
{
mode Rainbow;
Rainbow.name = "Rainbow Wave";
Rainbow.value = CM_MR6000_MODE_RAINBOW;
Rainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Rainbow.speed_min = MR6000_RAINBOW_SPEED_SLOWEST;
Rainbow.speed = MR6000_RAINBOW_SPEED_NORMAL;
Rainbow.speed_max = MR6000_RAINBOW_SPEED_FASTEST;
Rainbow.color_mode = MODE_COLORS_NONE;
Rainbow.speed = MR6000_RAINBOW_SPEED_NORMAL;
Rainbow.brightness_min = 0x00;
Rainbow.brightness_max = 0xFF;
Rainbow.brightness = 0xFF;
modes.push_back(Rainbow);
mode Bounce;
Bounce.name = "Bounce";
Bounce.value = CM_MR6000_MODE_BOUNCE;
Bounce.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Bounce.speed_min = MR6000_CYCLE_SPEED_SLOWEST;
Bounce.speed = MR6000_CYCLE_SPEED_NORMAL;
Bounce.speed_max = MR6000_CYCLE_SPEED_FASTEST;
Bounce.color_mode = MODE_COLORS_NONE;
Bounce.speed = MR6000_CYCLE_SPEED_NORMAL;
Bounce.brightness_min = 0x00;
Bounce.brightness_max = 0xFF;
Bounce.brightness = 0xFF;
modes.push_back(Bounce);
mode Chase;
Chase.name = "Chase";
Chase.value = CM_MR6000_MODE_CHASE;
Chase.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR;
Chase.speed_min = MR6000_CYCLE_SPEED_SLOWEST;
Chase.speed = MR6000_CYCLE_SPEED_NORMAL;
Chase.speed_max = MR6000_CYCLE_SPEED_FASTEST;
Chase.color_mode = MODE_COLORS_MODE_SPECIFIC;
Chase.colors_min = 2;
Chase.colors_max = 2;
Chase.colors.resize(2);
Chase.speed = MR6000_CYCLE_SPEED_NORMAL;
Chase.brightness_min = 0;
Chase.brightness_max = 0xFF;
Chase.brightness = 0xFF;
modes.push_back(Chase);
mode Swirl;
Swirl.name = "Swirl";
Swirl.value = CM_MR6000_MODE_SWIRL;
Swirl.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_DIRECTION_LR;
Swirl.speed_min = MR6000_CYCLE_SPEED_SLOWEST;
Swirl.speed = MR6000_CYCLE_SPEED_NORMAL;
Swirl.speed_max = MR6000_CYCLE_SPEED_FASTEST;
Swirl.color_mode = MODE_COLORS_MODE_SPECIFIC;
Swirl.colors_min = 1;
Swirl.colors_max = 1;
Swirl.colors.resize(1);
Swirl.speed = MR6000_CYCLE_SPEED_NORMAL;
Swirl.brightness_min = 0;
Swirl.brightness_max = 0xFF;
Swirl.brightness = 0xFF;
modes.push_back(Swirl);
}
SetupZones();
active_mode = 1;
}
RGBController_CMR6000Controller::~RGBController_CMR6000Controller()
{
delete controller;
}
void RGBController_CMR6000Controller::SetupZones()
{
zone GP_zone;
GP_zone.name = "GPU";
GP_zone.type = ZONE_TYPE_SINGLE;
GP_zone.leds_min = 1;
GP_zone.leds_max = 1;
GP_zone.leds_count = 1;
GP_zone.matrix_map = NULL;
zones.push_back(GP_zone);
led GP_led;
GP_led.name = "Logo";
GP_led.value = 0;
leds.push_back(GP_led);
SetupColors();
}
void RGBController_CMR6000Controller::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}
void RGBController_CMR6000Controller::DeviceUpdateLEDs()
{
mode new_mode = modes[active_mode];
RGBColor color1 = (new_mode.colors.size() > 0) ? new_mode.colors[0] : colors[0];
RGBColor color2 = (new_mode.colors.size() > 1) ? new_mode.colors[1] : 0;
unsigned char bri = (new_mode.flags & MODE_FLAG_HAS_BRIGHTNESS) ? new_mode.brightness : 0xFF;
unsigned char rnd = 0x20;
switch(new_mode.value)
{
/*-----------------------------------------------------------------*\
| Breathing mode requires value 0x20 when in MODE_SPECIFIC_COLOR |
\*-----------------------------------------------------------------*/
case CM_MR6000_MODE_BREATHE:
if(new_mode.color_mode == MODE_COLORS_RANDOM)
{
rnd = 0xA0;
}
break;
case CM_MR6000_MODE_SWIRL:
case CM_MR6000_MODE_CHASE:
rnd = new_mode.direction;
break;
default:
rnd = 0;
}
controller->SetMode(new_mode.value, new_mode.speed, color1, color2, rnd, bri);
}
void RGBController_CMR6000Controller::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMR6000Controller::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}
void RGBController_CMR6000Controller::DeviceUpdateMode()
{
DeviceUpdateLEDs();
}
@@ -0,0 +1,36 @@
/*---------------------------------------------------------*\
| RGBController_CMR6000Controller.h |
| |
| RGBController for Cooler Master AMD Radeon 6000 series |
| GPU |
| |
| Eric S (edbgon) 02 Feb 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CMR6000Controller.h"
class RGBController_CMR6000Controller : public RGBController
{
public:
RGBController_CMR6000Controller(CMR6000Controller* controller_ptr);
~RGBController_CMR6000Controller();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
CMR6000Controller* controller;
int GetDeviceMode();
};
@@ -0,0 +1,374 @@
/*---------------------------------------------------------*\
| CMRGBController.cpp |
| |
| Driver for Cooler Master RGB controller |
| |
| Nic W (midgetspy) 13 Apr 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "RGBController_CMRGBController.h"
#include "CMRGBController.h"
#include "StringUtils.h"
CMRGBController::CMRGBController(hid_device* dev_handle, char* path)
{
dev = dev_handle;
location = path;
/*---------------------------------------------------------*\
| Get device name from HID manufacturer and product strings |
\*---------------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
ReadCurrentMode();
}
void CMRGBController::SendFlowControl(unsigned char byte_flag)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { 0x00, CM_RGBC_OPCODE_OP_FLOW_CONTROL }; //Packets on Windows need a 0x00 if they don't use ReportIDs
buffer[0x02] = byte_flag;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendApply()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { 0x00, CM_RGBC_OPCODE_OP_UNKNOWN_50, CM_RGBC_OPCODE_TYPE_UNKNOWN_55 }; //Packets on Windows need a 0x00 if they don't use ReportIDs
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendReadMode()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_MODE;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
current_mode = buffer[CM_RGBC_PACKET_OFFSET_MODE];
}
void CMRGBController::SendSetMode(unsigned char mode)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_MODE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendSetCustomColors(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
current_port1_color = color_1;
current_port2_color = color_2;
current_port3_color = color_3;
current_port4_color = color_4;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_LED_INFO;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1] = RGBGetRValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 1] = RGBGetGValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 2] = RGBGetBValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2] = RGBGetRValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 1] = RGBGetGValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 2] = RGBGetBValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3] = RGBGetRValue(color_3);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 1] = RGBGetGValue(color_3);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 2] = RGBGetBValue(color_3);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4] = RGBGetRValue(color_4);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 1] = RGBGetGValue(color_4);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 2] = RGBGetBValue(color_4);
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendReadCustomColors()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_LED_INFO;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
current_port1_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 + 2]);
current_port2_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 + 2]);
current_port3_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 + 2]);
current_port4_color = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 1],
buffer[CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 + 2]);
}
void CMRGBController::SendSetConfig(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2, bool simplified=false, bool multilayer=false)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
current_mode = mode;
current_speed = speed;
current_brightness = brightness;
current_mode_color_1 = color_1;
current_mode_color_2 = color_2;
/*---------------------------------------------*\
| Handle special cases |
\*---------------------------------------------*/
switch(mode)
{
case CM_RGBC_MODE_COLOR_CYCLE:
brightness = 0xDF;
color_1 = 0xFFFFFF;
color_2 = 0x000000;
break;
case CM_RGBC_MODE_OFF:
brightness = 0x03;
break;
}
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = simplified ? CM_RGBC_OPCODE_TYPE_CONFIG_SIMPLIFIED : CM_RGBC_OPCODE_TYPE_CONFIG_FULL;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_SPEED] = speed;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_BRIGHTNESS] = brightness;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1] = RGBGetRValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1 + 1] = RGBGetGValue(color_1);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_1 + 2] = RGBGetBValue(color_1);
/*---------------------------------------------*\
| Magic values, meaning unknown |
\*---------------------------------------------*/
buffer[REPORT_ID_OFFSET + 0x06] = (mode == CM_RGBC_MODE_BREATHING) ? 0x20 : 0x00;
buffer[REPORT_ID_OFFSET + 0x07] = (mode == CM_RGBC_MODE_STAR) ? 0x19 : 0xFF;
buffer[REPORT_ID_OFFSET + 0x08] = 0xFF;
if(!simplified)
{
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MULTILAYER] = multilayer ? 0x01 : 0x00;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2] = RGBGetRValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2 + 1] = RGBGetGValue(color_2);
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_COLOR_2 + 2] = RGBGetBValue(color_2);
for(int i = REPORT_ID_OFFSET + 16; i < CM_RGBC_PACKET_SIZE; i++)
{
buffer[i] = 0xFF;
}
}
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::SendReadConfig(unsigned char mode)
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_READ;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_CONFIG_FULL;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_MODE] = mode;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
current_mode = mode;
current_speed = buffer[CM_RGBC_PACKET_OFFSET_SPEED];
current_brightness = buffer[CM_RGBC_PACKET_OFFSET_BRIGHTNESS];
current_mode_color_1 = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1 + 1],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_1 + 2]);
current_mode_color_2 = ToRGBColor(
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2 + 1],
buffer[CM_RGBC_PACKET_OFFSET_COLOR_2 + 2]);
}
void CMRGBController::SendCustomColorStart()
{
const unsigned char buffer_size = CM_RGBC_PACKET_SIZE;
unsigned char buffer[buffer_size] = { };
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_OP] = CM_RGBC_OPCODE_OP_WRITE;
buffer[REPORT_ID_OFFSET + CM_RGBC_PACKET_OFFSET_TYPE] = CM_RGBC_OPCODE_TYPE_UNKNOWN_30;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_RGBC_INTERRUPT_TIMEOUT);
}
void CMRGBController::ReadCurrentMode()
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_01);
SendReadMode();
}
void CMRGBController::ReadModeConfig(unsigned char mode)
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
SendReadConfig(mode);
if(mode == CM_RGBC_MODE_MULTIPLE)
{
SendReadCustomColors();
}
}
void CMRGBController::SetMode(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2)
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_01);
SendSetConfig(mode, speed, brightness, color_1, color_2, false);
SendSetMode(mode);
SendApply();
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
}
void CMRGBController::SetLedsDirect(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4)
{
SendFlowControl(CM_RGBC_OPCODE_FLOW_80);
SendCustomColorStart();
SendSetCustomColors(color_1, color_2, color_3, color_4);
SendSetMode(CM_RGBC_MODE_MULTIPLE);
SendCustomColorStart();
SendSetConfig(CM_RGBC_MODE_MULTIPLE, 0x00, 0xFF, color_1, 0x000000, false);
SendApply();
SendFlowControl(CM_RGBC_OPCODE_FLOW_00);
}
std::string CMRGBController::GetDeviceName()
{
return(device_name);
}
std::string CMRGBController::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_serial_number_string(dev, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string CMRGBController::GetLocation()
{
return("HID: " + location);
}
unsigned char CMRGBController::GetMode()
{
return(current_mode);
}
unsigned char CMRGBController::GetSpeed()
{
return(current_speed);
}
unsigned char CMRGBController::GetBrightness()
{
return(current_brightness);
}
RGBColor CMRGBController::GetModeColor(int color_number)
{
switch(color_number)
{
case 0:
return(current_mode_color_1);
case 1:
return(current_mode_color_2);
default:
return(ToRGBColor(0, 0, 0));
}
}
RGBColor CMRGBController::GetPortColor(int port_number)
{
switch(port_number)
{
case 0:
return(current_port1_color);
case 1:
return(current_port2_color);
case 2:
return(current_port3_color);
case 3:
return(current_port4_color);
default:
return(ToRGBColor(0, 0, 0));
}
}
CMRGBController::~CMRGBController()
{
if(dev)
{
hid_close(dev);
}
}
@@ -0,0 +1,152 @@
/*---------------------------------------------------------*\
| CMRGBController.h |
| |
| Driver for Cooler Master RGB controller |
| |
| Nic W (midgetspy) 13 Apr 2021 |
| |
| 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_RGBC_NUM_LEDS 4
#define REPORT_ID_OFFSET 1
#define CM_RGBC_PACKET_SIZE 64 + REPORT_ID_OFFSET //This needs to have one byte extra for the report ID thing
#define CM_RGBC_PACKET_OFFSET_OP 0x00
#define CM_RGBC_PACKET_OFFSET_TYPE 0x01
#define CM_RGBC_PACKET_OFFSET_MULTILAYER 0x02
#define CM_RGBC_PACKET_OFFSET_MODE 0x04
#define CM_RGBC_PACKET_OFFSET_SPEED 0x05
#define CM_RGBC_PACKET_OFFSET_BRIGHTNESS 0x09
#define CM_RGBC_PACKET_OFFSET_COLOR_1 0x0A
#define CM_RGBC_PACKET_OFFSET_COLOR_2 0x0D
#define CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_1 0x04
#define CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_2 0x07
#define CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_3 0x0A
#define CM_RGBC_PACKET_OFFSET_MULTIPLE_COLOR_4 0x0D
#define CM_RGBC_INTERRUPT_TIMEOUT 250
#define CM_RGBC_SPEED_NONE 0x05
#define CM_RGBC_BRIGHTNESS_OFF 0x03
#define HID_MAX_STR 255
/*-------------------------------------------------*\
| OP OPCODES |
\*-------------------------------------------------*/
enum
{
CM_RGBC_OPCODE_OP_FLOW_CONTROL = 0x41,
CM_RGBC_OPCODE_OP_UNKNOWN_50 = 0x50,
CM_RGBC_OPCODE_OP_WRITE = 0x51,
CM_RGBC_OPCODE_OP_READ = 0x52,
};
/*-------------------------------------------------*\
| CONTROL FLOW OPCODES |
\*-------------------------------------------------*/
enum
{
CM_RGBC_OPCODE_FLOW_00 = 0x00,
CM_RGBC_OPCODE_FLOW_01 = 0x01,
CM_RGBC_OPCODE_FLOW_80 = 0x80,
};
/*-------------------------------------------------*\
| OP TYPE OPCODES |
\*-------------------------------------------------*/
enum
{
CM_RGBC_OPCODE_TYPE_MODE = 0x28,
CM_RGBC_OPCODE_TYPE_CONFIG_SIMPLIFIED = 0x2B,
CM_RGBC_OPCODE_TYPE_CONFIG_FULL = 0x2C,
CM_RGBC_OPCODE_TYPE_UNKNOWN_30 = 0x30,
CM_RGBC_OPCODE_TYPE_UNKNOWN_55 = 0x55,
CM_RGBC_OPCODE_TYPE_LED_INFO = 0xA8,
};
/*-------------------------------------------------*\
| MODES |
\*-------------------------------------------------*/
enum
{
CM_RGBC_MODE_STATIC = 0x00,
CM_RGBC_MODE_BREATHING = 0x01,
CM_RGBC_MODE_COLOR_CYCLE = 0x02,
CM_RGBC_MODE_STAR = 0x03,
CM_RGBC_MODE_MULTIPLE = 0x04,
CM_RGBC_MODE_MULTILAYER = 0xE0,
CM_RGBC_MODE_OFF = 0xFE,
};
/*-------------------------------------------------*\
| SPEED |
\*-------------------------------------------------*/
enum
{
CM_RGBC_SPEED_BREATHING_SLOWEST = 0x3C,
CM_RGBC_SPEED_BREATHING_FASTEST = 0x26,
CM_RGBC_SPEED_COLOR_CYCLE_SLOWEST = 0x96,
CM_RGBC_SPEED_COLOR_CYCLE_FASTEST = 0x68,
CM_RGBC_SPEED_STAR_SLOWEST = 0x46,
CM_RGBC_SPEED_STAR_FASTEST = 0x32,
};
class CMRGBController
{
public:
CMRGBController(hid_device* dev_handle, char* path);
~CMRGBController();
std::string GetDeviceName();
std::string GetSerial();
std::string GetLocation();
unsigned char GetMode();
unsigned char GetSpeed();
unsigned char GetBrightness();
RGBColor GetModeColor(int color_number);
RGBColor GetPortColor(int port_number);
void SetMode(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2);
void SetLedsDirect(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4);
void ReadCurrentMode();
void ReadModeConfig(unsigned char mode);
private:
std::string device_name;
std::string location;
hid_device* dev;
unsigned char current_mode;
unsigned char current_speed;
unsigned char current_brightness;
RGBColor current_mode_color_1;
RGBColor current_mode_color_2;
RGBColor current_port1_color;
RGBColor current_port2_color;
RGBColor current_port3_color;
RGBColor current_port4_color;
void SendFlowControl(unsigned char byte_flag);
void SendApply();
void SendCustomColorStart();
void SendReadMode();
void SendSetMode(unsigned char mode);
void SendReadCustomColors();
void SendSetCustomColors(RGBColor color_1, RGBColor color_2, RGBColor color_3, RGBColor color_4);
void SendReadConfig(unsigned char mode);
void SendSetConfig(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor color_1, RGBColor color_2, bool simplified, bool multilayer);
};
@@ -0,0 +1,274 @@
/*---------------------------------------------------------*\
| RGBController_CMRGBController.cpp |
| |
| RGBController for Cooler Master RGB controller |
| |
| Nic W (midgetspy) 13 Apr 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMRGBController.h"
/*-----------------------------------------------------------------------------------------------------------------------------------------*\
| This controller has 4 ports, each for a 12v non-addressable LED item. |
| |
| It supports the following modes: |
| Static: All 4 ports a single color. Has brightness option. |
| Breathing: All ports a single color, fading in and out. Has brightness and speed option. |
| Star: Some weird effect using all 4 ports and a single color. Has brightness and speed option. |
| Color Cycle: All ports cycle through the rainbow in unison. Has brightness and speed option. |
| Off: All 4 ports off |
| |
| Plus some "special" modes: |
| Multilayer: Each of the 4 ports can have any of the modes above applied individually |
| Multiple Color/Customize: Each port can be set to its own static color |
| Mirage: A strobe effect that varies the LED pulse frequency which affects any of the above modes |
| |
| Note: |
| Multiple Color/Customize is equivalent to Multilayer + Static, but the device supports both separately |
| Static is equivalent to Multiple Color/Customize with the same color on each port, but the device supports both separately |
| |
| It can be controlled with 2 different pieces of software: MasterPlus+ or "RGB LED Controller". They appear to use different protocols. |
| |
| RGB LED Controller: |
| Sets changes temporarily and then applies them or cancels the changes separately |
| Supports all modes above |
| Has 3 brightness increments |
| Has two different colors for the Star effect (Star/Sky) |
| |
| MasterPlus+: |
| Sets changes permanently as soon as you change anything in the UI |
| Doesn't support Multilayer or Mirage |
| Has 5 brightness increments |
| Single color for Star |
\*-----------------------------------------------------------------------------------------------------------------------------------------*/
/**------------------------------------------------------------------*\
@name Coolermaster RGB
@category LEDStrip
@type USB
@save :robot:
@direct :x:
@effects :white_check_mark:
@detectors DetectCoolerMasterRGB
@comment This is a 12V analogue RGB controller only.
\*-------------------------------------------------------------------*/
RGBController_CMRGBController::RGBController_CMRGBController(CMRGBController* controller_ptr)
{
controller = controller_ptr;
name = "Cooler Master RGB Controller";
vendor = "Cooler Master";
type = DEVICE_TYPE_LEDSTRIP;
description = controller->GetDeviceName();
serial = controller->GetSerial();
location = controller->GetLocation();
mode Static;
Static.name = "Static";
Static.value = CM_RGBC_MODE_STATIC;
Static.flags = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Static.colors_min = 1;
Static.colors_max = 1;
Static.colors.resize(Static.colors_max);
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
Static.brightness_min = 0x00;
Static.brightness_max = 0xFF;
Static.brightness = 0xFF;
modes.push_back(Static);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_RGBC_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(Breathing.colors_max);
Breathing.speed_min = CM_RGBC_SPEED_BREATHING_SLOWEST;
Breathing.speed_max = CM_RGBC_SPEED_BREATHING_FASTEST;
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
Breathing.speed = CM_RGBC_SPEED_BREATHING_SLOWEST;
Breathing.brightness_min = 0x00;
Breathing.brightness_max = 0xFF;
Breathing.brightness = 0xFF;
modes.push_back(Breathing);
mode ColorCycle;
ColorCycle.name = "Spectrum Cycle";
ColorCycle.value = CM_RGBC_MODE_COLOR_CYCLE;
ColorCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_RANDOM_COLOR;
ColorCycle.speed_min = CM_RGBC_SPEED_COLOR_CYCLE_SLOWEST;
ColorCycle.speed_max = CM_RGBC_SPEED_COLOR_CYCLE_FASTEST;
ColorCycle.color_mode = MODE_COLORS_RANDOM;
ColorCycle.speed = CM_RGBC_SPEED_COLOR_CYCLE_SLOWEST;
ColorCycle.brightness_min = 0x00;
ColorCycle.brightness_max = 0xFF;
ColorCycle.brightness = 0xFF;
modes.push_back(ColorCycle);
mode Star;
Star.name = "Star";
Star.value = CM_RGBC_MODE_STAR;
Star.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR;
Star.colors_min = 2;
Star.colors_max = 2;
Star.colors.resize(Star.colors_max);
Star.speed_min = CM_RGBC_SPEED_STAR_SLOWEST;
Star.speed_max = CM_RGBC_SPEED_STAR_FASTEST;
Star.color_mode = MODE_COLORS_MODE_SPECIFIC;
Star.speed = CM_RGBC_SPEED_STAR_SLOWEST;
Star.brightness_min = 0x00;
Star.brightness_max = 0xFF;
Star.brightness = 0xFF;
modes.push_back(Star);
mode Multiple;
Multiple.name = "Custom";
Multiple.value = CM_RGBC_MODE_MULTIPLE;
Multiple.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Multiple.colors_min = 1;
Multiple.colors_max = 1;
Multiple.colors.resize(Multiple.colors_max);
Multiple.color_mode = MODE_COLORS_PER_LED;
Multiple.speed = 0;
Multiple.brightness_min = 0x00;
Multiple.brightness_max = 0xFF;
Multiple.brightness = 0xFF;
modes.push_back(Multiple);
mode Off;
Off.name = "Off";
Off.value = CM_RGBC_MODE_OFF;
Off.color_mode = MODE_COLORS_NONE;
Off.flags = 0;
modes.push_back(Off);
SetupZones();
ReadAllModeConfigsFromDevice();
}
RGBController_CMRGBController::~RGBController_CMRGBController()
{
delete controller;
}
void RGBController_CMRGBController::ReadAllModeConfigsFromDevice()
{
int device_mode = controller->GetMode();
for(int mode_idx = 0; mode_idx < (int)modes.size(); mode_idx++)
{
if(device_mode == modes[mode_idx].value)
{
active_mode = mode_idx;
continue;
}
if(!modes[mode_idx].flags)
{
continue;
}
controller->ReadModeConfig(modes[mode_idx].value);
LoadConfigFromDeviceController(mode_idx);
}
/*---------------------------------------------------------*\
| Do the active mode last so the device controller state |
| is left with the active mode's config |
\*---------------------------------------------------------*/
if(active_mode != -1)
{
controller->ReadModeConfig(modes[active_mode].value);
LoadConfigFromDeviceController(active_mode);
}
}
void RGBController_CMRGBController::LoadConfigFromDeviceController(int mode_idx)
{
for(int color_idx = 0; color_idx < (int)modes[mode_idx].colors.size(); color_idx++)
{
modes[mode_idx].colors[0] = controller->GetModeColor(color_idx);
}
if(modes[mode_idx].flags & MODE_FLAG_HAS_PER_LED_COLOR)
{
for(int led_idx = 0; led_idx < (int)leds.size(); led_idx++)
{
SetLED(led_idx, controller->GetPortColor(led_idx));
}
}
if(modes[mode_idx].flags & MODE_FLAG_HAS_SPEED)
{
modes[mode_idx].speed = controller->GetSpeed();
}
if(modes[mode_idx].flags & MODE_FLAG_HAS_BRIGHTNESS)
{
modes[active_mode].brightness = controller->GetBrightness();
}
}
void RGBController_CMRGBController::SetupZones()
{
leds.clear();
zones.clear();
colors.clear();
/*-----------------------------------------------------*\
| One zone, 4 leds. This might not actually work with |
| the Multilayer mode, but we'll deal with that later |
\*-----------------------------------------------------*/
zone* new_zone = new zone();
new_zone->name = "Controller";
new_zone->type = ZONE_TYPE_SINGLE;
new_zone->leds_min = 1;
new_zone->leds_max = 4;
new_zone->leds_count = 4;
new_zone->matrix_map = NULL;
for(int i = 1; i <= CM_RGBC_NUM_LEDS; i++)
{
led* new_led = new led();
new_led->name = "LED " + std::to_string(i);
leds.push_back(*new_led);
}
zones.push_back(*new_zone);
SetupColors();
}
void RGBController_CMRGBController::ResizeZone(int /*zone*/, int /*new_size*/)
{
}
void RGBController_CMRGBController::DeviceUpdateLEDs()
{
for(int zone_idx = 0; zone_idx < (int)zones.size(); zone_idx++)
{
UpdateZoneLEDs(zone_idx);
}
}
void RGBController_CMRGBController::UpdateZoneLEDs(int zone)
{
controller->SetLedsDirect(zones[zone].colors[0], zones[zone].colors[1], zones[zone].colors[2], zones[zone].colors[3]);
}
void RGBController_CMRGBController::UpdateSingleLED(int /*led*/)
{
}
void RGBController_CMRGBController::DeviceUpdateMode()
{
RGBColor color_1 = (modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC) ? modes[active_mode].colors[0] : 0;
RGBColor color_2 = (modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC && modes[active_mode].colors.size() > 1) ? modes[active_mode].colors[1] : 0;
controller->SetMode(modes[active_mode].value, modes[active_mode].speed, modes[active_mode].brightness, color_1, color_2);
}
@@ -0,0 +1,37 @@
/*---------------------------------------------------------*\
| RGBController_CMRGBController.h |
| |
| RGBController for Cooler Master RGB controller |
| |
| Nic W (midgetspy) 13 Apr 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <vector>
#include "RGBController.h"
#include "CMRGBController.h"
class RGBController_CMRGBController : public RGBController
{
public:
RGBController_CMRGBController(CMRGBController* controller_ptr);
~RGBController_CMRGBController();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void DeviceUpdateMode();
private:
CMRGBController* controller;
void LoadConfigFromDeviceController(int device_mode);
void ReadAllModeConfigsFromDevice();
};
@@ -0,0 +1,239 @@
/*---------------------------------------------------------*\
| CMSmallARGBController.cpp |
| |
| Driver for Cooler Master Small ARGB controller |
| |
| Chris M (Dr_No) 31 Jan 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include <cstring>
#include "CMSmallARGBController.h"
#include "StringUtils.h"
cm_small_argb_headers cm_small_argb_header_data[1] =
{
{ "CM Small ARGB", 0x01, true, 12 }
};
CMSmallARGBController::CMSmallARGBController(hid_device* dev_handle, char *_path, unsigned char _zone_idx)
{
dev = dev_handle;
location = _path;
zone_index = _zone_idx;
current_speed = CM_SMALL_ARGB_SPEED_NORMAL;
/*---------------------------------------------------------*\
| Get device name from HID manufacturer and product strings |
\*---------------------------------------------------------*/
wchar_t name_string[HID_MAX_STR];
hid_get_manufacturer_string(dev, name_string, HID_MAX_STR);
device_name = StringUtils::wstring_to_string(name_string);
hid_get_product_string(dev, name_string, HID_MAX_STR);
device_name.append(" ").append(StringUtils::wstring_to_string(name_string));
GetStatus();
}
CMSmallARGBController::~CMSmallARGBController()
{
if(dev)
{
hid_close(dev);
}
}
void CMSmallARGBController::GetStatus()
{
unsigned char buffer[CM_SMALL_ARGB_PACKET_SIZE] = { 0x00, 0x80, 0x01, 0x01 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
int header = zone_index - 1;
buffer[CM_SMALL_ARGB_ZONE_BYTE] = header;
buffer[CM_SMALL_ARGB_MODE_BYTE] = 0x01;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_SMALL_ARGB_INTERRUPT_TIMEOUT);
memset(buffer, 0x00, buffer_size );
buffer[CM_SMALL_ARGB_COMMAND_BYTE] = 0x0B;
buffer[CM_SMALL_ARGB_FUNCTION_BYTE] = 0x01;
buffer[CM_SMALL_ARGB_ZONE_BYTE] = 0x01;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_SMALL_ARGB_INTERRUPT_TIMEOUT);
current_mode = buffer[4];
current_speed = buffer[5];
bool_random = buffer[6] == 0x00;
current_brightness = buffer[7];
current_red = buffer[8];
current_green = buffer[9];
current_blue = buffer[10];
}
std::string CMSmallARGBController::GetDeviceName()
{
return(device_name);
}
std::string CMSmallARGBController::GetSerial()
{
wchar_t serial_string[HID_MAX_STR];
int ret = hid_get_serial_number_string(dev, serial_string, HID_MAX_STR);
if(ret != 0)
{
return("");
}
return(StringUtils::wstring_to_string(serial_string));
}
std::string CMSmallARGBController::GetLocation()
{
return("HID: " + location);
}
unsigned char CMSmallARGBController::GetZoneIndex()
{
return(zone_index);
}
unsigned char CMSmallARGBController::GetMode()
{
return(current_mode);
}
unsigned char CMSmallARGBController::GetLedRed()
{
return(current_red);
}
unsigned char CMSmallARGBController::GetLedGreen()
{
return(current_green);
}
unsigned char CMSmallARGBController::GetLedBlue()
{
return(current_blue);
}
unsigned char CMSmallARGBController::GetLedSpeed()
{
return(current_speed);
}
bool CMSmallARGBController::GetRandomColours()
{
return(bool_random);
}
void CMSmallARGBController::SetLedCount(int zone, int led_count)
{
unsigned char buffer[CM_SMALL_ARGB_PACKET_SIZE] = { 0x00, 0x80, 0x0D, 0x02 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
buffer[CM_SMALL_ARGB_ZONE_BYTE] = zone;
buffer[CM_SMALL_ARGB_MODE_BYTE] = (0x0F - led_count > 0) ? 0x0F - led_count : 0x01;
buffer[CM_SMALL_ARGB_SPEED_BYTE] = led_count;
hid_write(dev, buffer, buffer_size);
}
void CMSmallARGBController::SetMode(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor colour, bool random_colours)
{
current_mode = mode;
current_speed = speed;
current_brightness = brightness;
current_red = RGBGetRValue(colour);
current_green = RGBGetGValue(colour);
current_blue = RGBGetBValue(colour);
bool_random = random_colours;
SendUpdate();
}
void CMSmallARGBController::SetLedsDirect(RGBColor* led_colours, unsigned int led_count)
{
const unsigned char buffer_size = CM_SMALL_ARGB_PACKET_SIZE;
unsigned char buffer[buffer_size] = { 0x00, 0x00, 0x10, 0x02 };
unsigned char packet_count = 0;
std::vector<uint8_t> colours;
/*---------------------------------------------*\
| Set up the RGB triplets to send |
\*---------------------------------------------*/
for(unsigned int i = 0; i < led_count; i++)
{
RGBColor colour = led_colours[i];
colours.push_back( RGBGetRValue(colour) );
colours.push_back( RGBGetGValue(colour) );
colours.push_back( RGBGetBValue(colour) );
}
buffer[CM_SMALL_ARGB_ZONE_BYTE] = zone_index - 1; //argb_header_data[zone_index].header;
buffer[CM_SMALL_ARGB_MODE_BYTE] = led_count;
unsigned char buffer_idx = CM_SMALL_ARGB_MODE_BYTE + 1;
for(std::vector<unsigned char>::iterator it = colours.begin(); it != colours.end(); buffer_idx = CM_SMALL_ARGB_COMMAND_BYTE)
{
/*-----------------------------------------------------------------*\
| Fill the write buffer till its full or the colour buffer is empty |
\*-----------------------------------------------------------------*/
buffer[CM_SMALL_ARGB_REPORT_BYTE] = packet_count;
while (( buffer_idx < buffer_size) && ( it != colours.end() ))
{
buffer[buffer_idx] = *it;
buffer_idx++;
it++;
}
if(it == colours.end())
{
buffer[CM_SMALL_ARGB_REPORT_BYTE] += 0x80;
}
hid_write(dev, buffer, buffer_size);
/*-----------------------------------------------------------------*\
| Reset the write buffer |
\*-----------------------------------------------------------------*/
memset(buffer, 0x00, buffer_size );
packet_count++;
}
}
void CMSmallARGBController::SendUpdate()
{
unsigned char buffer[CM_SMALL_ARGB_PACKET_SIZE] = { 0x00 };
int buffer_size = (sizeof(buffer) / sizeof(buffer[0]));
bool boolPassthru = ( current_mode == CM_SMALL_ARGB_MODE_PASSTHRU );
bool boolDirect = ( current_mode == CM_SMALL_ARGB_MODE_DIRECT );
unsigned char function = boolPassthru ? 0x02 : 0x01;
buffer[CM_SMALL_ARGB_REPORT_BYTE] = 0x80;
buffer[CM_SMALL_ARGB_COMMAND_BYTE] = boolDirect ? 0x10 : 0x01;
buffer[CM_SMALL_ARGB_FUNCTION_BYTE] = boolDirect ? 0x01 : function;
buffer[CM_SMALL_ARGB_MODE_BYTE] = boolPassthru ? 0x00 : 0x02;
hid_write(dev, buffer, buffer_size);
buffer[CM_SMALL_ARGB_COMMAND_BYTE] = 0x0b;
buffer[CM_SMALL_ARGB_FUNCTION_BYTE] = (false) ? 0x01 : 0x02; //This controls custom mode TODO
buffer[CM_SMALL_ARGB_ZONE_BYTE] = cm_small_argb_header_data[zone_index].header;
buffer[CM_SMALL_ARGB_MODE_BYTE] = current_mode;
buffer[CM_SMALL_ARGB_SPEED_BYTE] = current_speed;
buffer[CM_SMALL_ARGB_COLOUR_INDEX_BYTE] = (bool_random) ? 0x00 : 0x10; //This looks to still be the colour index and controls random colours
buffer[CM_SMALL_ARGB_BRIGHTNESS_BYTE] = current_brightness;
buffer[CM_SMALL_ARGB_RED_BYTE] = current_red;
buffer[CM_SMALL_ARGB_GREEN_BYTE] = current_green;
buffer[CM_SMALL_ARGB_BLUE_BYTE] = current_blue;
hid_write(dev, buffer, buffer_size);
hid_read_timeout(dev, buffer, buffer_size, CM_SMALL_ARGB_INTERRUPT_TIMEOUT);
}
@@ -0,0 +1,114 @@
/*---------------------------------------------------------*\
| CMSmallARGBController.h |
| |
| Driver for Cooler Master Small ARGB controller |
| |
| Chris M (Dr_No) 31 Jan 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <array>
#include <string>
#include <hidapi.h>
#include "RGBController.h" //Needed to set the direct mode
/*---------------------------------------------------------*\
| Simple RGB device with 5 modes |
\*---------------------------------------------------------*/
#define CM_SMALL_ARGB_PACKET_SIZE 65
#define CM_SMALL_ARGB_INTERRUPT_TIMEOUT 250
#define HID_MAX_STR 255
enum
{
CM_SMALL_ARGB_REPORT_BYTE = 1,
CM_SMALL_ARGB_COMMAND_BYTE = 2,
CM_SMALL_ARGB_FUNCTION_BYTE = 3,
CM_SMALL_ARGB_ZONE_BYTE = 4,
CM_SMALL_ARGB_MODE_BYTE = 5,
CM_SMALL_ARGB_SPEED_BYTE = 6,
CM_SMALL_ARGB_COLOUR_INDEX_BYTE = 7, //Not used on the small controller
CM_SMALL_ARGB_BRIGHTNESS_BYTE = 8, //0x00 thru 0xFF
CM_SMALL_ARGB_RED_BYTE = 9,
CM_SMALL_ARGB_GREEN_BYTE = 10,
CM_SMALL_ARGB_BLUE_BYTE = 11,
};
struct cm_small_argb_headers
{
const char* name;
unsigned char header;
bool digital;
unsigned int count;
};
extern cm_small_argb_headers cm_small_argb_header_data[1];
enum
{
CM_SMALL_ARGB_MODE_SPECTRUM = 0x01, //Spectrum Mode
CM_SMALL_ARGB_MODE_RELOAD = 0x02, //Reload Mode
CM_SMALL_ARGB_MODE_RECOIL = 0x03, //Recoil Mode
CM_SMALL_ARGB_MODE_BREATHING = 0x04, //Breathing Mode
CM_SMALL_ARGB_MODE_REFILL = 0x05, //Refill Mode
CM_SMALL_ARGB_MODE_DEMO = 0x06, //Demo Mode
CM_SMALL_ARGB_MODE_OFF = 0x09, //Turn off
CM_SMALL_ARGB_MODE_DIRECT = 0xFE, //Direct Led Control (possibly N?A for small controller)
CM_SMALL_ARGB_MODE_PASSTHRU = 0xFF //Motherboard Pass Thru Mode
};
enum
{
CM_SMALL_ARGB_SPEED_SLOWEST = 0x00, // Slowest speed
CM_SMALL_ARGB_SPEED_SLOW = 0x01, // Slower speed
CM_SMALL_ARGB_SPEED_NORMAL = 0x02, // Normal speed
CM_SMALL_ARGB_SPEED_FAST = 0x03, // Fast speed
CM_SMALL_ARGB_SPEED_FASTEST = 0x04, // Fastest speed
};
class CMSmallARGBController
{
public:
CMSmallARGBController(hid_device* dev_handle, char *_path, unsigned char _zone_idx);
~CMSmallARGBController();
std::string GetDeviceName();
std::string GetSerial();
std::string GetLocation();
unsigned char GetZoneIndex();
unsigned char GetMode();
unsigned char GetLedRed();
unsigned char GetLedGreen();
unsigned char GetLedBlue();
unsigned char GetLedSpeed();
bool GetRandomColours();
void SetLedCount(int zone, int led_count);
void SetMode(unsigned char mode, unsigned char speed, unsigned char brightness, RGBColor colour, bool random_colours);
void SetLedsDirect(RGBColor * led_colours, unsigned int led_count);
private:
std::string device_name;
std::string location;
hid_device* dev;
unsigned char zone_index;
unsigned char current_mode;
unsigned char current_speed;
unsigned char current_red;
unsigned char current_green;
unsigned char current_blue;
unsigned char current_brightness;
bool bool_random;
unsigned int GetLargestColour(unsigned int red, unsigned int green, unsigned int blue);
unsigned char GetColourIndex(unsigned char red, unsigned char green, unsigned char blue);
void GetStatus();
void SendUpdate();
};
@@ -0,0 +1,305 @@
/*---------------------------------------------------------*\
| RGBController_CMSmallARGBController.cpp |
| |
| RGBController for Cooler Master Small ARGB controller |
| |
| Chris M (Dr_No) 31 Jan 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#include "RGBController_CMSmallARGBController.h"
/**------------------------------------------------------------------*\
@name Coolermaster Small ARGB
@category LEDStrip
@type USB
@save :robot:
@direct :white_check_mark:
@effects :white_check_mark:
@detectors DetectCoolerMasterSmallARGB
@comment The Coolermaster Small ARGB device supports `Direct` mode
from firmware 0012 onwards. Check the serial number for the date
"A202104052336" or newer.
\*-------------------------------------------------------------------*/
RGBController_CMSmallARGBController::RGBController_CMSmallARGBController(CMSmallARGBController* controller_ptr)
{
controller = controller_ptr;
unsigned char speed = controller->GetLedSpeed();
name = cm_small_argb_header_data[controller->GetZoneIndex()].name;
vendor = "Cooler Master";
type = DEVICE_TYPE_LEDSTRIP;
description = controller->GetDeviceName();
version = "2.0 for FW0012";
serial = controller->GetSerial();
location = controller->GetLocation();
if(serial >= CM_SMALL_ARGB_FW0012)
{
mode Direct;
Direct.name = "Direct";
Direct.value = CM_SMALL_ARGB_MODE_DIRECT;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Direct.brightness_min = 0;
Direct.brightness_max = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Direct.brightness = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);
}
mode Off;
Off.name = "Turn Off";
Off.value = CM_SMALL_ARGB_MODE_OFF;
Off.color_mode = MODE_COLORS_NONE;
modes.push_back(Off);
mode Reload;
Reload.name = "Reload";
Reload.value = CM_SMALL_ARGB_MODE_RELOAD;
Reload.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Reload.colors_min = 1;
Reload.colors_max = 1;
Reload.colors.resize(Reload.colors_max);
Reload.brightness_min = 0;
Reload.brightness_max = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Reload.brightness = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Reload.speed_min = CM_SMALL_ARGB_SPEED_SLOWEST;
Reload.speed_max = CM_SMALL_ARGB_SPEED_FASTEST;
Reload.color_mode = MODE_COLORS_RANDOM;
Reload.speed = speed;
modes.push_back(Reload);
mode Recoil;
Recoil.name = "Recoil";
Recoil.value = CM_SMALL_ARGB_MODE_RECOIL;
Recoil.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Recoil.colors_min = 1;
Recoil.colors_max = 1;
Recoil.colors.resize(Recoil.colors_max);
Recoil.brightness_min = 0;
Recoil.brightness_max = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Recoil.brightness = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Recoil.speed_min = CM_SMALL_ARGB_SPEED_SLOWEST;
Recoil.speed_max = CM_SMALL_ARGB_SPEED_FASTEST;
Recoil.color_mode = MODE_COLORS_RANDOM;
Recoil.speed = speed;
modes.push_back(Recoil);
mode Breathing;
Breathing.name = "Breathing";
Breathing.value = CM_SMALL_ARGB_MODE_BREATHING;
Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Breathing.colors_min = 1;
Breathing.colors_max = 1;
Breathing.colors.resize(Breathing.colors_max);
Breathing.brightness_min = 0;
Breathing.brightness_max = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Breathing.brightness = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Breathing.speed_min = CM_SMALL_ARGB_SPEED_SLOWEST;
Breathing.speed_max = CM_SMALL_ARGB_SPEED_FASTEST;
Breathing.color_mode = MODE_COLORS_RANDOM;
Breathing.speed = speed;
modes.push_back(Breathing);
mode Refill;
Refill.name = "Refill";
Refill.value = CM_SMALL_ARGB_MODE_REFILL;
Refill.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_BRIGHTNESS;
Refill.colors_min = 1;
Refill.colors_max = 1;
Refill.colors.resize(Refill.colors_max);
Refill.brightness_min = 0;
Refill.brightness_max = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Refill.brightness = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Refill.speed_min = CM_SMALL_ARGB_SPEED_SLOWEST;
Refill.speed_max = CM_SMALL_ARGB_SPEED_FASTEST;
Refill.color_mode = MODE_COLORS_RANDOM;
Refill.speed = speed;
modes.push_back(Refill);
mode Demo;
Demo.name = "Demo";
Demo.value = CM_SMALL_ARGB_MODE_DEMO;
Demo.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Demo.brightness_min = 0;
Demo.brightness_max = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Demo.brightness = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Demo.speed_min = CM_SMALL_ARGB_SPEED_SLOWEST;
Demo.speed_max = CM_SMALL_ARGB_SPEED_FASTEST;
Demo.color_mode = MODE_COLORS_NONE;
Demo.speed = speed;
modes.push_back(Demo);
mode Spectrum;
Spectrum.name = "Spectrum";
Spectrum.value = CM_SMALL_ARGB_MODE_SPECTRUM;
Spectrum.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS;
Spectrum.brightness_min = 0;
Spectrum.brightness_max = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Spectrum.brightness = CM_SMALL_ARGB_BRIGHTNESS_MAX;
Spectrum.speed_min = CM_SMALL_ARGB_SPEED_SLOWEST;
Spectrum.speed_max = CM_SMALL_ARGB_SPEED_FASTEST;
Spectrum.color_mode = MODE_COLORS_NONE;
Spectrum.speed = speed;
modes.push_back(Spectrum);
mode PassThru;
PassThru.name = "Pass Thru";
PassThru.value = CM_SMALL_ARGB_MODE_PASSTHRU;
PassThru.color_mode = MODE_COLORS_NONE;
modes.push_back(PassThru);
Init_Controller(); //Only processed on first run
SetupZones();
int temp_mode = controller->GetMode();
for(int mode_idx = 0; mode_idx < (int)modes.size() ; mode_idx++)
{
if(temp_mode == modes[mode_idx].value)
{
active_mode = mode_idx;
break;
}
}
if (modes[active_mode].flags & MODE_FLAG_HAS_MODE_SPECIFIC_COLOR)
{
modes[active_mode].colors[0] = ToRGBColor(controller->GetLedRed(), controller->GetLedGreen(), controller->GetLedBlue());
}
modes[active_mode].color_mode = (controller->GetRandomColours()) ? MODE_COLORS_RANDOM : MODE_COLORS_MODE_SPECIFIC;
if (modes[active_mode].flags & MODE_FLAG_HAS_SPEED)
{
modes[active_mode].speed = controller->GetLedSpeed();
}
}
RGBController_CMSmallARGBController::~RGBController_CMSmallARGBController()
{
delete controller;
}
void RGBController_CMSmallARGBController::Init_Controller()
{
int zone_idx = controller->GetZoneIndex();
int zone_led_count = cm_small_argb_header_data[zone_idx].count;
bool boolSingleLED = ( zone_led_count == 1 ); //If argb_header_data[zone_idx].count == 1 then the zone is ZONE_TYPE_SINGLE
zone ARGB_zone;
ARGB_zone.name = std::to_string(zone_idx);
ARGB_zone.type = (boolSingleLED) ? ZONE_TYPE_SINGLE : ZONE_TYPE_LINEAR;
ARGB_zone.leds_min = CM_SMALL_ARGB_MIN_LEDS;
ARGB_zone.leds_max = CM_SMALL_ARGB_MAX_LEDS;
ARGB_zone.leds_count = zone_led_count;
ARGB_zone.matrix_map = NULL;
zones.push_back(ARGB_zone);
}
void RGBController_CMSmallARGBController::SetupZones()
{
/*-------------------------------------------------*\
| Clear any existing color/LED configuration |
\*-------------------------------------------------*/
leds.clear();
colors.clear();
/*---------------------------------------------------------*\
| Set up zones |
\*---------------------------------------------------------*/
for(std::size_t zone_idx = 0; zone_idx < zones.size(); zone_idx++)
{
bool boolSingleLED = (zones[zone_idx].type == ZONE_TYPE_SINGLE); //Calculated for later use
if (!boolSingleLED)
{
controller->SetLedCount(cm_small_argb_header_data[zone_idx].header, zones[zone_idx].leds_count);
}
for(unsigned int lp_idx = 0; lp_idx < zones[zone_idx].leds_count; lp_idx++)
{
led new_led;
unsigned int i = std::stoi(zones[zone_idx].name);
if(boolSingleLED)
{
new_led.name = i;
new_led.value = cm_small_argb_header_data[i].header;
}
else
{
new_led.name = i;
new_led.name.append(" LED " + std::to_string(lp_idx));
new_led.value = cm_small_argb_header_data[i].header;
}
leds.push_back(new_led);
}
}
SetupColors();
}
void RGBController_CMSmallARGBController::ResizeZone(int zone, int new_size)
{
if((size_t) zone >= zones.size())
{
return;
}
if(((unsigned int)new_size >= zones[zone].leds_min) && ((unsigned int)new_size <= zones[zone].leds_max))
{
zones[zone].leds_count = new_size;
SetupZones();
}
}
void RGBController_CMSmallARGBController::DeviceUpdateLEDs()
{
for(int zone_idx = 0; zone_idx < (int)zones.size(); zone_idx++)
{
UpdateZoneLEDs(zone_idx);
}
}
void RGBController_CMSmallARGBController::UpdateZoneLEDs(int zone)
{
if(serial >= CM_SMALL_ARGB_FW0012)
{
controller->SetLedsDirect( zones[zone].colors, zones[zone].leds_count );
}
}
void RGBController_CMSmallARGBController::UpdateSingleLED(int led)
{
UpdateZoneLEDs(led);
}
void RGBController_CMSmallARGBController::SetCustomMode()
{
/*-------------------------------------------------*\
| The small ARGB may not support "Direct" mode |
| in which case this will select "Pass Thru" |
\*-------------------------------------------------*/
if(serial >= CM_SMALL_ARGB_FW0012)
{
active_mode = 0;
}
else
{
active_mode = 7;
}
}
void RGBController_CMSmallARGBController::DeviceUpdateMode()
{
bool random_colours = (modes[active_mode].color_mode == MODE_COLORS_RANDOM);
RGBColor colour = (modes[active_mode].color_mode == MODE_COLORS_MODE_SPECIFIC) ? modes[active_mode].colors[0] : 0;
controller->SetMode( modes[active_mode].value, modes[active_mode].speed, modes[active_mode].brightness, colour, random_colours);
}
@@ -0,0 +1,43 @@
/*---------------------------------------------------------*\
| RGBController_CMSmallARGBController.h |
| |
| RGBController for Cooler Master Small ARGB controller |
| |
| Chris M (Dr_No) 31 Jan 2021 |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
#pragma once
#include <vector>
#include "RGBController.h"
#include "CMSmallARGBController.h"
#define CM_SMALL_ARGB_MIN_LEDS 4
#define CM_SMALL_ARGB_MAX_LEDS 48
#define CM_SMALL_ARGB_BRIGHTNESS_MAX 0xFF
#define CM_SMALL_ARGB_FW0012 "A202104052336"
class RGBController_CMSmallARGBController : public RGBController
{
public:
RGBController_CMSmallARGBController(CMSmallARGBController* controller_ptr);
~RGBController_CMSmallARGBController();
void SetupZones();
void ResizeZone(int zone, int new_size);
void DeviceUpdateLEDs();
void UpdateZoneLEDs(int zone);
void UpdateSingleLED(int led);
void SetCustomMode();
void DeviceUpdateMode();
private:
void Init_Controller();
int GetDeviceMode();
CMSmallARGBController* controller;
};
@@ -0,0 +1,382 @@
/*---------------------------------------------------------*\
| CoolerMasterControllerDetect.cpp |
| |
| Detector for Cooler Master devices |
| |
| This file is part of the OpenRGB project |
| SPDX-License-Identifier: GPL-2.0-or-later |
\*---------------------------------------------------------*/
/*-----------------------------------------------------*\
| OpenRGB includes |
\*-----------------------------------------------------*/
#include <hidapi.h>
#include "Detector.h"
#include "LogManager.h"
/*-----------------------------------------------------*\
| Coolermaster specific includes |
\*-----------------------------------------------------*/
#include "RGBController_CMMMController.h"
#include "RGBController_CMMM711Controller.h"
#include "RGBController_CMMM712Controller.h"
#include "RGBController_CMMP750Controller.h"
#include "RGBController_CMARGBController.h"
#include "RGBController_CMSmallARGBController.h"
#include "RGBController_CMARGBGen2A1Controller.h"
#include "RGBController_CMRGBController.h"
#include "RGBController_CMR6000Controller.h"
#include "RGBController_CMMonitorController.h"
#include "RGBController_CMGD160Controller.h"
#include "RGBController_CMKeyboardController.h"
/*-----------------------------------------------------*\
| Coolermaster USB vendor ID |
\*-----------------------------------------------------*/
#define COOLERMASTER_VID 0x2516
/*-----------------------------------------------------*\
| Coolermaster Keyboards |
| PIDs defined in `CMMKControllerV2.h` |
\*-----------------------------------------------------*/
/*-----------------------------------------------------*\
| Coolermaster GPUs |
| PIDs defined in `CMR6000Controller.h` |
\*-----------------------------------------------------*/
/*-----------------------------------------------------*\
| Coolermaster LEDstrip controllers |
\*-----------------------------------------------------*/
#define COOLERMASTER_ARGB_PID 0x1011
#define COOLERMASTER_ARGB_GEN2_A1_PID 0x0173
#define COOLERMASTER_ARGB_GEN2_A1_V2_PID 0x01C9
#define COOLERMASTER_ARGB_GEN2_A1_MINI_PID 0x01CB
#define COOLERMASTER_SMALL_ARGB_PID 0x1000
#define COOLERMASTER_RGB_PID 0x004F
/*-----------------------------------------------------*\
| Coolermaster Mice |
\*-----------------------------------------------------*/
#define COOLERMASTER_MM530_PID 0x0065
#define COOLERMASTER_MM531_PID 0x0097
#define COOLERMASTER_MM711_PID 0x0101
#define COOLERMASTER_MM712_PID 0x0169
#define COOLERMASTER_MM720_PID 0x0141
#define COOLERMASTER_MM730_PID 0x0165
/*-----------------------------------------------------*\
| Coolermaster Mousemats |
\*-----------------------------------------------------*/
#define COOLERMASTER_MP750_XL_PID 0x0109
#define COOLERMASTER_MP750_L_PID 0x0107
#define COOLERMASTER_MP750_MEDIUM_PID 0x0105
/*-----------------------------------------------------*\
| Coolermaster Monitors |
\*-----------------------------------------------------*/
#define COOLERMASTER_GM27_FQS_PID 0x01BB
/*-----------------------------------------------------*\
| Coolermaster Desks |
\*-----------------------------------------------------*/
#define COOLERMASTER_GD160_PID 0x01A9
/******************************************************************************************\
* *
* DetectCoolerMasterControllers *
* *
* Tests the USB address to see if any CoolerMaster controllers exists there. *
* *
\******************************************************************************************/
void DetectCoolerMasterARGB(hid_device_info* info, const std::string&)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMARGBController* controller = new CMARGBController(dev, info->path);
if(controller->GetVersion() != "Unsupported")
{
RGBController_CMARGBController* rgb_controller = new RGBController_CMARGBController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
else
{
LOG_ERROR("[CMARGBController] Unsupported firmware version");
delete controller;
}
}
}
void DetectCoolerMasterARGBGen2A1(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMARGBGen2A1controller* controller = new CMARGBGen2A1controller(dev, *info, name);
RGBController_CMARGBGen2A1Controller* rgb_controller = new RGBController_CMARGBGen2A1Controller(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterGPU(hid_device_info* info, const std::string&)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMR6000Controller* controller = new CMR6000Controller(dev, info->path, info->product_id);
RGBController_CMR6000Controller* rgb_controller = new RGBController_CMR6000Controller(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterV1Keyboards(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
switch(info->product_id)
{
case COOLERMASTER_KEYBOARD_PRO_L_PID:
case COOLERMASTER_KEYBOARD_PRO_L_WHITE_PID:
case COOLERMASTER_KEYBOARD_PRO_S_PID:
{
CMKeyboardV1Controller* controller = new CMKeyboardV1Controller(dev, info, name);
RGBController_CMKeyboardController* rgb_controller = new RGBController_CMKeyboardController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
break;
default:
LOG_DEBUG("[%s] Controller not created as the product ID %04X is missing from detector switch", name.c_str(), info->product_id);
break;
}
}
}
void DetectCoolerMasterV2Keyboards(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
switch(info->product_id)
{
case COOLERMASTER_KEYBOARD_PRO_L_PID:
case COOLERMASTER_KEYBOARD_PRO_L_WHITE_PID:
case COOLERMASTER_KEYBOARD_PRO_S_PID:
{
CMKeyboardV1Controller* controller = new CMKeyboardV1Controller(dev, info, name);
RGBController_CMKeyboardController* rgb_controller = new RGBController_CMKeyboardController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
break;
case COOLERMASTER_KEYBOARD_SK622B_PID:
case COOLERMASTER_KEYBOARD_SK622W_PID:
case COOLERMASTER_KEYBOARD_SK630_PID:
case COOLERMASTER_KEYBOARD_SK650_PID:
case COOLERMASTER_KEYBOARD_SK652_PID:
case COOLERMASTER_KEYBOARD_SK653_PID:
case COOLERMASTER_KEYBOARD_CK530_PID:
case COOLERMASTER_KEYBOARD_CK530_V2_PID:
case COOLERMASTER_KEYBOARD_CK550_V2_PID:
case COOLERMASTER_KEYBOARD_CK552_V2_PID:
case COOLERMASTER_KEYBOARD_MK730_PID:
case COOLERMASTER_KEYBOARD_MK750_PID:
{
CMKeyboardV2Controller* controller = new CMKeyboardV2Controller(dev, info, name);
RGBController_CMKeyboardController* rgb_controller = new RGBController_CMKeyboardController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
break;
default:
LOG_DEBUG("[%s] Controller not created as the product ID %04X is missing from detector switch", name.c_str(), info->product_id);
break;
}
}
}
void DetectCoolerMasterMouse(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMMMController* controller = new CMMMController(dev, info->path, info->product_id, name);
RGBController_CMMMController* rgb_controller = new RGBController_CMMMController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterMouse711(hid_device_info* info, const std::string& /*name*/)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMMM711Controller* controller = new CMMM711Controller(dev, info->path);
RGBController_CMMM711Controller* rgb_controller = new RGBController_CMMM711Controller(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterMouse712(hid_device_info* info, const std::string& /*name*/)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMMM712Controller* controller = new CMMM712Controller(dev, info->path);
RGBController_CMMM712Controller* rgb_controller = new RGBController_CMMM712Controller(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterMousemats(hid_device_info* info, const std::string& /*name*/)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMMP750Controller* controller = new CMMP750Controller(dev, info->path);
RGBController_CMMP750Controller* rgb_controller = new RGBController_CMMP750Controller(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterRGB(hid_device_info* info, const std::string& /*name*/)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMRGBController* controller = new CMRGBController(dev, info->path);
RGBController_CMRGBController* rgb_controller = new RGBController_CMRGBController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterSmallARGB(hid_device_info* info, const std::string& /*name*/)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMSmallARGBController* controller = new CMSmallARGBController(dev, info->path, 0);
RGBController_CMSmallARGBController* rgb_controller = new RGBController_CMSmallARGBController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterMonitor(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMMonitorController* controller = new CMMonitorController(dev, *info, name);
RGBController_CMMonitorController* rgb_controller = new RGBController_CMMonitorController(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
void DetectCoolerMasterGD160(hid_device_info* info, const std::string& name)
{
hid_device* dev = hid_open_path(info->path);
if(dev)
{
CMGD160Controller* controller = new CMGD160Controller(dev, *info, name);
RGBController_CMGD160Controller* rgb_controller = new RGBController_CMGD160Controller(controller);
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
/*-----------------------------------------------------*\
| Coolermaster Keyboards |
| PIDs defined in `CMKeyboardDevices.h` |
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Cooler Master MasterKeys Pro S", DetectCoolerMasterV1Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_PRO_S_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MasterKeys Pro L", DetectCoolerMasterV1Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_PRO_L_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MasterKeys Pro L White", DetectCoolerMasterV1Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_PRO_L_WHITE_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MK850", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_MK850_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK620 White", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK620W_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK620 Black", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK620B_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK622 White", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK622W_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK622 Black", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK622B_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK630", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK630_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK650", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK650_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK652", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK652_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master SK653", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_SK653_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MK730", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_MK730_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MK750", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_MK750_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master CK530", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_CK530_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master CK530 V2", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_CK530_V2_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master CK550 V2", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_CK550_V2_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master CK550 V1 / CK552", DetectCoolerMasterV2Keyboards, COOLERMASTER_VID, COOLERMASTER_KEYBOARD_CK552_V2_PID, 1, 0xFF00, 1);
/*-----------------------------------------------------*\
| Coolermaster LEDstrip controllers |
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Cooler Master ARGB", DetectCoolerMasterARGB, COOLERMASTER_VID, COOLERMASTER_ARGB_PID, 0, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master ARGB Gen 2 A1", DetectCoolerMasterARGBGen2A1, COOLERMASTER_VID, COOLERMASTER_ARGB_GEN2_A1_PID, 1, 0xFF01, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master ARGB Gen 2 A1 V2", DetectCoolerMasterARGBGen2A1, COOLERMASTER_VID, COOLERMASTER_ARGB_GEN2_A1_V2_PID, 1, 0xFF01, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master ARGB Gen 2 A1 Mini", DetectCoolerMasterARGBGen2A1, COOLERMASTER_VID, COOLERMASTER_ARGB_GEN2_A1_MINI_PID, 1, 0xFF01, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master RGB", DetectCoolerMasterRGB, COOLERMASTER_VID, COOLERMASTER_RGB_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master Small ARGB", DetectCoolerMasterSmallARGB, COOLERMASTER_VID, COOLERMASTER_SMALL_ARGB_PID, 0, 0xFF00, 1);
/*-----------------------------------------------------*\
| Coolermaster Mice |
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Cooler Master MM530", DetectCoolerMasterMouse, COOLERMASTER_VID, COOLERMASTER_MM530_PID, 1, 0xFF00, 1);
//REGISTER_HID_DETECTOR_IPU("Cooler Master MM531", DetectCoolerMasterMouse, COOLERMASTER_VID, COOLERMASTER_MM531_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MM711", DetectCoolerMasterMouse711, COOLERMASTER_VID, COOLERMASTER_MM711_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MM712", DetectCoolerMasterMouse712, COOLERMASTER_VID, COOLERMASTER_MM712_PID, 3, 0xFF0A, 2);
REGISTER_HID_DETECTOR_IPU("Cooler Master MM720", DetectCoolerMasterMouse, COOLERMASTER_VID, COOLERMASTER_MM720_PID, 1, 0xFF00, 1);
REGISTER_HID_DETECTOR_IPU("Cooler Master MM730", DetectCoolerMasterMouse, COOLERMASTER_VID, COOLERMASTER_MM730_PID, 1, 0xFF00, 1);
/*-----------------------------------------------------*\
| Coolermaster Mousemats |
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_PU ("Cooler Master MP750 XL", DetectCoolerMasterMousemats, COOLERMASTER_VID, COOLERMASTER_MP750_XL_PID, 0xFF00, 1);
REGISTER_HID_DETECTOR_PU ("Cooler Master MP750 Large", DetectCoolerMasterMousemats, COOLERMASTER_VID, COOLERMASTER_MP750_L_PID, 0xFF00, 1);
REGISTER_HID_DETECTOR_PU ("Cooler Master MP750 Medium", DetectCoolerMasterMousemats, COOLERMASTER_VID, COOLERMASTER_MP750_MEDIUM_PID, 0xFF00, 1);
/*-----------------------------------------------------*\
| Coolermaster GPUs |
| PIDs defined in `CMR6000Controller.h` |
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_I ("Cooler Master Radeon RX 6000 GPU", DetectCoolerMasterGPU, COOLERMASTER_VID, COOLERMASTER_RADEON_6000_PID, 1 );
REGISTER_HID_DETECTOR_I ("Cooler Master Radeon RX 6900 GPU", DetectCoolerMasterGPU, COOLERMASTER_VID, COOLERMASTER_RADEON_6900_PID, 1 );
/*-----------------------------------------------------*\
| Coolermaster Monitors |
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Cooler Master GM27-FQS ARGB Monitor", DetectCoolerMasterMonitor, COOLERMASTER_VID, COOLERMASTER_GM27_FQS_PID, 0, 0xFF00, 1);
/*-----------------------------------------------------*\
| Coolermaster Desks |
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_IPU("Cooler Master GD160 ARGB Gaming Desk", DetectCoolerMasterGD160, COOLERMASTER_VID, COOLERMASTER_GD160_PID, 0, 0xFF00, 1);