diff --git a/Controllers/MSIMysticLightController/MSIMysticLight112Controller.cpp b/Controllers/MSIMysticLightController/MSIMysticLight112Controller.cpp new file mode 100644 index 00000000..35fa0ca0 --- /dev/null +++ b/Controllers/MSIMysticLightController/MSIMysticLight112Controller.cpp @@ -0,0 +1,472 @@ +/*-----------------------------------------*\ +| MSIMysticLight112Controller.cpp | +| | +| Driver for MSI Mystic Light (112-byte) | +| USB lighting controller | +| | +| thombo 12/17/2022 | +\*-----------------------------------------*/ + +#include "MSIMysticLight112Controller.h" +#include +#include +#include + + +#define BITSET(val, bit, pos) ((unsigned char)std::bitset<8>(val).set((pos), (bit)).to_ulong()) + + +struct Config +{ + unsigned short pid; // PID of the board + size_t numof_onboard_leds; // number of onboard leds + const std::vector* supported_zones; // pointer to vector of supported zones +}; + +const std::vector zones_set = +{ + MSI_ZONE_J_RGB_1, + MSI_ZONE_J_RAINBOW_1, + MSI_ZONE_J_CORSAIR, + MSI_ZONE_ON_BOARD_LED_0 +}; + + +MSIMysticLight112Controller::MSIMysticLight112Controller + ( + hid_device* handle, + const char *path + ) +{ + dev = handle; + + if(dev) + { + location = path; + + ReadName(); + ReadSerial(); + ReadFwVersion(); + ReadSettings(); + } + + /*-----------------------------------------*\ + | Initialize save flag | + \*-----------------------------------------*/ + data.save_data = 0; + data.on_board_led.colorFlags = 0x81; // force MS bit of color flags to 1 to have expected zone control + + /*-----------------------------------------*\ + | Initialize zone based per LED data | + \*-----------------------------------------*/ + numof_onboard_leds = 7; + supported_zones = &zones_set; + + zone_based_per_led_data.j_rgb_1.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.j_rgb_1.colorFlags = BITSET(zone_based_per_led_data.j_rgb_1.colorFlags, true, 7u); + zone_based_per_led_data.j_rainbow_1.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.j_rainbow_1.colorFlags = BITSET(zone_based_per_led_data.j_rainbow_1.colorFlags, true, 7u); + zone_based_per_led_data.on_board_led.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.on_board_led.colorFlags = BITSET(zone_based_per_led_data.on_board_led.colorFlags, true, 7u); + zone_based_per_led_data.on_board_led_1.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.on_board_led_1.colorFlags = BITSET(zone_based_per_led_data.on_board_led_1.colorFlags, true, 7u); + zone_based_per_led_data.on_board_led_2.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.on_board_led_2.colorFlags = BITSET(zone_based_per_led_data.on_board_led_2.colorFlags, true, 7u); + zone_based_per_led_data.on_board_led_3.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.on_board_led_3.colorFlags = BITSET(zone_based_per_led_data.on_board_led_3.colorFlags, true, 7u); + zone_based_per_led_data.on_board_led_4.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.on_board_led_4.colorFlags = BITSET(zone_based_per_led_data.on_board_led_4.colorFlags, true, 7u); + zone_based_per_led_data.on_board_led_5.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2; + zone_based_per_led_data.on_board_led_5.colorFlags = BITSET(zone_based_per_led_data.on_board_led_5.colorFlags, true, 7u); + zone_based_per_led_data.on_board_led_6.speedAndBrightnessFlags = MSI_BRIGHTNESS_LEVEL_100 << 2 << 2; + zone_based_per_led_data.on_board_led_6.colorFlags = BITSET(zone_based_per_led_data.on_board_led_6.colorFlags, true, 7u); + zone_based_per_led_data.save_data = 0; + + direct_mode = false; +} + +MSIMysticLight112Controller::~MSIMysticLight112Controller() +{ + hid_close(dev); +} + +void MSIMysticLight112Controller::SetMode + ( + MSI_ZONE zone, + MSI_MODE mode, + MSI_SPEED speed, + MSI_BRIGHTNESS brightness, + bool rainbow_color + ) +{ + ZoneData* zone_data = GetZoneData(data, zone); + + if(zone_data == nullptr) + { + return; + } + + if (zone <= MSI_ZONE_ON_BOARD_LED_0) + { + zone_data->effect = mode; + zone_data->speedAndBrightnessFlags = (brightness << 2) | (speed & 0x03); + zone_data->colorFlags = BITSET(zone_data->colorFlags, !rainbow_color, 7u); + zone_data->padding = 0x00; + + if(mode > MSI_MODE_DOUBLE_FLASHING) + { + zone_data->speedAndBrightnessFlags |= SYNC_SETTING_JRGB; + zone_data->colorFlags |= SYNC_SETTING_ONBOARD; + } + else + { + zone_data->speedAndBrightnessFlags &= ~SYNC_SETTING_JRGB; + zone_data->colorFlags &= ~SYNC_SETTING_ONBOARD; + } + } + + if((zone >= MSI_ZONE_ON_BOARD_LED_0) && (mode <= MSI_MODE_DOUBLE_FLASHING)) + { + zone_data = GetZoneData(data, (MSI_ZONE)((int)zone + 1)); + + if(zone_data != nullptr) + { + zone_data->effect = mode; + zone_data->speedAndBrightnessFlags = (brightness << 2) | (speed & 0x03); + zone_data->colorFlags = BITSET(zone_data->colorFlags, !rainbow_color, 7u); + zone_data->padding = 0x00; + } + } +} + +std::string MSIMysticLight112Controller::GetDeviceName() +{ + return name; +} + +std::string MSIMysticLight112Controller::GetFWVersion() +{ + std::string firmware_version; + firmware_version = "APROM: " + version_APROM + ", LDROM: " + version_LDROM; + return firmware_version; +} + +std::string MSIMysticLight112Controller::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string MSIMysticLight112Controller::GetSerial() +{ + return chip_id; +} + +bool MSIMysticLight112Controller::ReadSettings() +{ + /*-----------------------------------------------------*\ + | Read packet from hardware, return true if successful | + \*-----------------------------------------------------*/ + return(hid_get_feature_report(dev, (unsigned char*)&data, sizeof(data)) == sizeof data); +} + +bool MSIMysticLight112Controller::Update + ( + bool save + ) +{ + /*-----------------------------------------------------*\ + | Send packet to hardware, return true if successful | + \*-----------------------------------------------------*/ + if(direct_mode) + { + return (hid_send_feature_report(dev, (unsigned char*)&zone_based_per_led_data, sizeof(zone_based_per_led_data)) == sizeof(zone_based_per_led_data)); + } + else + { + data.save_data = save; + return (hid_send_feature_report(dev, (unsigned char*)&data, sizeof(data)) == sizeof(data)); + } +} + +void MSIMysticLight112Controller::SetZoneColor + ( + MSI_ZONE zone, + unsigned char red1, + unsigned char grn1, + unsigned char blu1, + unsigned char red2, + unsigned char grn2, + unsigned char blu2 + ) +{ + ZoneData* zone_data = GetZoneData(data, zone); + + if(zone_data == nullptr) + { + return; + } + + if (zone <= MSI_ZONE_ON_BOARD_LED_0) + { + zone_data->color.R = red1; + zone_data->color.G = grn1; + zone_data->color.B = blu1; + zone_data->color2.R = red2; + zone_data->color2.G = grn2; + zone_data->color2.B = blu2; + } + + if(zone >= MSI_ZONE_ON_BOARD_LED_0) + { + zone_data = GetZoneData(data, (MSI_ZONE)((int)zone + 1)); + + if(zone_data != nullptr) + { + zone_data->color.R = red1; + zone_data->color.G = grn1; + zone_data->color.B = blu1; + zone_data->color2.R = red2; + zone_data->color2.G = grn2; + zone_data->color2.B = blu2; + } + } +} + +void MSIMysticLight112Controller::SetLedColor + ( + MSI_ZONE zone, + unsigned char red, + unsigned char grn, + unsigned char blu + ) +{ + if(zone >= MSI_ZONE_ON_BOARD_LED_0) + { + zone = (MSI_ZONE)((int)zone + 1); + } + + ZoneData *zone_data = GetZoneData(zone_based_per_led_data, zone); + + if(zone_data == nullptr) + { + return; + } + + zone_data->color.R = red; + zone_data->color.G = grn; + zone_data->color.B = blu; + zone_data->color2.R = red; + zone_data->color2.G = grn; + zone_data->color2.B = blu; +} + +ZoneData *MSIMysticLight112Controller::GetZoneData + ( + FeaturePacket_112& data_packet, + MSI_ZONE zone + ) +{ + switch(zone) + { + case MSI_ZONE_J_RGB_1: + return &data_packet.j_rgb_1; + case MSI_ZONE_J_RAINBOW_1: + return &data_packet.j_rainbow_1; + case MSI_ZONE_ON_BOARD_LED_0: + return &data_packet.on_board_led; + case MSI_ZONE_ON_BOARD_LED_1: + return &data_packet.on_board_led_1; + case MSI_ZONE_ON_BOARD_LED_2: + return &data_packet.on_board_led_2; + case MSI_ZONE_ON_BOARD_LED_3: + return &data_packet.on_board_led_3; + case MSI_ZONE_ON_BOARD_LED_4: + return &data_packet.on_board_led_4; + case MSI_ZONE_ON_BOARD_LED_5: + return &data_packet.on_board_led_5; + case MSI_ZONE_ON_BOARD_LED_6: + return &data_packet.on_board_led_6; + case MSI_ZONE_J_CORSAIR: + return &data_packet.j_corsair_1; + default: + break; + } + + return nullptr; +} + +bool MSIMysticLight112Controller::ReadFwVersion() +{ + unsigned char request[64]; + unsigned char response[64]; + int ret_val = 64; + + /*-----------------------------------------------------*\ + | First read the APROM | + | Checksum also available at report ID 180, with MSB | + | stored at index 0x08 and LSB at 0x09 | + \*-----------------------------------------------------*/ + + /*-----------------------------------------------------*\ + | Zero out buffers | + \*-----------------------------------------------------*/ + memset(request, 0x00, sizeof(request)); + memset(response, 0x00, sizeof(response)); + + /*-----------------------------------------------------*\ + | Set up APROM Firmware Version Request packet | + \*-----------------------------------------------------*/ + request[0x00] = 0x01; + request[0x01] = 0xB0; + + /*-----------------------------------------------------*\ + | Fill request from 0x02 to 0x61 with 0xCC | + \*-----------------------------------------------------*/ + memset(&request[0x02], 0xCC, sizeof(request) - 2); + + /*-----------------------------------------------------*\ + | Send request and receive response packets | + \*-----------------------------------------------------*/ + ret_val &= hid_write(dev, request, 64); + ret_val &= hid_read(dev, response, 64); + + /*-----------------------------------------------------*\ + | Extract high and low values from response | + \*-----------------------------------------------------*/ + unsigned char highValue = response[2] >> 4; + unsigned char lowValue = response[2] & 0x0F; + + /*-----------------------------------------------------*\ + | Build firmware string . | + \*-----------------------------------------------------*/ + version_APROM = std::to_string((int)highValue).append(".").append(std::to_string((int)lowValue)); + + /*-----------------------------------------------------*\ + | First read the LDROM | + | Checksum also available at report ID 184, with MSB | + | stored at index 0x08 and LSB at 0x09 | + \*-----------------------------------------------------*/ + + /*-----------------------------------------------------*\ + | Set up LDROM Firmware Version Request packet | + \*-----------------------------------------------------*/ + request[0x00] = 0x01; + request[0x01] = 0xB6; + + /*-----------------------------------------------------*\ + | Send request and receive response packets | + \*-----------------------------------------------------*/ + ret_val &= hid_write(dev, request, 64); + ret_val &= hid_read(dev, response, 64); + + /*-----------------------------------------------------*\ + | Extract high and low values from response | + \*-----------------------------------------------------*/ + highValue = response[2] >> 4; + lowValue = response[2] & 0x0F; + + /*-----------------------------------------------------*\ + | Build firmware string . | + \*-----------------------------------------------------*/ + version_LDROM = std::to_string((int)highValue).append(".").append(std::to_string((int)lowValue)); + + /*-----------------------------------------------------*\ + | If return value is zero it means an HID transfer | + | failed | + \*-----------------------------------------------------*/ + return(ret_val > 0); +} + +void MSIMysticLight112Controller::ReadSerial() +{ + wchar_t serial[256]; + + /*-----------------------------------------------------*\ + | Get the serial number string from HID | + \*-----------------------------------------------------*/ + hid_get_serial_number_string(dev, serial, 256); + + /*-----------------------------------------------------*\ + | Convert wchar_t into std::wstring into std::string | + \*-----------------------------------------------------*/ + std::wstring wserial = std::wstring(serial); + chip_id = std::string(wserial.begin(), wserial.end()); +} + +void MSIMysticLight112Controller::ReadName() +{ + wchar_t tname[256]; + + /*-----------------------------------------------------*\ + | Get the manufacturer string from HID | + \*-----------------------------------------------------*/ + hid_get_manufacturer_string(dev, tname, 256); + + /*-----------------------------------------------------*\ + | Convert wchar_t into std::wstring into std::string | + \*-----------------------------------------------------*/ + std::wstring wname = std::wstring(tname); + name = std::string(wname.begin(), wname.end()); + + /*-----------------------------------------------------*\ + | Get the product string from HID | + \*-----------------------------------------------------*/ + hid_get_product_string(dev, tname, 256); + + /*-----------------------------------------------------*\ + | Append the product string to the manufacturer string | + \*-----------------------------------------------------*/ + wname = std::wstring(tname); + name.append(" ").append(std::string(wname.begin(), wname.end())); +} + +MSI_MODE MSIMysticLight112Controller::GetMode() +{ + return (MSI_MODE)data.on_board_led.effect; +} + +void MSIMysticLight112Controller::GetMode + ( + MSI_ZONE zone, + MSI_MODE &mode, + MSI_SPEED &speed, + MSI_BRIGHTNESS &brightness, + bool &rainbow_color, + unsigned int &color + ) +{ + /*-----------------------------------------------------*\ + | Get data for given zone | + \*-----------------------------------------------------*/ + ZoneData *zone_data = GetZoneData(data, zone); + + /*-----------------------------------------------------*\ + | Return if zone is invalid | + \*-----------------------------------------------------*/ + if(zone_data == nullptr) + { + return; + } + + /*-----------------------------------------------------*\ + | Update pointers with data | + \*-----------------------------------------------------*/ + mode = (MSI_MODE)zone_data->effect; + speed = (MSI_SPEED)(zone_data->speedAndBrightnessFlags & 0x03); + brightness = (MSI_BRIGHTNESS)((zone_data->speedAndBrightnessFlags >> 2) & 0x1F); + rainbow_color = (zone_data->colorFlags & 0x80) == 0 ? true : false; + color = ToRGBColor(zone_data->color.R, zone_data->color.G, zone_data->color.B); +} + +void MSIMysticLight112Controller::SetDirectMode + ( + bool mode + ) +{ + direct_mode = mode; +} + +size_t MSIMysticLight112Controller::GetMaxOnboardLeds() +{ + return numof_onboard_leds; +} diff --git a/Controllers/MSIMysticLightController/MSIMysticLight112Controller.h b/Controllers/MSIMysticLightController/MSIMysticLight112Controller.h new file mode 100644 index 00000000..7997de7f --- /dev/null +++ b/Controllers/MSIMysticLightController/MSIMysticLight112Controller.h @@ -0,0 +1,111 @@ +/*-----------------------------------------*\ +| MSIMysticLight112Controller.h | +| | +| Definitions and types for MSI Mystic | +| Light (112-byte) USB lighting controllers| +| | +| thombo 12/17/2022 | +\*-----------------------------------------*/ + +#include "MSIMysticLightCommon.h" +#include "RGBController.h" +#include +#include +#include + +#pragma once + +class MSIMysticLight112Controller +{ +public: + MSIMysticLight112Controller + ( + hid_device* handle, + const char *path + ); + ~MSIMysticLight112Controller(); + + void SetMode + ( + MSI_ZONE zone, + MSI_MODE mode, + MSI_SPEED speed, + MSI_BRIGHTNESS brightness, + bool rainbow_color + ); + + MSI_MODE GetMode(); + + void GetMode + ( + MSI_ZONE zone, + MSI_MODE &mode, + MSI_SPEED &speed, + MSI_BRIGHTNESS &brightness, + bool &rainbow_color, + unsigned int &color + ); + + void SetZoneColor + ( + MSI_ZONE zone, + unsigned char red1, + unsigned char grn1, + unsigned char blu1, + unsigned char red2, + unsigned char grn2, + unsigned char blu2 + ); + + void SetLedColor + ( + MSI_ZONE zone, + unsigned char red, + unsigned char grn, + unsigned char blu + ); + + bool Update + ( + bool save + ); + + std::string GetDeviceName(); + std::string GetDeviceLocation(); + std::string GetFWVersion(); + std::string GetSerial(); + + + void SetDirectMode + ( + bool mode + ); + bool IsDirectModeActive() { return direct_mode; } + size_t GetMaxOnboardLeds(); + const std::vector* + GetSupportedZones() { return supported_zones; } + +private: + bool ReadSettings(); + bool ReadFwVersion(); + void ReadSerial(); + void ReadName(); + ZoneData* GetZoneData + ( + FeaturePacket_112& dataPacket, + MSI_ZONE zone + ); + + hid_device* dev; + std::string name; + std::string location; + std::string version_APROM; + std::string version_LDROM; + std::string chip_id; + + FeaturePacket_112 data; + FeaturePacket_112 zone_based_per_led_data; + bool direct_mode; + size_t numof_onboard_leds; + const std::vector* supported_zones; +}; diff --git a/Controllers/MSIMysticLightController/MSIMysticLight185Controller.cpp b/Controllers/MSIMysticLightController/MSIMysticLight185Controller.cpp index b37699cd..66dc39f0 100644 --- a/Controllers/MSIMysticLightController/MSIMysticLight185Controller.cpp +++ b/Controllers/MSIMysticLightController/MSIMysticLight185Controller.cpp @@ -265,6 +265,7 @@ static const Config board_configs[] = { 0x7D77, 6, 0, 0, 2, &zones_set13, MSIMysticLight185Controller::DIRECT_MODE_PER_LED }, // PRO B650M-A WIFI { 0x7D91, 1, 0, 0, 1, &zones_set10, MSIMysticLight185Controller::DIRECT_MODE_PER_LED }, // MAG Z790 TOMAHAWK WIFI { 0x7E06, 0, 0, 0, 2, &zones_set11, MSIMysticLight185Controller::DIRECT_MODE_PER_LED }, // PRO Z790-P WIFI DDR4 + { 0x7E07, 0, 0, 0, 2, &zones_set10, MSIMysticLight185Controller::DIRECT_MODE_PER_LED }, // PRO Z790-A WIFI DDR4 }; diff --git a/Controllers/MSIMysticLightController/MSIMysticLightCommon.h b/Controllers/MSIMysticLightController/MSIMysticLightCommon.h index b99db561..43b2a838 100644 --- a/Controllers/MSIMysticLightController/MSIMysticLightCommon.h +++ b/Controllers/MSIMysticLightController/MSIMysticLightCommon.h @@ -166,6 +166,23 @@ struct FeaturePacket_64 const unsigned char padding[37] = {}; //pad to make the packet size 64 bytes }; +struct FeaturePacket_112 +{ + const unsigned char report_id = 0x52; // Report ID + ZoneData j_rgb_1; // 1 + ZoneData j_rainbow_1; // 11 + ZoneData j_corsair_1; // 21 + ZoneData j_corsair_outerll120; // 31 + ZoneData on_board_led; // 41 + ZoneData on_board_led_1; // 51 + ZoneData on_board_led_2; // 61 + ZoneData on_board_led_3; // 71 + ZoneData on_board_led_4; // 81 + ZoneData on_board_led_5; // 91 + ZoneData on_board_led_6; // 101 + unsigned char save_data = 0; // 111 +}; + struct FeaturePacket_162 { const unsigned char report_id = 0x52; // Report ID diff --git a/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp b/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp index 5c61e43f..51a17e1a 100644 --- a/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp +++ b/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp @@ -1,8 +1,10 @@ #include "Detector.h" #include "MSIMysticLight64Controller.h" +#include "MSIMysticLight112Controller.h" #include "MSIMysticLight162Controller.h" #include "MSIMysticLight185Controller.h" #include "RGBController_MSIMysticLight64.h" +#include "RGBController_MSIMysticLight112.h" #include "RGBController_MSIMysticLight162.h" #include "RGBController_MSIMysticLight185.h" #include "dependencies/dmiinfo.h" @@ -55,6 +57,13 @@ void DetectMSIMysticLightControllers rgb_controller->name = "MSI " + dmi.getMainboard(); ResourceManager::get()->RegisterRGBController(rgb_controller); } + else if((packet_length >= sizeof(FeaturePacket_112)) && (packet_length <= (sizeof(FeaturePacket_112) + 1))) + { + MSIMysticLight112Controller* controller = new MSIMysticLight112Controller(dev, info->path); + RGBController_MSIMysticLight112* rgb_controller = new RGBController_MSIMysticLight112(controller); + rgb_controller->name = "MSI " + dmi.getMainboard(); + ResourceManager::get()->RegisterRGBController(rgb_controller); + } else // no supported length returned { std::string name = "MSI " + dmi.getMainboard(); @@ -151,6 +160,7 @@ REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_7D69", DetectMSIMysticLightCont REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_7D77", DetectMSIMysticLightControllers, MSI_USB_VID, 0x7D77, 0x0001, 0x00); REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_7D91", DetectMSIMysticLightControllers, MSI_USB_VID, 0x7D91, 0x0001, 0x00); REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_7E06", DetectMSIMysticLightControllers, MSI_USB_VID, 0x7E06, 0x0001, 0x00); +REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_7E07", DetectMSIMysticLightControllers, MSI_USB_VID, 0x7E07, 0x0001, 0x00); #ifdef ENABLE_UNTESTED_MYSTIC_LIGHT REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_3EA4", DetectMSIMysticLightControllers, MSI_USB_VID, 0x3EA4, 0x0001, 0x00); diff --git a/Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.cpp b/Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.cpp new file mode 100644 index 00000000..d8d2bb7b --- /dev/null +++ b/Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.cpp @@ -0,0 +1,388 @@ +/*-----------------------------------------*\ +| RGBController_MSIMysticLight112.cpp | +| | +| Generic RGB Interface for OpenRGB | +| MSI Mystic Light (112-byte) USB Driver | +| | +| thombo 12/17/2022 | +\*-----------------------------------------*/ + +#include "RGBController_MSIMysticLight112.h" + + +struct ZoneDescription +{ + std::string name; + MSI_ZONE zone_type; +}; + +#define NUMOF_ZONES (sizeof(led_zones) / sizeof(ZoneDescription)) + +const ZoneDescription led_zones[] = +{ + ZoneDescription{ "JRGB1", MSI_ZONE_J_RGB_1 }, + ZoneDescription{ "JRAINBOW1", MSI_ZONE_J_RAINBOW_1 }, + ZoneDescription{ "JCORSAIR", MSI_ZONE_J_CORSAIR }, + ZoneDescription{ "Onboard LEDs", MSI_ZONE_ON_BOARD_LED_0 } +}; + + +static std::vector zone_description; + + + +/**------------------------------------------------------------------*\ + @name MSI Mystic Light (112 Byte) + @category Motherboard + @type USB + @save :robot: + @direct :white_check_mark: + @effects :white_check_mark: + @detectors DetectMSIMysticLightControllers + @comment +\*-------------------------------------------------------------------*/ + +RGBController_MSIMysticLight112::RGBController_MSIMysticLight112 + ( + MSIMysticLight112Controller* controller_ptr + ) +{ + controller = controller_ptr; + + name = controller->GetDeviceName(); + vendor = "MSI"; + type = DEVICE_TYPE_MOTHERBOARD; + description = "MSI Mystic Light Device (112-byte)"; + version = controller->GetFWVersion(); + location = controller->GetDeviceLocation(); + serial = controller->GetSerial(); + + const std::vector* supported_zones = controller->GetSupportedZones(); + + for(std::size_t i = 0; i < supported_zones->size(); ++i) + { + for(std::size_t j = 0; j < NUMOF_ZONES; ++j) + { + if(led_zones[j].zone_type == (*supported_zones)[i]) + { + zone_description.push_back(&led_zones[j]); + break; + } + } + } + + SetupModes(); + SetupZones(); + SetupColors(); + active_mode = GetDeviceMode(); + GetDeviceConfig(); +} + +RGBController_MSIMysticLight112::~RGBController_MSIMysticLight112() +{ + zone_description.clear(); + delete controller; +} + +int RGBController_MSIMysticLight112::GetDeviceMode() +{ + MSI_MODE mode = controller->GetMode(); + + for(unsigned int i = 0; i < modes.size(); ++i) + { + if(mode == modes[i].value) + { + return i; + } + } + + return 0; +} + +void RGBController_MSIMysticLight112::SetupZones() +{ + /*---------------------------------------------------------*\ + | Set up zones | + \*---------------------------------------------------------*/ + for(std::size_t zone_idx = 0; zone_idx < zone_description.size(); ++zone_idx) + { + const ZoneDescription* zd = zone_description[zone_idx]; + + zone new_zone; + + new_zone.name = zd->name; + + /*--------------------------------------------------\ + | 112-byte MSI does not have resizable zones, but | + | onboard LED zones have multiple LEDs | + \*-------------------------------------------------*/ + if(zd->zone_type == MSI_ZONE_ON_BOARD_LED_0) + { + new_zone.leds_max = (int)controller->GetMaxOnboardLeds(); + } + else + { + new_zone.leds_max = 1; + } + + new_zone.leds_min = new_zone.leds_max; + new_zone.leds_count = new_zone.leds_max; + + /*-------------------------------------------------*\ + | Determine zone type based on max number of LEDs | + \*-------------------------------------------------*/ + if(new_zone.leds_max == 1) + { + new_zone.type = ZONE_TYPE_SINGLE; + } + else + { + new_zone.type = ZONE_TYPE_LINEAR; + } + + new_zone.matrix_map = NULL; + zones.push_back(new_zone); + } + + /*---------------------------------------------------------*\ + | Set up LEDs | + \*---------------------------------------------------------*/ + for(std::size_t zone_idx = 0; zone_idx < zone_description.size(); ++zone_idx) + { + for(std::size_t led_idx = 0; led_idx < zones[zone_idx].leds_count; ++led_idx) + { + led new_led; + + new_led.name = zones[zone_idx].name + " LED "; + + if(zones[zone_idx].leds_count > 1) + { + new_led.name.append(std::to_string(led_idx + 1)); + } + + new_led.value = (unsigned int)(zone_description[zone_idx]->zone_type + led_idx); + leds.push_back(new_led); + } + } +} + +void RGBController_MSIMysticLight112::ResizeZone + ( + int /*zone*/, + int /*new_size*/ + ) +{ +} + +void RGBController_MSIMysticLight112::DeviceUpdateLEDs() +{ + for(std::size_t zone_idx = 0; zone_idx < zones.size(); ++zone_idx) + { + for(int led_idx = zones[zone_idx].leds_count - 1; led_idx >= 0; led_idx--) + { + UpdateLed((int)zone_idx, led_idx); + } + } + controller->Update((modes[active_mode].flags & MODE_FLAG_AUTOMATIC_SAVE) != 0); +} + +void RGBController_MSIMysticLight112::UpdateZoneLEDs + ( + int zone + ) +{ + for(int led_idx = zones[zone].leds_count - 1; led_idx >= 0; led_idx--) + { + UpdateLed(zone, led_idx); + } + controller->Update((modes[active_mode].flags & MODE_FLAG_AUTOMATIC_SAVE) != 0); +} + +void RGBController_MSIMysticLight112::UpdateSingleLED + ( + int led + ) +{ + UpdateLed(leds[led].value, led); + controller->Update((modes[active_mode].flags & MODE_FLAG_AUTOMATIC_SAVE) != 0); +} + +void RGBController_MSIMysticLight112::DeviceUpdateMode() +{ + if(modes[active_mode].value == MSI_MODE_DIRECT_DUMMY) + { + controller->SetDirectMode(true); + } + else + { + controller->SetDirectMode(false); + DeviceUpdateLEDs(); + } +} + +void RGBController_MSIMysticLight112::DeviceSaveMode() +{ + controller->Update(true); +} + +void RGBController_MSIMysticLight112::SetupModes() +{ + constexpr unsigned int PER_LED_ONLY = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_MANUAL_SAVE; + constexpr unsigned int RANDOM_ONLY = MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_RANDOM_COLOR | MODE_FLAG_MANUAL_SAVE; + constexpr unsigned int COMMON = RANDOM_ONLY | MODE_FLAG_HAS_PER_LED_COLOR; + + SetupMode("Direct", MSI_MODE_DIRECT_DUMMY, MODE_FLAG_HAS_PER_LED_COLOR); + SetupMode("Static", MSI_MODE_STATIC, MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_MANUAL_SAVE); + SetupMode("Breathing", MSI_MODE_BREATHING, PER_LED_ONLY); + SetupMode("Flashing", MSI_MODE_FLASHING, COMMON); + SetupMode("Double flashing", MSI_MODE_DOUBLE_FLASHING, COMMON); + SetupMode("Lightning", MSI_MODE_LIGHTNING, PER_LED_ONLY); + SetupMode("Meteor", MSI_MODE_METEOR, COMMON); + SetupMode("Stack", MSI_MODE_WATER_DROP, COMMON); + SetupMode("Rainbow", MSI_MODE_COLOR_RING, COMMON); + SetupMode("Planetary", MSI_MODE_PLANETARY, RANDOM_ONLY); + SetupMode("Double meteor", MSI_MODE_DOUBLE_METEOR, RANDOM_ONLY); + SetupMode("Energy", MSI_MODE_ENERGY, RANDOM_ONLY); + SetupMode("Blink", MSI_MODE_BLINK, COMMON); + SetupMode("Clock", MSI_MODE_CLOCK, RANDOM_ONLY); + SetupMode("Color pulse", MSI_MODE_COLOR_PULSE, COMMON); + SetupMode("Color shift", MSI_MODE_COLOR_SHIFT, RANDOM_ONLY); + SetupMode("Color wave", MSI_MODE_COLOR_WAVE, COMMON); + SetupMode("Marquee", MSI_MODE_MARQUEE, PER_LED_ONLY); + SetupMode("Rainbow wave", MSI_MODE_RAINBOW_WAVE, RANDOM_ONLY); + SetupMode("Visor", MSI_MODE_VISOR, COMMON); + SetupMode("Rainbow flashing", MSI_MODE_RAINBOW_FLASHING, RANDOM_ONLY); + SetupMode("Rainbow double flashing", MSI_MODE_RAINBOW_DOUBLE_FLASHING, RANDOM_ONLY); +} + +void RGBController_MSIMysticLight112::UpdateLed + ( + int zone, + int led + ) +{ + unsigned char red = RGBGetRValue(zones[zone].colors[led]); + unsigned char grn = RGBGetGValue(zones[zone].colors[led]); + unsigned char blu = RGBGetBValue(zones[zone].colors[led]); + + if(controller->IsDirectModeActive()) + { + controller->SetLedColor((MSI_ZONE)zones[zone].leds[led].value, red, grn, blu); + } + else + { + bool random = modes[active_mode].color_mode == MODE_COLORS_RANDOM; + MSI_MODE mode = (MSI_MODE)modes[active_mode].value; + MSI_SPEED speed = (MSI_SPEED)modes[active_mode].speed; + MSI_BRIGHTNESS brightness = (MSI_BRIGHTNESS)modes[active_mode].brightness; + + controller->SetMode((MSI_ZONE)zones[zone].leds[led].value, mode, speed, brightness, random); + controller->SetZoneColor((MSI_ZONE)zones[zone].leds[led].value, red, grn, blu, red, grn, blu); + } +} + +void RGBController_MSIMysticLight112::SetupMode + ( + const char *name, + MSI_MODE mod, + unsigned int flags + ) +{ + mode Mode; + Mode.name = name; + Mode.value = mod; + Mode.flags = flags; + + if(flags & MODE_FLAG_HAS_PER_LED_COLOR) + { + Mode.color_mode = MODE_COLORS_PER_LED; + } + else + { + Mode.color_mode = MODE_COLORS_RANDOM; + } + + if(flags & MODE_FLAG_HAS_SPEED) + { + Mode.speed = MSI_SPEED_MEDIUM; + Mode.speed_max = MSI_SPEED_HIGH; + Mode.speed_min = MSI_SPEED_LOW; + } + else + { + /*---------------------------------------------------------*\ + | For modes without speed this needs to be set to avoid | + | bad values in the saved profile which in turn corrupts | + | the brightness calculation when loading the profile | + \*---------------------------------------------------------*/ + Mode.speed = 0; + Mode.speed_max = 0; + Mode.speed_min = 0; + } + + if(flags & MODE_FLAG_HAS_BRIGHTNESS) + { + Mode.brightness = MSI_BRIGHTNESS_LEVEL_100; + Mode.brightness_max = MSI_BRIGHTNESS_LEVEL_100; + Mode.brightness_min = MSI_BRIGHTNESS_OFF; + } + else + { + Mode.brightness = MSI_BRIGHTNESS_LEVEL_100; + Mode.brightness_max = MSI_BRIGHTNESS_LEVEL_100; + Mode.brightness_min = MSI_BRIGHTNESS_LEVEL_100; + } + + modes.push_back(Mode); +} + +void RGBController_MSIMysticLight112::GetDeviceConfig() +{ + MSI_MODE mode; + MSI_SPEED speed; + MSI_BRIGHTNESS brightness; + bool rainbow; + unsigned int color; + + for(size_t i = 0; i < zone_description.size(); ++i) + { + controller->GetMode(zone_description[i]->zone_type, mode, speed, brightness, rainbow, color); + + for(size_t j = 0; j < zones[i].leds_count; ++j) + { + zones[i].colors[j] = color; + } + } + + controller->GetMode(zone_description[0]->zone_type, mode, speed, brightness, rainbow, color); + + for(size_t i = 0; i < modes.size(); ++i) + { + if(mode == modes[i].value) + { + if(modes[i].flags & MODE_FLAG_HAS_SPEED) + { + modes[i].speed = speed; + } + if(modes[i].flags & MODE_FLAG_HAS_BRIGHTNESS) + { + modes[i].brightness = brightness; + } + if(rainbow) + { + if(modes[i].flags & (MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_RANDOM_COLOR)) + { + if(rainbow) + { + modes[i].color_mode = MODE_COLORS_RANDOM; + } + else + { + modes[i].color_mode = MODE_COLORS_PER_LED; + } + } + } + break; + } + } +} diff --git a/Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.h b/Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.h new file mode 100644 index 00000000..cf1cabf1 --- /dev/null +++ b/Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.h @@ -0,0 +1,48 @@ +/*-----------------------------------------*\ +| RGBController_MSIMysticLight112.h | +| | +| Generic RGB Interface for OpenRGB | +| MSI Mystic Light (112-byte) USB Driver | +| | +| thombo 12/17/2022 | +\*-----------------------------------------*/ + +#pragma once +#include "RGBController.h" +#include "MSIMysticLight112Controller.h" +#include + +class RGBController_MSIMysticLight112: public RGBController +{ +public: + RGBController_MSIMysticLight112(MSIMysticLight112Controller* controller_ptr); + ~RGBController_MSIMysticLight112(); + + 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 SetupModes(); + void UpdateLed + ( + int zone, + int led + ); + void SetupMode + ( + const char *name, + MSI_MODE mode, + unsigned int flags + ); + int GetDeviceMode(); + void GetDeviceConfig(); + + MSIMysticLight112Controller* controller; +}; diff --git a/OpenRGB.pro b/OpenRGB.pro index e691160d..a0783375 100644 --- a/OpenRGB.pro +++ b/OpenRGB.pro @@ -501,9 +501,11 @@ HEADERS += Controllers/MSIGPUController/RGBController_MSIGPU.h \ Controllers/MSIMysticLightController/MSIMysticLightCommon.h \ Controllers/MSIMysticLightController/MSIMysticLight64Controller.h \ + Controllers/MSIMysticLightController/MSIMysticLight112Controller.h \ Controllers/MSIMysticLightController/MSIMysticLight162Controller.h \ Controllers/MSIMysticLightController/MSIMysticLight185Controller.h \ Controllers/MSIMysticLightController/RGBController_MSIMysticLight64.h \ + Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.h \ Controllers/MSIMysticLightController/RGBController_MSIMysticLight162.h \ Controllers/MSIMysticLightController/RGBController_MSIMysticLight185.h \ Controllers/MSIOptixController/MSIOptixController.h \ @@ -1075,9 +1077,11 @@ SOURCES += Controllers/MSIGPUController/RGBController_MSIGPU.cpp \ Controllers/MSIMysticLightController/MSIMysticLight64Controller.cpp \ Controllers/MSIMysticLightController/MSIMysticLight162Controller.cpp \ + Controllers/MSIMysticLightController/MSIMysticLight112Controller.cpp \ Controllers/MSIMysticLightController/MSIMysticLight185Controller.cpp \ Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp \ Controllers/MSIMysticLightController/RGBController_MSIMysticLight64.cpp \ + Controllers/MSIMysticLightController/RGBController_MSIMysticLight112.cpp \ Controllers/MSIMysticLightController/RGBController_MSIMysticLight162.cpp \ Controllers/MSIMysticLightController/RGBController_MSIMysticLight185.cpp \ Controllers/MSIOptixController/MSIOptixController.cpp \