mirror of
https://github.com/CalcProgrammer1/OpenRGB.git
synced 2026-07-29 14:36:06 -04:00
MSIMonitorController: 0x72 layout support (MPG 322URX QD-OLED + siblings)
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_MSIMonitor.cpp |
|
||||
| MSIMonitorController.cpp |
|
||||
| |
|
||||
| RGBController for MSI monitor (gaming controller) |
|
||||
| Driver for MSI monitor (gaming controller) |
|
||||
| |
|
||||
| Andy Herbert 2026 June 4 |
|
||||
| Ken Sanislo 2026 July 20 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
@@ -119,3 +120,123 @@ void MSIMonitorController::Set(uint8_t mode_value, const std::vector<RGBColor> c
|
||||
|
||||
hid_send_feature_report(dev, data, MSI_MONITOR_PACKET_SIZE);
|
||||
}
|
||||
|
||||
uint8_t MSIMonitorController::GetLayoutVersion()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Ask the MCU which buffer layout it speaks. Request |
|
||||
| is [0x01][opcode] zero padded, reply is [0x01][0x5A] |
|
||||
| then data with the version at byte 3. |
|
||||
\*-----------------------------------------------------*/
|
||||
uint8_t request[MSI_MONITOR_QUERY_PACKET_SIZE];
|
||||
uint8_t reply[MSI_MONITOR_QUERY_PACKET_SIZE];
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Unimplemented opcodes never answer, so a reply left |
|
||||
| queued by an earlier exchange would be read here and |
|
||||
| parsed as this query's answer. Drain first. |
|
||||
\*-----------------------------------------------------*/
|
||||
while(hid_read_timeout(dev, reply, MSI_MONITOR_QUERY_PACKET_SIZE, 0) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
memset(request, 0x00, MSI_MONITOR_QUERY_PACKET_SIZE);
|
||||
|
||||
request[0] = MSI_MONITOR_QUERY_REPORT_ID;
|
||||
request[1] = MSI_MONITOR_OPCODE_GET_VERSION;
|
||||
|
||||
if(hid_write(dev, request, MSI_MONITOR_QUERY_PACKET_SIZE) < 0)
|
||||
{
|
||||
return(MSI_MONITOR_VERSION_UNKNOWN);
|
||||
}
|
||||
|
||||
memset(reply, 0x00, MSI_MONITOR_QUERY_PACKET_SIZE);
|
||||
|
||||
if(hid_read_timeout(dev, reply, MSI_MONITOR_QUERY_PACKET_SIZE, 500) <= 0)
|
||||
{
|
||||
return(MSI_MONITOR_VERSION_UNKNOWN);
|
||||
}
|
||||
|
||||
if(reply[1] != MSI_MONITOR_QUERY_ACK)
|
||||
{
|
||||
return(MSI_MONITOR_VERSION_UNKNOWN);
|
||||
}
|
||||
|
||||
return(reply[3]);
|
||||
}
|
||||
|
||||
void MSIMonitorController::SetMode72(uint8_t mode_value, uint8_t speed, uint8_t brightness, RGBColor color1, RGBColor color2, bool user_palette, bool save, const std::vector<RGBColor>& led_colors, bool fill_both_arrays)
|
||||
{
|
||||
uint8_t data[MSI_MONITOR_72_PACKET_SIZE];
|
||||
memset(data, 0x00, MSI_MONITOR_72_PACKET_SIZE);
|
||||
|
||||
data[0] = 0x72;
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Identical 11 byte control blocks at index 1 and 12 |
|
||||
\*-----------------------------------------------------*/
|
||||
for(unsigned int base = 1; base <= 12; base += 11)
|
||||
{
|
||||
data[base + 0] = mode_value;
|
||||
data[base + 1] = RGBGetRValue(color1);
|
||||
data[base + 2] = RGBGetGValue(color1);
|
||||
data[base + 3] = RGBGetBValue(color1);
|
||||
data[base + 4] = speed;
|
||||
data[base + 5] = brightness;
|
||||
data[base + 6] = RGBGetRValue(color2);
|
||||
data[base + 7] = RGBGetGValue(color2);
|
||||
data[base + 8] = RGBGetBValue(color2);
|
||||
data[base + 9] = user_palette ? 0x80 : 0x00;
|
||||
data[base + 10] = 0x00;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| The engine paints from the second inline colour array |
|
||||
| at index 95, not from Colour1 and not from the first |
|
||||
| array at index 23: on a 322URX a buffer carrying only |
|
||||
| Colour1 renders black, and walking one lit slot |
|
||||
| through the buffer only lights LEDs for the second |
|
||||
| array. That pairs with the control block at index 12 |
|
||||
| being the operative one. Built in palette modes |
|
||||
| leave the array clear so the firmware effect is not |
|
||||
| painted over. |
|
||||
| |
|
||||
| fill_both_arrays also writes the first array at index |
|
||||
| 23, for the dual block versions (11/13/15) whose two |
|
||||
| control blocks each drive their own run. On a single |
|
||||
| block layout the first array is inert, so filling it |
|
||||
| is harmless. Those versions also route colour index |
|
||||
| above 15 to a separate DragonShield emblem region not |
|
||||
| handled here - one reason they stay disabled. |
|
||||
\*-----------------------------------------------------*/
|
||||
if(user_palette)
|
||||
{
|
||||
for(unsigned int slot = 0; slot < MSI_MONITOR_72_ARRAY_SLOTS && slot < led_colors.size(); slot++)
|
||||
{
|
||||
unsigned int offset_b = MSI_MONITOR_72_ARRAY_B_INDEX + (slot * 3);
|
||||
|
||||
data[offset_b + 0] = RGBGetRValue(led_colors[slot]);
|
||||
data[offset_b + 1] = RGBGetGValue(led_colors[slot]);
|
||||
data[offset_b + 2] = RGBGetBValue(led_colors[slot]);
|
||||
|
||||
if(fill_both_arrays)
|
||||
{
|
||||
unsigned int offset_a = MSI_MONITOR_72_ARRAY_A_INDEX + (slot * 3);
|
||||
|
||||
data[offset_a + 0] = RGBGetRValue(led_colors[slot]);
|
||||
data[offset_a + 1] = RGBGetGValue(led_colors[slot]);
|
||||
data[offset_a + 2] = RGBGetBValue(led_colors[slot]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Final byte is store to flash: 0x01 persists across |
|
||||
| power cycles, 0x00 applies without a flash write. |
|
||||
| Keep 0x00 for streaming to avoid flicker and wear. |
|
||||
\*-----------------------------------------------------*/
|
||||
data[MSI_MONITOR_72_STORE_INDEX] = save ? 0x01 : 0x00;
|
||||
|
||||
hid_send_feature_report(dev, data, MSI_MONITOR_72_PACKET_SIZE);
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_MSIMonitor.cpp |
|
||||
| MSIMonitorController.h |
|
||||
| |
|
||||
| RGBController for MSI monitor (gaming controller) |
|
||||
| Driver for MSI monitor (gaming controller) |
|
||||
| |
|
||||
| Andy Herbert 2026 June 1 |
|
||||
| Ken Sanislo 2026 July 20 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
@@ -18,6 +19,42 @@
|
||||
#define MSI_MONITOR_LEDS 9
|
||||
#define MSI_MONITOR_PACKET_SIZE 78
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| 0x72 layout (dual control block, e.g. MPG 322URX QD-OLED) |
|
||||
\*---------------------------------------------------------*/
|
||||
#define MSI_MONITOR_72_PACKET_SIZE 168
|
||||
#define MSI_MONITOR_72_STORE_INDEX 167
|
||||
#define MSI_MONITOR_72_ARRAY_A_INDEX 23
|
||||
#define MSI_MONITOR_72_ARRAY_B_INDEX 95
|
||||
#define MSI_MONITOR_72_ARRAY_SLOTS 24
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Fill order the firmware expects (vendor Direction enum). |
|
||||
| Only the physical origin differs; index 0 is that end. |
|
||||
| The controller mirrors RightToLeft into left origin so |
|
||||
| OpenRGB LED 0 is always the left/start. Circle and Ctype |
|
||||
| are non linear shapes: driven as a plain line for now, |
|
||||
| they want a custom layout once someone maps the shape. |
|
||||
\*---------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
MSI_MONITOR_72_DIR_RIGHT_TO_LEFT = 0,
|
||||
MSI_MONITOR_72_DIR_LEFT_TO_RIGHT = 1,
|
||||
MSI_MONITOR_72_DIR_UP_TO_DOWN = 2,
|
||||
MSI_MONITOR_72_DIR_CIRCLE = 3,
|
||||
MSI_MONITOR_72_DIR_CTYPE = 4,
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Layout version query rides the short report channel: |
|
||||
| write [0x01][opcode], read [0x01][0x5A][data] |
|
||||
\*---------------------------------------------------------*/
|
||||
#define MSI_MONITOR_QUERY_PACKET_SIZE 64
|
||||
#define MSI_MONITOR_QUERY_REPORT_ID 0x01
|
||||
#define MSI_MONITOR_QUERY_ACK 0x5A
|
||||
#define MSI_MONITOR_OPCODE_GET_VERSION 0xB0
|
||||
#define MSI_MONITOR_VERSION_UNKNOWN 0
|
||||
|
||||
enum
|
||||
{
|
||||
MSI_MONITOR_OFF_MODE_VALUE = 0x00,
|
||||
@@ -31,6 +68,53 @@ enum
|
||||
MSI_MONITOR_RANDOM_MODE_VALUE = 0x1F
|
||||
};
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| 0x72 layout mode values. These match the MSI Mystic |
|
||||
| Light motherboard mode enum value for value (see |
|
||||
| MSIMysticLightController/MSIMysticLightCommon.h): the |
|
||||
| monitor runs the same Nuvoton Mystic Light engine, so the |
|
||||
| effect numbering is shared with its motherboard sibling. |
|
||||
| Values 10-14 and 32 are the audio modes, not exposed |
|
||||
| here (they need the music level feed). |
|
||||
\*---------------------------------------------------------*/
|
||||
enum
|
||||
{
|
||||
MSI_MONITOR_72_MODE_OFF = 0,
|
||||
MSI_MONITOR_72_MODE_STATIC = 1,
|
||||
MSI_MONITOR_72_MODE_BREATHING = 2,
|
||||
MSI_MONITOR_72_MODE_FLASHING = 3,
|
||||
MSI_MONITOR_72_MODE_DOUBLE_FLASHING = 4,
|
||||
MSI_MONITOR_72_MODE_LIGHTNING = 5,
|
||||
MSI_MONITOR_72_MODE_SCANNER = 6,
|
||||
MSI_MONITOR_72_MODE_METEOR = 7,
|
||||
MSI_MONITOR_72_MODE_WATER_DROP = 8,
|
||||
MSI_MONITOR_72_MODE_RAINBOW_MSI = 9,
|
||||
MSI_MONITOR_72_MODE_COLOR_RING = 15,
|
||||
MSI_MONITOR_72_MODE_PLANETARY = 16,
|
||||
MSI_MONITOR_72_MODE_DOUBLE_METEOR = 17,
|
||||
MSI_MONITOR_72_MODE_ENERGY = 18,
|
||||
MSI_MONITOR_72_MODE_BLINK = 19,
|
||||
MSI_MONITOR_72_MODE_CLOCK = 20,
|
||||
MSI_MONITOR_72_MODE_COLOR_PULSE = 21,
|
||||
MSI_MONITOR_72_MODE_COLOR_SHIFT = 22,
|
||||
MSI_MONITOR_72_MODE_COLOR_WAVE = 23,
|
||||
MSI_MONITOR_72_MODE_MARQUEE = 24,
|
||||
MSI_MONITOR_72_MODE_RAINBOW = 25,
|
||||
MSI_MONITOR_72_MODE_RAINBOW_WAVE = 26,
|
||||
MSI_MONITOR_72_MODE_VISOR = 27,
|
||||
MSI_MONITOR_72_MODE_JRAINBOW = 28,
|
||||
MSI_MONITOR_72_MODE_RAINBOW_FLASH = 29,
|
||||
MSI_MONITOR_72_MODE_RAINBOW_DBLFLASH = 30,
|
||||
MSI_MONITOR_72_MODE_RAINBOW_LINE = 33,
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
MSI_MONITOR_72_SPEED_LOW = 0,
|
||||
MSI_MONITOR_72_SPEED_MEDIUM = 1,
|
||||
MSI_MONITOR_72_SPEED_HIGH = 2,
|
||||
};
|
||||
|
||||
class MSIMonitorController
|
||||
{
|
||||
public:
|
||||
@@ -44,6 +128,9 @@ public:
|
||||
|
||||
void Set(uint8_t mode_value, const std::vector<RGBColor> colors, uint8_t last_bit);
|
||||
|
||||
uint8_t GetLayoutVersion();
|
||||
void SetMode72(uint8_t mode_value, uint8_t speed, uint8_t brightness, RGBColor color1, RGBColor color2, bool user_palette, bool save, const std::vector<RGBColor>& led_colors, bool fill_both_arrays);
|
||||
|
||||
private:
|
||||
hid_device *dev;
|
||||
std::string description;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| MSIKeyboardControllerDetect.cpp |
|
||||
| MSIMonitorControllerDetect.cpp |
|
||||
| |
|
||||
| Detector for MSI monitor (MSI Gaming Controller) |
|
||||
| |
|
||||
@@ -10,10 +10,107 @@
|
||||
#include "DetectionManager.h"
|
||||
#include "MSIMonitorController.h"
|
||||
#include "RGBController_MSIMonitor.h"
|
||||
#include "RGBController_MSIMonitor72.h"
|
||||
|
||||
#define MSI_USB_VID 0x1462
|
||||
#define MSI_USB_PID 0x3FA4
|
||||
|
||||
/*---------------------------------------------------------*\
|
||||
| Vendor layout table (from the version -> layout map). |
|
||||
| The firmware reports its version to the 0xB0 query but |
|
||||
| not a LED count, so count/direction/block-count come |
|
||||
| from here. Fields: version, LED count, fill direction |
|
||||
| (MSI_MONITOR_72_DIR_*), dual_block. |
|
||||
| |
|
||||
| Every entry here is a single linear run driven through |
|
||||
| the 168 byte 0x72 buffer. Direction mirrors the fill so |
|
||||
| OpenRGB LED 0 is the left/start on every model. Circle |
|
||||
| and Ctype have no simple line mapping - they are driven |
|
||||
| as a plain line here and should get a custom per model |
|
||||
| layout once an owner maps the physical shape. |
|
||||
| |
|
||||
| Only version 34 is hardware verified (MPG 322URX). The |
|
||||
| rest are derived from the vendor table: same buffer, LED |
|
||||
| count and direction are the only differences, so effect |
|
||||
| and single colour modes are correct by construction. |
|
||||
| |
|
||||
| Left out on purpose: |
|
||||
| - dual_block versions 11/13/15 are stubbed but disabled |
|
||||
| (see the commented block); their two control blocks |
|
||||
| drive two runs and the per LED split is unconfirmed. |
|
||||
| - Advanced/0x82 versions 31/47 need the 0x30 bulk report |
|
||||
| this controller does not implement. |
|
||||
| A version not matched here falls through to the legacy |
|
||||
| 0x71 controller, home of the MAG272 class. |
|
||||
\*---------------------------------------------------------*/
|
||||
struct MSIMonitor72Layout
|
||||
{
|
||||
uint8_t version;
|
||||
unsigned int leds;
|
||||
unsigned int direction;
|
||||
bool dual_block;
|
||||
};
|
||||
|
||||
static const MSIMonitor72Layout msi_monitor_72_layouts[] =
|
||||
{
|
||||
{ 34, 9, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG271QRXQD_OLED (MPG 322URX reports this) - verified */
|
||||
{ 5, 12, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, false }, /* MAG272R */
|
||||
{ 8, 24, MSI_MONITOR_72_DIR_CIRCLE, false }, /* MAG301CR - Circle, wants custom layout */
|
||||
{ 10, 9, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG273R */
|
||||
{ 12, 9, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG271VCR */
|
||||
{ 14, 14, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* NXG253R */
|
||||
{ 17, 8, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, false }, /* MAG2x5R */
|
||||
{ 20, 12, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG301RF */
|
||||
{ 21, 18, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG341QR */
|
||||
{ 22, 24, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG321QRF */
|
||||
{ 24, 12, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG321QR */
|
||||
{ 25, 24, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG321UR */
|
||||
{ 28, 9, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG273CQR */
|
||||
{ 29, 24, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, false }, /* MAG401QR */
|
||||
{ 30, 21, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, false }, /* MAG325CQRF */
|
||||
{ 32, 7, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG274QRF */
|
||||
{ 33, 7, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG274URFQD */
|
||||
{ 36, 9, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG275CQRXF */
|
||||
{ 37, 22, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG345CQRD */
|
||||
{ 38, 20, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG325CQRFQDE2 */
|
||||
{ 39, 8, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, false }, /* MPG321CURX_QD_OLED */
|
||||
{ 40, 12, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MAG322URDFE16 */
|
||||
{ 41, 14, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, false }, /* MPG242RX60N */
|
||||
{ 42, 22, MSI_MONITOR_72_DIR_CTYPE, false }, /* MPG274URDFWE16 - Ctype, wants custom layout */
|
||||
{ 43, 21, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG346CQRFX24 */
|
||||
{ 44, 9, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG271QRQD_OLEDX50 */
|
||||
{ 46, 9, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, false }, /* MPG341CQRQD_OLEDX36 */
|
||||
|
||||
/*-----------------------------------------------------------------*\
|
||||
| Dual block - stubbed but DISABLED. The dual_block path fills |
|
||||
| both colour arrays so uniform colour modes are correct, but each |
|
||||
| block drives its own run and the per LED split is unconfirmed, so |
|
||||
| Direct is a guess. These versions also map colour index above 15 |
|
||||
| to a separate DragonShield emblem region (unhandled). An owner |
|
||||
| should enable, test, and ideally give it a custom layout: |
|
||||
| { 11, 16, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, true }, MPG273CQR |
|
||||
| { 13, 21, MSI_MONITOR_72_DIR_LEFT_TO_RIGHT, true }, MPG343CQR |
|
||||
| { 15, 18, MSI_MONITOR_72_DIR_RIGHT_TO_LEFT, true }, MPG323CQR |
|
||||
| |
|
||||
| Advanced/0x82 - not addable here, need the 0x30 bulk report: |
|
||||
| version 31, 40 LEDs, MEG342CQD_OLED |
|
||||
| version 47, 83 LEDs, 4 areas, MEG_X |
|
||||
\*-----------------------------------------------------------------*/
|
||||
};
|
||||
|
||||
static const MSIMonitor72Layout* MSIMonitorLayout(uint8_t version)
|
||||
{
|
||||
for(unsigned int i = 0; i < (sizeof(msi_monitor_72_layouts) / sizeof(msi_monitor_72_layouts[0])); i++)
|
||||
{
|
||||
if(msi_monitor_72_layouts[i].version == version)
|
||||
{
|
||||
return(&msi_monitor_72_layouts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return(nullptr);
|
||||
}
|
||||
|
||||
DetectedControllers DetectMSIMonitorController(hid_device_info* info, const std::string& name)
|
||||
{
|
||||
DetectedControllers detected_controllers;
|
||||
@@ -23,10 +120,41 @@ DetectedControllers DetectMSIMonitorController(hid_device_info* info, const std:
|
||||
|
||||
if(dev)
|
||||
{
|
||||
MSIMonitorController* controller = new MSIMonitorController(dev, *info, name);
|
||||
RGBController_MSIMonitor* rgb_controller = new RGBController_MSIMonitor(controller);
|
||||
/*-------------------------------------------------*\
|
||||
| One VID/PID covers several buffer layouts, so ask |
|
||||
| the MCU which one it speaks. A version in the |
|
||||
| 0x72 table selects the 168 byte layout and its |
|
||||
| LED count; anything else keeps the legacy 0x71 |
|
||||
| path, which is what the older monitors answer to. |
|
||||
\*-------------------------------------------------*/
|
||||
MSIMonitorController* controller = new MSIMonitorController(dev, *info, name);
|
||||
|
||||
detected_controllers.push_back(rgb_controller);
|
||||
uint8_t version = controller->GetLayoutVersion();
|
||||
const MSIMonitor72Layout* layout = MSIMonitorLayout(version);
|
||||
|
||||
if(layout != nullptr)
|
||||
{
|
||||
detected_controllers.push_back(new RGBController_MSIMonitor72(controller, layout->leds, layout->direction, layout->dual_block));
|
||||
}
|
||||
else
|
||||
{
|
||||
/*-------------------------------------------------*\
|
||||
| 0x71 family (78 byte buffer), handled by the |
|
||||
| legacy controller as a plain line. For an owner |
|
||||
| who wants to bring one onto this controller: same |
|
||||
| operative block 12, but the second colour array |
|
||||
| is at index 50 (not 95) and store-flash at 77. |
|
||||
| RightToLeft mirroring applies. version, LEDs, |
|
||||
| direction: |
|
||||
| 1, 9, RightToLeft (early/generic) |
|
||||
| 2, 7, LeftToRight (malformed stub, skip) |
|
||||
| 3, 9, RightToLeft (early/generic) |
|
||||
| 4, 9, LeftToRight (early/generic) |
|
||||
| 6, 9, UpToDown MAG270CR |
|
||||
| 7, 7, LeftToRight MAG251RX |
|
||||
\*-------------------------------------------------*/
|
||||
detected_controllers.push_back(new RGBController_MSIMonitor(controller));
|
||||
}
|
||||
}
|
||||
|
||||
return(detected_controllers);
|
||||
|
||||
@@ -9,12 +9,8 @@
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "RGBController_MSIMonitor.h"
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name MSIMonitor
|
||||
@category Accessory
|
||||
@@ -112,10 +108,6 @@ RGBController_MSIMonitor::RGBController_MSIMonitor(MSIMonitorController* control
|
||||
|
||||
RGBController_MSIMonitor::~RGBController_MSIMonitor()
|
||||
{
|
||||
keepalive_thread_run = 0;
|
||||
keepalive_thread->join();
|
||||
delete keepalive_thread;
|
||||
|
||||
Shutdown();
|
||||
|
||||
delete controller;
|
||||
@@ -145,7 +137,6 @@ void RGBController_MSIMonitor::SetupZones()
|
||||
|
||||
void RGBController_MSIMonitor::DeviceUpdateLEDs()
|
||||
{
|
||||
last_update_time = std::chrono::steady_clock::now();
|
||||
controller->Set(modes[active_mode].value, colors, active_mode == 0 ? 0x00 : 0x01);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_MSIMonitor.cpp |
|
||||
| RGBController_MSIMonitor.h |
|
||||
| |
|
||||
| RGBController for MSI monitor (gaming controller) |
|
||||
| |
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <chrono>
|
||||
#include "RGBController.h"
|
||||
#include "MSIMonitorController.h"
|
||||
|
||||
@@ -31,9 +30,4 @@ public:
|
||||
|
||||
private:
|
||||
MSIMonitorController* controller;
|
||||
std::thread* keepalive_thread;
|
||||
std::atomic<bool> keepalive_thread_run;
|
||||
std::chrono::time_point<std::chrono::steady_clock> last_update_time;
|
||||
|
||||
void KeepaliveThread();
|
||||
};
|
||||
|
||||
570
Controllers/MSIMonitorController/RGBController_MSIMonitor72.cpp
Normal file
570
Controllers/MSIMonitorController/RGBController_MSIMonitor72.cpp
Normal file
@@ -0,0 +1,570 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_MSIMonitor72.cpp |
|
||||
| |
|
||||
| RGBController for MSI monitors using the 0x72 dual |
|
||||
| control block layout (MPG 322URX QD-OLED) |
|
||||
| |
|
||||
| Ken Sanislo 19 Jul 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#include <algorithm>
|
||||
#include "RGBController_MSIMonitor72.h"
|
||||
|
||||
/**------------------------------------------------------------------*\
|
||||
@name MSIMonitor72
|
||||
@category Accessory
|
||||
@type USB
|
||||
@save :robot:
|
||||
@direct :white_check_mark:
|
||||
@effects :white_check_mark:
|
||||
@detectors DetectMSIMonitorController
|
||||
@comment Developed with MSI MPG 322URX QD-OLED
|
||||
\*-------------------------------------------------------------------*/
|
||||
RGBController_MSIMonitor72::RGBController_MSIMonitor72(MSIMonitorController* controller_ptr, unsigned int count, unsigned int direction, bool dual)
|
||||
{
|
||||
controller = controller_ptr;
|
||||
led_count = count;
|
||||
reverse_order = (direction == MSI_MONITOR_72_DIR_RIGHT_TO_LEFT);
|
||||
dual_block = dual;
|
||||
|
||||
name = controller->GetNameString();
|
||||
vendor = "MSI";
|
||||
type = DEVICE_TYPE_MONITOR;
|
||||
description = "MSI Monitor (Gaming Controller)";
|
||||
location = controller->GetDeviceLocation();
|
||||
serial = controller->GetSerialString();
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| This layout has no Advanced mode, so Direct is Static |
|
||||
| driven from the inline per LED colour arrays. |
|
||||
\*-----------------------------------------------------*/
|
||||
mode Direct;
|
||||
Direct.name = "Direct";
|
||||
Direct.value = MSI_MONITOR_72_MODE_STATIC;
|
||||
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Direct.brightness_min = 0;
|
||||
Direct.brightness_max = 100;
|
||||
Direct.brightness = 100;
|
||||
Direct.color_mode = MODE_COLORS_PER_LED;
|
||||
modes.push_back(Direct);
|
||||
|
||||
mode Static;
|
||||
Static.name = "Static";
|
||||
Static.value = MSI_MONITOR_72_MODE_STATIC;
|
||||
Static.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Static.colors_min = 1;
|
||||
Static.colors_max = 1;
|
||||
Static.colors.resize(1);
|
||||
Static.brightness_min = 0;
|
||||
Static.brightness_max = 100;
|
||||
Static.brightness = 100;
|
||||
Static.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Static);
|
||||
|
||||
mode Breathing;
|
||||
Breathing.name = "Breathing";
|
||||
Breathing.value = MSI_MONITOR_72_MODE_BREATHING;
|
||||
Breathing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Breathing.colors_min = 1;
|
||||
Breathing.colors_max = 1;
|
||||
Breathing.colors.resize(1);
|
||||
Breathing.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Breathing.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Breathing.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Breathing.brightness_min = 0;
|
||||
Breathing.brightness_max = 100;
|
||||
Breathing.brightness = 100;
|
||||
Breathing.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Breathing);
|
||||
|
||||
mode Flashing;
|
||||
Flashing.name = "Flashing";
|
||||
Flashing.value = MSI_MONITOR_72_MODE_FLASHING;
|
||||
Flashing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Flashing.colors_min = 2;
|
||||
Flashing.colors_max = 2;
|
||||
Flashing.colors.resize(2);
|
||||
Flashing.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Flashing.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Flashing.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Flashing.brightness_min = 0;
|
||||
Flashing.brightness_max = 100;
|
||||
Flashing.brightness = 100;
|
||||
Flashing.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Flashing);
|
||||
|
||||
mode DoubleFlashing;
|
||||
DoubleFlashing.name = "Double Flashing";
|
||||
DoubleFlashing.value = MSI_MONITOR_72_MODE_DOUBLE_FLASHING;
|
||||
DoubleFlashing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
DoubleFlashing.colors_min = 2;
|
||||
DoubleFlashing.colors_max = 2;
|
||||
DoubleFlashing.colors.resize(2);
|
||||
DoubleFlashing.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
DoubleFlashing.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
DoubleFlashing.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
DoubleFlashing.brightness_min = 0;
|
||||
DoubleFlashing.brightness_max = 100;
|
||||
DoubleFlashing.brightness = 100;
|
||||
DoubleFlashing.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(DoubleFlashing);
|
||||
|
||||
mode Lightning;
|
||||
Lightning.name = "Lightning";
|
||||
Lightning.value = MSI_MONITOR_72_MODE_LIGHTNING;
|
||||
Lightning.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Lightning.colors_min = 1;
|
||||
Lightning.colors_max = 1;
|
||||
Lightning.colors.resize(1);
|
||||
Lightning.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Lightning.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Lightning.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Lightning.brightness_min = 0;
|
||||
Lightning.brightness_max = 100;
|
||||
Lightning.brightness = 100;
|
||||
Lightning.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Lightning);
|
||||
|
||||
mode Scanner;
|
||||
Scanner.name = "Scanner";
|
||||
Scanner.value = MSI_MONITOR_72_MODE_SCANNER;
|
||||
Scanner.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Scanner.colors_min = 1;
|
||||
Scanner.colors_max = 1;
|
||||
Scanner.colors.resize(1);
|
||||
Scanner.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Scanner.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Scanner.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Scanner.brightness_min = 0;
|
||||
Scanner.brightness_max = 100;
|
||||
Scanner.brightness = 100;
|
||||
Scanner.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Scanner);
|
||||
|
||||
mode Meteor;
|
||||
Meteor.name = "Meteor";
|
||||
Meteor.value = MSI_MONITOR_72_MODE_METEOR;
|
||||
Meteor.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Meteor.colors_min = 1;
|
||||
Meteor.colors_max = 1;
|
||||
Meteor.colors.resize(1);
|
||||
Meteor.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Meteor.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Meteor.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Meteor.brightness_min = 0;
|
||||
Meteor.brightness_max = 100;
|
||||
Meteor.brightness = 100;
|
||||
Meteor.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Meteor);
|
||||
|
||||
mode WaterDrop;
|
||||
WaterDrop.name = "Water Drop";
|
||||
WaterDrop.value = MSI_MONITOR_72_MODE_WATER_DROP;
|
||||
WaterDrop.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
WaterDrop.colors_min = 1;
|
||||
WaterDrop.colors_max = 1;
|
||||
WaterDrop.colors.resize(1);
|
||||
WaterDrop.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
WaterDrop.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
WaterDrop.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
WaterDrop.brightness_min = 0;
|
||||
WaterDrop.brightness_max = 100;
|
||||
WaterDrop.brightness = 100;
|
||||
WaterDrop.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(WaterDrop);
|
||||
|
||||
mode RainbowMSI;
|
||||
RainbowMSI.name = "Rainbow";
|
||||
RainbowMSI.value = MSI_MONITOR_72_MODE_RAINBOW_MSI;
|
||||
RainbowMSI.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
RainbowMSI.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
RainbowMSI.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
RainbowMSI.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
RainbowMSI.brightness_min = 0;
|
||||
RainbowMSI.brightness_max = 100;
|
||||
RainbowMSI.brightness = 100;
|
||||
RainbowMSI.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(RainbowMSI);
|
||||
|
||||
mode ColorRing;
|
||||
ColorRing.name = "Color Ring";
|
||||
ColorRing.value = MSI_MONITOR_72_MODE_COLOR_RING;
|
||||
ColorRing.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
ColorRing.colors_min = 1;
|
||||
ColorRing.colors_max = 1;
|
||||
ColorRing.colors.resize(1);
|
||||
ColorRing.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
ColorRing.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
ColorRing.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
ColorRing.brightness_min = 0;
|
||||
ColorRing.brightness_max = 100;
|
||||
ColorRing.brightness = 100;
|
||||
ColorRing.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(ColorRing);
|
||||
|
||||
mode Planetary;
|
||||
Planetary.name = "Planetary";
|
||||
Planetary.value = MSI_MONITOR_72_MODE_PLANETARY;
|
||||
Planetary.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Planetary.colors_min = 1;
|
||||
Planetary.colors_max = 1;
|
||||
Planetary.colors.resize(1);
|
||||
Planetary.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Planetary.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Planetary.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Planetary.brightness_min = 0;
|
||||
Planetary.brightness_max = 100;
|
||||
Planetary.brightness = 100;
|
||||
Planetary.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Planetary);
|
||||
|
||||
mode DoubleMeteor;
|
||||
DoubleMeteor.name = "Double Meteor";
|
||||
DoubleMeteor.value = MSI_MONITOR_72_MODE_DOUBLE_METEOR;
|
||||
DoubleMeteor.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
DoubleMeteor.colors_min = 1;
|
||||
DoubleMeteor.colors_max = 1;
|
||||
DoubleMeteor.colors.resize(1);
|
||||
DoubleMeteor.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
DoubleMeteor.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
DoubleMeteor.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
DoubleMeteor.brightness_min = 0;
|
||||
DoubleMeteor.brightness_max = 100;
|
||||
DoubleMeteor.brightness = 100;
|
||||
DoubleMeteor.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(DoubleMeteor);
|
||||
|
||||
mode Energy;
|
||||
Energy.name = "Energy";
|
||||
Energy.value = MSI_MONITOR_72_MODE_ENERGY;
|
||||
Energy.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Energy.colors_min = 1;
|
||||
Energy.colors_max = 1;
|
||||
Energy.colors.resize(1);
|
||||
Energy.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Energy.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Energy.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Energy.brightness_min = 0;
|
||||
Energy.brightness_max = 100;
|
||||
Energy.brightness = 100;
|
||||
Energy.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Energy);
|
||||
|
||||
mode Blink;
|
||||
Blink.name = "Blink";
|
||||
Blink.value = MSI_MONITOR_72_MODE_BLINK;
|
||||
Blink.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Blink.colors_min = 1;
|
||||
Blink.colors_max = 1;
|
||||
Blink.colors.resize(1);
|
||||
Blink.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Blink.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Blink.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Blink.brightness_min = 0;
|
||||
Blink.brightness_max = 100;
|
||||
Blink.brightness = 100;
|
||||
Blink.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Blink);
|
||||
|
||||
mode Clock;
|
||||
Clock.name = "Clock";
|
||||
Clock.value = MSI_MONITOR_72_MODE_CLOCK;
|
||||
Clock.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Clock.colors_min = 1;
|
||||
Clock.colors_max = 1;
|
||||
Clock.colors.resize(1);
|
||||
Clock.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Clock.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Clock.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Clock.brightness_min = 0;
|
||||
Clock.brightness_max = 100;
|
||||
Clock.brightness = 100;
|
||||
Clock.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Clock);
|
||||
|
||||
mode ColorPulse;
|
||||
ColorPulse.name = "Color Pulse";
|
||||
ColorPulse.value = MSI_MONITOR_72_MODE_COLOR_PULSE;
|
||||
ColorPulse.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
ColorPulse.colors_min = 1;
|
||||
ColorPulse.colors_max = 1;
|
||||
ColorPulse.colors.resize(1);
|
||||
ColorPulse.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
ColorPulse.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
ColorPulse.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
ColorPulse.brightness_min = 0;
|
||||
ColorPulse.brightness_max = 100;
|
||||
ColorPulse.brightness = 100;
|
||||
ColorPulse.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(ColorPulse);
|
||||
|
||||
mode ColorShift;
|
||||
ColorShift.name = "Color Shift";
|
||||
ColorShift.value = MSI_MONITOR_72_MODE_COLOR_SHIFT;
|
||||
ColorShift.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
ColorShift.colors_min = 2;
|
||||
ColorShift.colors_max = 2;
|
||||
ColorShift.colors.resize(2);
|
||||
ColorShift.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
ColorShift.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
ColorShift.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
ColorShift.brightness_min = 0;
|
||||
ColorShift.brightness_max = 100;
|
||||
ColorShift.brightness = 100;
|
||||
ColorShift.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(ColorShift);
|
||||
|
||||
mode ColorWave;
|
||||
ColorWave.name = "Color Wave";
|
||||
ColorWave.value = MSI_MONITOR_72_MODE_COLOR_WAVE;
|
||||
ColorWave.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
ColorWave.colors_min = 2;
|
||||
ColorWave.colors_max = 2;
|
||||
ColorWave.colors.resize(2);
|
||||
ColorWave.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
ColorWave.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
ColorWave.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
ColorWave.brightness_min = 0;
|
||||
ColorWave.brightness_max = 100;
|
||||
ColorWave.brightness = 100;
|
||||
ColorWave.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(ColorWave);
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| Mode 24 marquee behaviour is model dependent. On the |
|
||||
| dual block / richer boards it wants the marker bytes |
|
||||
| plus a per LED array of separate colours (a user |
|
||||
| defined marquee). The vendor app does not even offer |
|
||||
| it for version 34, but the firmware still runs it as |
|
||||
| a one colour rolling band, so we expose that. |
|
||||
\*-----------------------------------------------------*/
|
||||
mode Marquee;
|
||||
Marquee.name = "Marquee";
|
||||
Marquee.value = MSI_MONITOR_72_MODE_MARQUEE;
|
||||
Marquee.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Marquee.colors_min = 1;
|
||||
Marquee.colors_max = 1;
|
||||
Marquee.colors.resize(1);
|
||||
Marquee.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Marquee.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Marquee.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Marquee.brightness_min = 0;
|
||||
Marquee.brightness_max = 100;
|
||||
Marquee.brightness = 100;
|
||||
Marquee.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Marquee);
|
||||
|
||||
mode SpectrumCycle;
|
||||
SpectrumCycle.name = "Spectrum Cycle";
|
||||
SpectrumCycle.value = MSI_MONITOR_72_MODE_RAINBOW;
|
||||
SpectrumCycle.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
SpectrumCycle.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
SpectrumCycle.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
SpectrumCycle.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
SpectrumCycle.brightness_min = 0;
|
||||
SpectrumCycle.brightness_max = 100;
|
||||
SpectrumCycle.brightness = 100;
|
||||
SpectrumCycle.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(SpectrumCycle);
|
||||
|
||||
mode RainbowWave;
|
||||
RainbowWave.name = "Rainbow Wave";
|
||||
RainbowWave.value = MSI_MONITOR_72_MODE_RAINBOW_WAVE;
|
||||
RainbowWave.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
RainbowWave.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
RainbowWave.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
RainbowWave.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
RainbowWave.brightness_min = 0;
|
||||
RainbowWave.brightness_max = 100;
|
||||
RainbowWave.brightness = 100;
|
||||
RainbowWave.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(RainbowWave);
|
||||
|
||||
mode Visor;
|
||||
Visor.name = "Visor";
|
||||
Visor.value = MSI_MONITOR_72_MODE_VISOR;
|
||||
Visor.flags = MODE_FLAG_HAS_MODE_SPECIFIC_COLOR | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
Visor.colors_min = 1;
|
||||
Visor.colors_max = 1;
|
||||
Visor.colors.resize(1);
|
||||
Visor.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
Visor.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
Visor.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
Visor.brightness_min = 0;
|
||||
Visor.brightness_max = 100;
|
||||
Visor.brightness = 100;
|
||||
Visor.color_mode = MODE_COLORS_MODE_SPECIFIC;
|
||||
modes.push_back(Visor);
|
||||
|
||||
mode JRainbow;
|
||||
JRainbow.name = "JRainbow";
|
||||
JRainbow.value = MSI_MONITOR_72_MODE_JRAINBOW;
|
||||
JRainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
JRainbow.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
JRainbow.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
JRainbow.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
JRainbow.brightness_min = 0;
|
||||
JRainbow.brightness_max = 100;
|
||||
JRainbow.brightness = 100;
|
||||
JRainbow.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(JRainbow);
|
||||
|
||||
mode RainbowFlash;
|
||||
RainbowFlash.name = "Rainbow Flashing";
|
||||
RainbowFlash.value = MSI_MONITOR_72_MODE_RAINBOW_FLASH;
|
||||
RainbowFlash.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
RainbowFlash.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
RainbowFlash.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
RainbowFlash.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
RainbowFlash.brightness_min = 0;
|
||||
RainbowFlash.brightness_max = 100;
|
||||
RainbowFlash.brightness = 100;
|
||||
RainbowFlash.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(RainbowFlash);
|
||||
|
||||
mode RainbowDblFlash;
|
||||
RainbowDblFlash.name = "Rainbow Double Flashing";
|
||||
RainbowDblFlash.value = MSI_MONITOR_72_MODE_RAINBOW_DBLFLASH;
|
||||
RainbowDblFlash.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
RainbowDblFlash.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
RainbowDblFlash.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
RainbowDblFlash.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
RainbowDblFlash.brightness_min = 0;
|
||||
RainbowDblFlash.brightness_max = 100;
|
||||
RainbowDblFlash.brightness = 100;
|
||||
RainbowDblFlash.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(RainbowDblFlash);
|
||||
|
||||
mode RainbowLine;
|
||||
RainbowLine.name = "Rainbow Line";
|
||||
RainbowLine.value = MSI_MONITOR_72_MODE_RAINBOW_LINE;
|
||||
RainbowLine.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_MANUAL_SAVE;
|
||||
RainbowLine.speed_min = MSI_MONITOR_72_SPEED_LOW;
|
||||
RainbowLine.speed_max = MSI_MONITOR_72_SPEED_HIGH;
|
||||
RainbowLine.speed = MSI_MONITOR_72_SPEED_MEDIUM;
|
||||
RainbowLine.brightness_min = 0;
|
||||
RainbowLine.brightness_max = 100;
|
||||
RainbowLine.brightness = 100;
|
||||
RainbowLine.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(RainbowLine);
|
||||
|
||||
mode Off;
|
||||
Off.name = "Off";
|
||||
Off.value = MSI_MONITOR_72_MODE_OFF;
|
||||
Off.flags = MODE_FLAG_MANUAL_SAVE;
|
||||
Off.color_mode = MODE_COLORS_NONE;
|
||||
modes.push_back(Off);
|
||||
|
||||
SetupZones();
|
||||
}
|
||||
|
||||
RGBController_MSIMonitor72::~RGBController_MSIMonitor72()
|
||||
{
|
||||
Shutdown();
|
||||
|
||||
delete controller;
|
||||
}
|
||||
|
||||
void RGBController_MSIMonitor72::SetupZones()
|
||||
{
|
||||
zone new_zone;
|
||||
|
||||
new_zone.name = "Rear";
|
||||
new_zone.type = ZONE_TYPE_LINEAR;
|
||||
new_zone.leds_min = led_count;
|
||||
new_zone.leds_max = led_count;
|
||||
new_zone.leds_count = led_count;
|
||||
|
||||
zones.emplace_back(new_zone);
|
||||
|
||||
for(unsigned int led_idx = 0; led_idx < led_count; led_idx++)
|
||||
{
|
||||
led new_led;
|
||||
new_led.name = "LED " + std::to_string(led_idx + 1);
|
||||
leds.push_back(new_led);
|
||||
}
|
||||
|
||||
SetupColors();
|
||||
}
|
||||
|
||||
void RGBController_MSIMonitor72::DeviceUpdateLEDs()
|
||||
{
|
||||
DeviceUpdateMode();
|
||||
}
|
||||
|
||||
void RGBController_MSIMonitor72::DeviceUpdateZoneLEDs(int /*zone*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_MSIMonitor72::DeviceUpdateSingleLED(int /*led*/)
|
||||
{
|
||||
DeviceUpdateLEDs();
|
||||
}
|
||||
|
||||
void RGBController_MSIMonitor72::ApplyMode(bool save)
|
||||
{
|
||||
const mode& active = modes[active_mode];
|
||||
|
||||
RGBColor color1 = 0;
|
||||
RGBColor color2 = 0;
|
||||
bool user_palette = false;
|
||||
std::vector<RGBColor> led_colors;
|
||||
|
||||
if(active.color_mode == MODE_COLORS_PER_LED)
|
||||
{
|
||||
user_palette = true;
|
||||
led_colors = colors;
|
||||
|
||||
if(led_colors.size() > 0)
|
||||
{
|
||||
color1 = led_colors[0];
|
||||
}
|
||||
}
|
||||
else if(active.color_mode == MODE_COLORS_MODE_SPECIFIC)
|
||||
{
|
||||
user_palette = true;
|
||||
|
||||
if(active.colors.size() > 0)
|
||||
{
|
||||
color1 = active.colors[0];
|
||||
|
||||
if(active.colors.size() > 1)
|
||||
{
|
||||
color2 = active.colors[1];
|
||||
}
|
||||
}
|
||||
|
||||
led_colors.assign(led_count, color1);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------*\
|
||||
| RightToLeft layouts start at the right end, so mirror |
|
||||
| the per LED order to keep OpenRGB LED 0 on the left. |
|
||||
| Uniform colour modes are unaffected by the order. |
|
||||
\*-----------------------------------------------------*/
|
||||
if(reverse_order)
|
||||
{
|
||||
std::reverse(led_colors.begin(), led_colors.end());
|
||||
}
|
||||
|
||||
controller->SetMode72((uint8_t)active.value, (uint8_t)active.speed, (uint8_t)active.brightness, color1, color2, user_palette, save, led_colors, dual_block);
|
||||
}
|
||||
|
||||
void RGBController_MSIMonitor72::DeviceUpdateMode()
|
||||
{
|
||||
/*-----------------------------------------------------*\
|
||||
| Updates are volatile. Persisting to flash is the |
|
||||
| Save To Device button (DeviceSaveMode), so live edits |
|
||||
| do not burn flash write cycles. |
|
||||
\*-----------------------------------------------------*/
|
||||
ApplyMode(false);
|
||||
}
|
||||
|
||||
void RGBController_MSIMonitor72::DeviceSaveMode()
|
||||
{
|
||||
ApplyMode(true);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*---------------------------------------------------------*\
|
||||
| RGBController_MSIMonitor72.h |
|
||||
| |
|
||||
| RGBController for MSI monitors using the 0x72 dual |
|
||||
| control block layout (MPG 322URX QD-OLED) |
|
||||
| |
|
||||
| Ken Sanislo 19 Jul 2026 |
|
||||
| |
|
||||
| This file is part of the OpenRGB project |
|
||||
| SPDX-License-Identifier: GPL-2.0-or-later |
|
||||
\*---------------------------------------------------------*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "RGBController.h"
|
||||
#include "MSIMonitorController.h"
|
||||
|
||||
class RGBController_MSIMonitor72 : public RGBController
|
||||
{
|
||||
public:
|
||||
RGBController_MSIMonitor72(MSIMonitorController* controller_ptr, unsigned int count, unsigned int direction, bool dual);
|
||||
~RGBController_MSIMonitor72();
|
||||
|
||||
void SetupZones();
|
||||
|
||||
void DeviceUpdateLEDs();
|
||||
void DeviceUpdateZoneLEDs(int zone);
|
||||
void DeviceUpdateSingleLED(int led);
|
||||
|
||||
void DeviceUpdateMode();
|
||||
void DeviceSaveMode();
|
||||
|
||||
private:
|
||||
void ApplyMode(bool save);
|
||||
|
||||
MSIMonitorController* controller;
|
||||
unsigned int led_count;
|
||||
bool reverse_order;
|
||||
bool dual_block;
|
||||
};
|
||||
Reference in New Issue
Block a user