mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2025-12-24 07:47:49 -05:00
501 lines
14 KiB
C++
501 lines
14 KiB
C++
/*---------------------------------------------------------*\
|
|
| 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;
|
|
}
|