Add support for CoolerMaster GM27. Closes #3627

This commit is contained in:
morg 2023-09-18 16:03:25 +02:00 committed by Adam Honse
parent 3c7a24c4c1
commit 86ba18595f
6 changed files with 597 additions and 1 deletions

View file

@ -0,0 +1,257 @@
/*-------------------------------------------------------------------*\
| CMMonitorController.cpp |
| |
| Driver for Coolermaster Gaming Monitor |
| |
| morg (Morgan Guimard) 9/18/2023 |
| |
\*-------------------------------------------------------------------*/
#include "CMMonitorController.h"
#include <cstring>
using namespace std::chrono_literals;
CMMonitorController::CMMonitorController(hid_device* dev_handle, const hid_device_info& info)
{
dev = dev_handle;
location = info.path;
wchar_t serial_string[128];
int ret = hid_get_serial_number_string(dev, serial_string, 128);
if(ret != 0)
{
serial_number = "";
}
else
{
std::wstring return_wstring = serial_string;
serial_number = std::string(return_wstring.begin(), return_wstring.end());
}
}
CMMonitorController::~CMMonitorController()
{
hid_close(dev);
}
std::string CMMonitorController::GetDeviceLocation()
{
return("HID: " + location);
}
std::string CMMonitorController::GetSerialString()
{
return(serial_number);
}
void CMMonitorController::SetMode(uint8_t mode_value, const RGBColor& color, uint8_t speed, uint8_t brightness)
{
if(software_mode_enabled)
{
DisableSoftwareMode();
}
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)
{
DisableSoftwareMode();
}
/*---------------------------------------------------------*\
| 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 8 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 += 58;
}
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)
{
EnableSoftwareMode();
}
/*---------------------------------------------------------*\
| 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 14 sequence packets |
\*---------------------------------------------------------*/
uint8_t usb_buf[CM_MONITOR_PACKET_LENGTH];
for(unsigned int p = 0; p < 2; p++)
{
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] = p + 1;
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::EnableSoftwareMode()
{
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] = 0x01;
usb_buf[6] = 0x01;
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
usb_buf[4] = 0x02;
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
uint8_t read_buf[CM_MONITOR_PACKET_LENGTH];
/*---------------------------------------------------------*\
| We have to send a few black packets, with some read ones |
\*---------------------------------------------------------*/
for(unsigned int p = 0; p < 4; p++)
{
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] = (p == 0 || p == 0 ) ? 0x01 : 0x02;
usb_buf[5] = 0x01;
usb_buf[6] = 0x80;
}
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
if(p ==0 && (i == 2 || i == 4))
{
memset(read_buf, 0x00, CM_MONITOR_PACKET_LENGTH);
hid_read(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
}
}
}
software_mode_enabled = true;
}
void CMMonitorController::DisableSoftwareMode()
{
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] = 0x01;
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
usb_buf[4] = 0x02;
hid_write(dev, usb_buf, CM_MONITOR_PACKET_LENGTH);
software_mode_enabled = false;
}

View file

@ -0,0 +1,57 @@
/*-------------------------------------------------------------------*\
| CMMonitorController.cpp |
| |
| Driver for Coolermaster Gaming Monitor |
| |
| morg (Morgan Guimard) 9/18/2023 |
| |
\*-------------------------------------------------------------------*/
#include "RGBController.h"
#include <string>
#include <hidapi/hidapi.h>
#pragma once
#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);
~CMMonitorController();
std::string GetSerialString();
std::string GetDeviceLocation();
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 serial_number;
std::string location;
hid_device* dev;
bool software_mode_enabled = false;
void EnableSoftwareMode();
void DisableSoftwareMode();
};

View file

@ -18,7 +18,7 @@
#include "RGBController_CMRGBController.h"
#include "RGBController_CMR6000Controller.h"
#include "RGBController_CMMKController.h"
#include "RGBController_CMMonitorController.h"
/*-----------------------------------------------------*\
| Coolermaster USB vendor ID |
\*-----------------------------------------------------*/
@ -64,6 +64,11 @@
#define COOLERMASTER_MP750_L_PID 0x0107
#define COOLERMASTER_MP750_MEDIUM_PID 0x0105
/*-----------------------------------------------------*\
| Coolermaster Monitors |
\*-----------------------------------------------------*/
#define COOLERMASTER_GM27_FQS_PID 0x01BB
/******************************************************************************************\
* *
* DetectCoolerMasterControllers *
@ -207,6 +212,19 @@ void DetectCoolerMasterSmallARGB(hid_device_info* info, const std::string&)
}
}
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);
RGBController_CMMonitorController* rgb_controller = new RGBController_CMMonitorController(controller);
rgb_controller->name = name;
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}
/*-----------------------------------------------------*\
| Coolermaster Keyboards |
\*-----------------------------------------------------*/
@ -248,3 +266,8 @@ REGISTER_HID_DETECTOR_PU ("Cooler Master MP750 Medium", DetectCooler
\*-----------------------------------------------------*/
REGISTER_HID_DETECTOR_I ("Cooler Master Radeon 6000 GPU", DetectCoolerMasterGPU, COOLERMASTER_VID, COOLERMASTER_RADEON_6000_PID, 1 );
REGISTER_HID_DETECTOR_I ("Cooler Master Radeon 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);

View file

@ -0,0 +1,225 @@
/*-------------------------------------------------------------------*\
| RGBController_CMMonitorController.cpp |
| |
| Driver for Coolermaster Gaming Monitor USB Controller |
| |
| morg (Morgan Guimard) 9/18/2023 |
| |
\*-------------------------------------------------------------------*/
#include "RGBController_CMMonitorController.h"
#include <thread>
#include <chrono>
/**------------------------------------------------------------------*\
@name Coolermaster Gaming Monitor
@category LEDStrip
@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 = "CoolerMaster LED Controller A1";
vendor = "CoolerMaster";
type = DEVICE_TYPE_LEDSTRIP;
description = name;
location = controller->GetDeviceLocation();
serial = controller->GetSerialString();
version = "";
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::SetCustomMode()
{
active_mode = 0;
}
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;
}
}

View file

@ -0,0 +1,30 @@
/*-------------------------------------------------------------------*\
| RGBController_CMMonitorController.cpp |
| |
| Driver for Coolermaster Gaming Monitor USB Controller |
| |
| morg (Morgan Guimard) 9/18/2023 |
| |
\*-------------------------------------------------------------------*/
#pragma once
#include "RGBController.h"
#include "CMMonitorController.h"
#include <vector>
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 SetCustomMode();
void DeviceUpdateMode();
private:
CMMonitorController* controller;
};