/*---------------------------------------------------------*\ | MSIMonitorController.h | | | | 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 | \*---------------------------------------------------------*/ #pragma once #include #include #include "RGBController.h" #define MSI_MONITOR_LEDS 9 #define MSI_MONITOR_PACKET_SIZE 78 /*---------------------------------------------------------*\ | This panel holds each feature report outstanding for | | tens of ms while its MCU applies the frame, pinning the | | shared control pipe. Idle briefly after each write so | | other non periodic traffic on the bus is not starved. | | See SendFeatureReport. | \*---------------------------------------------------------*/ #define MSI_MONITOR_PIPE_IDLE_MS 5 /*---------------------------------------------------------*\ | 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, MSI_MONITOR_STATIC_MODE_VALUE = 0x01, MSI_MONITOR_BREATHING_MODE_VALUE = 0x02, MSI_MONITOR_FLASHING_MODE_VALUE = 0x03, MSI_MONITOR_LIGHTNING_MODE_VALUE = 0x05, MSI_MONITOR_MARQUEE_MODE_VALUE = 0x06, MSI_MONITOR_METEOR_MODE_VALUE = 0x08, MSI_MONITOR_RAINBOW_MODE_VALUE = 0x1A, 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: MSIMonitorController(hid_device *dev_handle, const hid_device_info &info, std::string dev_name); ~MSIMonitorController(); std::string GetDeviceLocation(); std::string GetFirmwareVersion(); std::string GetNameString(); std::string GetSerialString(); void Set(uint8_t mode_value, const std::vector 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& led_colors, bool fill_both_arrays); private: void SendFeatureReport(uint8_t *data, size_t length); hid_device *dev; std::string description; std::string location; std::string name; std::string version; };