From 9f82afa485ae6d5e92e19f67ff05b1a639276189 Mon Sep 17 00:00:00 2001 From: rom4ster Date: Wed, 18 Jun 2025 23:14:42 +0000 Subject: [PATCH] MSI X870 Tomahawk WIFI support --- .../MSIMysticLight761Controller.cpp | 437 ++++++++++++++++ .../MSIMysticLight761Controller.h | 149 ++++++ .../RGBController_MSIMysticLight761.cpp | 467 ++++++++++++++++++ .../RGBController_MSIMysticLight761.h | 53 ++ .../MSIMysticLightCommon.h | 33 +- .../MSIMysticLightControllerDetect.cpp | 33 +- 6 files changed, 1167 insertions(+), 5 deletions(-) create mode 100644 Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.cpp create mode 100644 Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.h create mode 100644 Controllers/MSIMysticLightController/MSIMysticLight185Controller/RGBController_MSIMysticLight761.cpp create mode 100644 Controllers/MSIMysticLightController/MSIMysticLight185Controller/RGBController_MSIMysticLight761.h diff --git a/Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.cpp b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.cpp new file mode 100644 index 00000000..e108ea0d --- /dev/null +++ b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.cpp @@ -0,0 +1,437 @@ +/*---------------------------------------------------------*\ +| MSIMysticLight185Controller.cpp | +| | +| Driver for MSI Mystic Light 761-byte motherboard | +| | +| Direct mode functionality has been implemented based on | +| the SignalRGB project | +| (https://signalrgb.com/) | +| | +| rom4ster 11 Jun 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include +#include +#include +#include "MSIMysticLight761Controller.h" +#include "StringUtils.h" + + +#define NUM_CONFS sizeof(board_configs) / sizeof(mystic_light_761_config) +#define COLOR_BLACK {0, 0, 0} +#define IS_JARGB(X) (X == MSI_ZONE_JARGB_1 || X == MSI_ZONE_JARGB_2 || X == MSI_ZONE_JARGB_3) +#define GET_CHAR_PTR_REF(X) (unsigned char *) &(X) + +struct mystic_light_761_config +{ + unsigned short pid; // PID of the board + int numof_onboard_leds; // number of onboard leds + int numof_pipe1_leds; // number of pipe 1 leds (used in per LED mode only) + int numof_pipe2_leds; // number of pipe 2 leds (used in per LED mode only) + int numof_JRGBs; // number of supported JRGB headers (used in per LED mode only) + const std::vector* supported_zones; // pointer to vector of supported zones + MSIMysticLight761Controller::DIRECT_MODE per_led_mode; // type of direct mode support +}; + +const std::vector x870tomawhawk_zones = +{ + MSI_ZONE_JAF, + MSI_ZONE_JARGB_1, + MSI_ZONE_JARGB_2, + MSI_ZONE_JARGB_3, +}; + +static const mystic_light_761_config board_configs[] = +{ + { 0x0076, 0, 0, 0, 1, &x870tomawhawk_zones, MSIMysticLight761Controller::DIRECT_MODE_ZONE_BASED }, // MSI X870 TOMAHAWK WIFI +}; + +void init_packet(FeaturePacket_Zone_761 * packet) +{ + packet->packet.fixed1 = 0x09; + packet->packet.fixed2 = 0x00; + packet->packet.fixed3 = 0x00; + packet->packet.hdr2 = 240; + + for(int i = 0; i < NUM_LEDS_761; i++) + { + packet->packet.colors[i] = 0x0; + } + +} + +MSIMysticLight761Controller::MSIMysticLight761Controller + ( + hid_device* handle, + const char *path, + unsigned short pid + ) +{ + dev = handle; + + supported_zones = new std::vector; + const mystic_light_761_config * board_config = nullptr; + + for(int i = 0; i < NUM_CONFS; i++) + { + if(board_configs[i].pid == pid) + { + board_config = &board_configs[i]; + break; + } + } + + if(board_config != nullptr) + { + supported_zones = (std::vector*) board_config->supported_zones; + unsigned int max = 0; + for(int i = 0; i < board_config->supported_zones[0].size(); i++) + { + unsigned int curr_val = (unsigned int) (board_config->supported_zones[0][i]); + if( (unsigned int) curr_val > max ) + { + max = curr_val; + } + } + } + + for(MSI_ZONE supp_zone : *supported_zones ) + { + ZoneConfig conf; + conf.msi_zone = supp_zone; + ZoneData * dat = new ZoneData; + conf.zone_data = dat; + zone_configs.push_back(conf); + } + + if(dev) + { + location = path; + + ReadName(); + ReadFwVersion(); + ReadSettings(); + data = new FeaturePacket_761; + + data->jaf.zone = MSI_ZONE_JAF; + data->jargb1.zone = MSI_ZONE_JARGB_1; + data->jargb2.zone = MSI_ZONE_JARGB_2; + data->jargb3.zone = MSI_ZONE_JARGB_3; + + data->jaf.packet.hdr0 = 0x08; + data->jargb1.packet.hdr0 = 0x04; + data->jargb2.packet.hdr0 = 0x04; + data->jargb3.packet.hdr0 = 0x04; + + + data->jaf.packet.hdr1 = 0x00; + data->jargb1.packet.hdr1 = 0x00; + data->jargb2.packet.hdr1 = 0x01; + data->jargb3.packet.hdr1 = 0x02; + + init_packet(&data->jaf); + init_packet(&data->jargb1); + init_packet(&data->jargb2); + init_packet(&data->jargb3); + + } + +} + +MSIMysticLight761Controller::~MSIMysticLight761Controller() +{ + hid_close(dev); +} + +void MSIMysticLight761Controller::SetMode + ( + MSI_ZONE zone, + MSI_MODE mode, + MSI_SPEED speed, + MSI_BRIGHTNESS brightness, + bool rainbow_color + ) +{ + return; // Only supporting direct for now +} + +std::string MSIMysticLight761Controller::GetDeviceName() +{ + return name; +} + +std::string MSIMysticLight761Controller::GetFWVersion() +{ + return std::string("AP/LD ").append(version_APROM).append(" / ").append(version_LDROM); +} + +std::string MSIMysticLight761Controller::GetDeviceLocation() +{ + return("HID: " + location); +} + +std::string MSIMysticLight761Controller::GetSerial() +{ + wchar_t serial_string[128]; + int ret = hid_get_serial_number_string(dev, serial_string, 128); + + if(ret != 0) + { + return(""); + } + + return(StringUtils::wstring_to_string(serial_string)); +} + +bool MSIMysticLight761Controller::ReadSettings() +{ + /*-----------------------------------------------------*\ + | Read packet from hardware, return true if successful | + \*-----------------------------------------------------*/ + unsigned char buffer [500]; + buffer[0] = 0x51; + return (hid_get_feature_report(dev, buffer, 500)) > 0 ; +} + +bool MSIMysticLight761Controller::Update + ( + bool save + ) +{ + + int ret = 0; + bool flag = true; + ret = hid_send_feature_report(dev, GET_CHAR_PTR_REF(data->jaf.packet) , sizeof(FeaturePacket_PerLED_761)); + if(ret < 0) { flag = false;} + ret = hid_send_feature_report(dev, GET_CHAR_PTR_REF(data->jargb1.packet) , sizeof(FeaturePacket_PerLED_761)); + if(ret < 0) { flag = false;} + ret = hid_send_feature_report(dev, GET_CHAR_PTR_REF(data->jargb2.packet) , sizeof(FeaturePacket_PerLED_761)); + if(ret < 0) { flag = false;} + ret = hid_send_feature_report(dev, GET_CHAR_PTR_REF(data->jargb3.packet) , sizeof(FeaturePacket_PerLED_761)); + if(ret < 0) { flag = false;} + + return flag; +} + + + +void MSIMysticLight761Controller::SetZoneColor + ( + MSI_ZONE zone, + unsigned char red1, + unsigned char grn1, + unsigned char blu1, + unsigned char red2, + unsigned char grn2, + unsigned char blu2 + ) +{ + for(int i = 0; i < zone_configs.size(); i++) + { + if(zone_configs[i].msi_zone == zone) + { + zone_configs[i].zone_data->color.R = red1; + zone_configs[i].zone_data->color.G = grn1; + zone_configs[i].zone_data->color.B = blu1; + zone_configs[i].zone_data->color2.R = red2; + zone_configs[i].zone_data->color2.G = grn2; + zone_configs[i].zone_data->color2.B = blu2; + } + } +} + +void set_data_color(FeaturePacket_Zone_761 * packet, int index, unsigned char color_val ) +{ + if(packet == nullptr) + { + return; + } + packet->packet.colors[index] = color_val; +} + +void MSIMysticLight761Controller::SetLedColor + ( + MSI_ZONE zone, + int index, + unsigned char red, + unsigned char grn, + unsigned char blu + ) +{ + + FeaturePacket_Zone_761 * ptr = nullptr; + switch(zone) + { + case MSI_ZONE_JAF: + ptr = &data->jaf; + break; + case MSI_ZONE_JARGB_1: + ptr = &data->jargb1; + break; + case MSI_ZONE_JARGB_2: + ptr = &data->jargb2; + break; + case MSI_ZONE_JARGB_3: + ptr = &data->jargb3; + break; + default: + break; + } + + size_t candidate_index = index*3; + + if(candidate_index + 2 <= GetMaxDirectLeds(zone) && candidate_index >= 0) + { + set_data_color(ptr, candidate_index, red); + set_data_color(ptr, candidate_index+1, grn); + set_data_color(ptr, candidate_index+2, blu); + } + +} + +ZoneData *MSIMysticLight761Controller::GetZoneData + ( + FeaturePacket_761& data_packet, + MSI_ZONE zone + ) +{ + for(ZoneConfig zd : zone_configs) + { + if(zd.msi_zone == zone) + { + return zd.zone_data; + } + } + return nullptr; +} + +Color *MSIMysticLight761Controller::GetPerLedZoneData + ( + MSI_ZONE zone + ) +{ + return &(GetZoneData(*data, zone)->color); +} + +RainbowZoneData *MSIMysticLight761Controller::GetRainbowZoneData + ( + MSI_ZONE zone + ) +{ + return nullptr; +} + +bool MSIMysticLight761Controller::ReadFwVersion() +{ + return true; +} +void MSIMysticLight761Controller::ReadName() +{ + wchar_t tname[256]; + + /*-----------------------------------------------------*\ + | Get the manufacturer string from HID | + \*-----------------------------------------------------*/ + hid_get_manufacturer_string(dev, tname, 256); + + /*-----------------------------------------------------*\ + | Convert to std::string | + \*-----------------------------------------------------*/ + name = StringUtils::wstring_to_string(tname); + + /*-----------------------------------------------------*\ + | Get the product string from HID | + \*-----------------------------------------------------*/ + hid_get_product_string(dev, tname, 256); + + /*-----------------------------------------------------*\ + | Append the product string to the manufacturer string | + \*-----------------------------------------------------*/ + name.append(" ").append(StringUtils::wstring_to_string(tname)); +} + +MSI_MODE MSIMysticLight761Controller::GetMode() +{ + return MSI_MODE_DIRECT_DUMMY; +} + +void MSIMysticLight761Controller::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) + { + return; + } + + /*-----------------------------------------------------*\ + | Update pointers with data | + \*-----------------------------------------------------*/ + + // Actual support of non direct modes needs to be further investigated + 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 MSIMysticLight761Controller::SetCycleCount + ( + MSI_ZONE zone, + unsigned char cycle_num + ) +{ + return; +} + +void MSIMysticLight761Controller::SetDirectMode + ( + bool mode + ) +{ + SelectPerLedProtocol(); +} + + +size_t MSIMysticLight761Controller::GetMaxDirectLeds + ( + MSI_ZONE zone + ) +{ + switch(zone) + { + case MSI_ZONE_JAF: + case MSI_ZONE_JARGB_1: + case MSI_ZONE_JARGB_2: + case MSI_ZONE_JARGB_3: + return 240; + break; + default: + return 1; + } +} + + +void MSIMysticLight761Controller::SelectPerLedProtocol() +{ + return; +} diff --git a/Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.h b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.h new file mode 100644 index 00000000..2dd30c0c --- /dev/null +++ b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/MSIMysticLight761Controller.h @@ -0,0 +1,149 @@ +/*---------------------------------------------------------*\ +| MSIMysticLight185Controller.cpp | +| | +| Driver for MSI Mystic Light 761-byte motherboard | +| | +| Direct mode functionality has been implemented based on | +| the SignalRGB project | +| (https://signalrgb.com/) | +| | +| rom4ster 11 Jun 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include +#include +#include "MSIMysticLightCommon.h" +#include "RGBController.h" + +class MSIMysticLight761Controller +{ +public: + MSIMysticLight761Controller + ( + hid_device* handle, + const char *path, + unsigned short pid + ); + ~MSIMysticLight761Controller(); + + 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, + int index, + unsigned char red, + unsigned char grn, + unsigned char blu + ); + + void SetCycleCount + ( + MSI_ZONE zone, + unsigned char cycle_num + ); + + bool Update + ( + bool save + ); + + std::string GetDeviceName(); + std::string GetDeviceLocation(); + std::string GetFWVersion(); + std::string GetSerial(); + + void SetDirectMode + ( + bool mode + ); + bool IsDirectModeActive() { return true; } + size_t GetMaxDirectLeds + ( + MSI_ZONE zone + ); + const std::vector* + GetSupportedZones() { return supported_zones; } + + enum DIRECT_MODE + { + DIRECT_MODE_DISABLED, + DIRECT_MODE_PER_LED, + DIRECT_MODE_ZONE_BASED + }; + + DIRECT_MODE GetSupportedDirectMode() { return DIRECT_MODE_PER_LED; } + + struct ZoneConfig + { + MSI_ZONE msi_zone; + ZoneData * zone_data; + }; + +private: + bool ReadSettings(); + bool ReadFwVersion(); + void ReadName(); + std::string name; + std::vector zone_configs; + + ZoneData* GetZoneData + ( + FeaturePacket_761& data_packet, + MSI_ZONE zone + ); + RainbowZoneData* GetRainbowZoneData(MSI_ZONE zone); + Color* GetPerLedZoneData + ( + MSI_ZONE zone + ); + void SelectPerLedProtocol(); + + std::vector* supported_zones; + hid_device* dev; + std::string location; + std::string version_APROM; + std::string version_LDROM; + FeaturePacket_761* data; + + + + + +}; diff --git a/Controllers/MSIMysticLightController/MSIMysticLight185Controller/RGBController_MSIMysticLight761.cpp b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/RGBController_MSIMysticLight761.cpp new file mode 100644 index 00000000..9f4c20e5 --- /dev/null +++ b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/RGBController_MSIMysticLight761.cpp @@ -0,0 +1,467 @@ +/*---------------------------------------------------------*\ +| MSIMysticLight185Controller.cpp | +| | +| RGBController for MSI Mystic Light 761-byte motherboard | +| | +| | +| rom4ster 11 Jun 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "RGBController_MSIMysticLight761.h" +#include "LogManager.h" + +struct ZoneDescription +{ + std::string name; + MSI_ZONE zone_type; +}; + +#define NUMOF_ZONES (sizeof(led_zones) / sizeof(ZoneDescription)) + +const ZoneDescription led_zones[] = +{ + ZoneDescription{ "JAF", MSI_ZONE_JAF }, + ZoneDescription{ "JARGB 1", MSI_ZONE_JARGB_1 }, + ZoneDescription{ "JARGB 2", MSI_ZONE_JARGB_2 }, + ZoneDescription{ "JARGB 3", MSI_ZONE_JARGB_3 }, +}; + +static std::vector zone_description; + +static int IndexOfZoneForType(MSI_ZONE zone_type) +{ + for(size_t i = 0; i < zone_description.size(); ++i) + { + if(zone_description[i]->zone_type == zone_type) + { + return (int)i; + } + } + + return -1; +} + +RGBController_MSIMysticLight761::RGBController_MSIMysticLight761 + ( + MSIMysticLight761Controller* controller_ptr + ) +{ + controller = controller_ptr; + + name = controller->GetDeviceName(); + vendor = "MSI"; + type = DEVICE_TYPE_MOTHERBOARD; + description = "MSI Mystic Light Device (761-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; + } + } + } + + last_resizable_zone = MSI_ZONE_NONE; + SetupModes(); + SetupZones(); + active_mode = GetDeviceMode(); +} + +RGBController_MSIMysticLight761::~RGBController_MSIMysticLight761() +{ + zone_description.clear(); + delete controller; +} + +int RGBController_MSIMysticLight761::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_MSIMysticLight761::SetupZones() +{ + /*-------------------------------------------------*\ + | Clear any existing color/LED configuration | + \*-------------------------------------------------*/ + leds.clear(); + colors.clear(); + + bool first_run = false; + + if(zones.size() == 0) + { + first_run = true; + } + + if(first_run) + { + /*---------------------------------------------------------*\ + | 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; + new_zone.flags = 0; + + int maxLeds = (int)controller->GetMaxDirectLeds(zd->zone_type); + + /*-------------------------------------------------*\ + | This is a fixed size zone | + \*-------------------------------------------------*/ + if(((zd->zone_type != MSI_ZONE_J_RAINBOW_1) + && (zd->zone_type != MSI_ZONE_J_RAINBOW_2) + && (zd->zone_type != MSI_ZONE_J_RAINBOW_3) + && (zd->zone_type != MSI_ZONE_JAF) + && (zd->zone_type != MSI_ZONE_JARGB_1) + && (zd->zone_type != MSI_ZONE_JARGB_2) + && (zd->zone_type != MSI_ZONE_JARGB_3) + && (zd->zone_type != MSI_ZONE_J_CORSAIR))) + { + new_zone.leds_min = maxLeds; + new_zone.leds_max = maxLeds; + new_zone.leds_count = maxLeds; + } + /*--------------------------------------------------\ + | This is a resizable zone on a board that does not | + | support per-LED direct mode | + \*-------------------------------------------------*/ + else if(controller->GetSupportedDirectMode() == MSIMysticLight761Controller::DIRECT_MODE_ZONE_BASED) + { + new_zone.leds_min = 0; + new_zone.leds_max = 30;//maxLeds; + new_zone.leds_count = 0; + last_resizable_zone = zd->zone_type; + new_zone.flags |= ZONE_FLAG_RESIZE_EFFECTS_ONLY; + } + /*--------------------------------------------------\ + | This is a resizable zone on a board that does | + | support per-LED direct mode | + \*-------------------------------------------------*/ + else + { + new_zone.leds_min = 0; + new_zone.leds_max = maxLeds; + new_zone.leds_count = 0; + last_resizable_zone = zd->zone_type; + } + + /*-------------------------------------------------*\ + | Determine zone type based on max number of LEDs | + \*-------------------------------------------------*/ + if((new_zone.leds_max == 1) || (new_zone.flags & ZONE_FLAG_RESIZE_EFFECTS_ONLY)) + { + 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) + { + controller->SetCycleCount(zone_description[zone_idx]->zone_type, zones[zone_idx].leds_count); + + if((zones[zone_idx].flags & ZONE_FLAG_RESIZE_EFFECTS_ONLY) == 0) + { + 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; + + if(zones[zone_idx].leds_count > 1) + { + new_led.name.append(" LED " + std::to_string(led_idx + 1)); + } + + new_led.value = zone_description[zone_idx]->zone_type; + leds.push_back(new_led); + } + } + else if(zones[zone_idx].leds_count > 0) + { + led new_led; + + new_led.name = zones[zone_idx].name; + + new_led.value = zone_description[zone_idx]->zone_type; + leds.push_back(new_led); + } + } + + SetupColors(); +} + + +void RGBController_MSIMysticLight761::ResizeZone + ( + int zone, + int new_size + ) +{ + if((size_t)zone >= zones.size()) + { + return; + } + + if(((unsigned int)new_size >= zones[zone].leds_min) && ((unsigned int)new_size <= zones[zone].leds_max)) + { + zones[zone].leds_count = new_size; + SetupZones(); + + if(zone_description[zone]->zone_type == last_resizable_zone) + { + GetDeviceConfig(); + last_resizable_zone = MSI_ZONE_NONE; + } + } +} + +void RGBController_MSIMysticLight761::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_MSIMysticLight761::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_MSIMysticLight761::UpdateSingleLED + ( + int led + ) +{ + int zone_index = IndexOfZoneForType((MSI_ZONE)leds[led].value); + + if(zone_index == -1) + { + LOG_DEBUG("[%s]: could not find zone for type %d", controller->GetDeviceName().c_str(), leds[led].value); + return; + } + + int led_index = led - zones[zone_index].start_idx; + UpdateLed(zone_index, led_index); + controller->Update((modes[active_mode].flags & MODE_FLAG_AUTOMATIC_SAVE) != 0); +} + +void RGBController_MSIMysticLight761::DeviceUpdateMode() +{ + if(modes[active_mode].value == MSI_MODE_DIRECT_DUMMY) + { + controller->SetDirectMode(true); + } + else + { + controller->SetDirectMode(false); + DeviceUpdateLEDs(); + } +} + +void RGBController_MSIMysticLight761::DeviceSaveMode() +{ + controller->Update(true); +} + + +void RGBController_MSIMysticLight761::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; + + if(controller->GetSupportedDirectMode() != MSIMysticLight761Controller::DIRECT_MODE_DISABLED) + { + SetupMode("Direct", MSI_MODE_DIRECT_DUMMY, MODE_FLAG_HAS_PER_LED_COLOR); + } + +} + +void RGBController_MSIMysticLight761::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), led, red, grn, blu); + } + else + { + if(led == 0) + { + 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_MSIMysticLight761::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_MSIMysticLight761::GetDeviceConfig() +{ + if(controller->GetMode() != MSI_MODE_DIRECT_DUMMY) + { + 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); + + if(zones[i].colors != nullptr) + { + 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/MSIMysticLight185Controller/RGBController_MSIMysticLight761.h b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/RGBController_MSIMysticLight761.h new file mode 100644 index 00000000..dfd1fd36 --- /dev/null +++ b/Controllers/MSIMysticLightController/MSIMysticLight185Controller/RGBController_MSIMysticLight761.h @@ -0,0 +1,53 @@ +/*---------------------------------------------------------*\ +| MSIMysticLight185Controller.cpp | +| | +| RGBController for MSI Mystic Light 761-byte motherboard | +| | +| | +| rom4ster 11 Jun 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include +#include "RGBController.h" +#include "MSIMysticLight761Controller.h" + +class RGBController_MSIMysticLight761: public RGBController +{ +public: + RGBController_MSIMysticLight761(MSIMysticLight761Controller* controller_ptr); + ~RGBController_MSIMysticLight761(); + + 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(); + + MSIMysticLight761Controller* controller; + MSI_ZONE last_resizable_zone; +}; diff --git a/Controllers/MSIMysticLightController/MSIMysticLightCommon.h b/Controllers/MSIMysticLightController/MSIMysticLightCommon.h index 062f30f4..5a1aa860 100644 --- a/Controllers/MSIMysticLightController/MSIMysticLightCommon.h +++ b/Controllers/MSIMysticLightController/MSIMysticLightCommon.h @@ -35,7 +35,11 @@ enum MSI_ZONE MSI_ZONE_ON_BOARD_LED_7 = 17, MSI_ZONE_ON_BOARD_LED_8 = 18, MSI_ZONE_ON_BOARD_LED_9 = 19, - MSI_ZONE_ON_BOARD_LED_10 = 20 + MSI_ZONE_ON_BOARD_LED_10 = 20, + MSI_ZONE_JAF = 21, + MSI_ZONE_JARGB_1 = 22, + MSI_ZONE_JARGB_2 = 23, + MSI_ZONE_JARGB_3 = 24, }; enum MSI_MODE @@ -113,6 +117,7 @@ enum MSI_BRIGHTNESS }; #define NUMOF_PER_LED_MODE_LEDS 240 +#define NUM_LEDS_761 720 #define SYNC_SETTING_ONBOARD 0x01 #define SYNC_SETTING_JRAINBOW1 0x02 @@ -241,4 +246,30 @@ struct FeaturePacket_PerLED_185 Color leds[NUMOF_PER_LED_MODE_LEDS]; }; +struct FeaturePacket_PerLED_761 +{ + unsigned char report_id = 0x51; // Report ID + unsigned char fixed1 = 0x09; // Always 9? + unsigned char hdr0; // 0x08 for ez 0x04 for ARGB 0x06 for LED + unsigned char hdr1; // 0 for LED/EZ and argb num for ARGB? + unsigned char fixed2 = 0x00; // IDK what this is + unsigned char fixed3 = 0x00; // IDK what this is + unsigned char hdr2; // Led Count + unsigned char colors [NUM_LEDS_761]; +}; + +struct FeaturePacket_Zone_761 +{ + MSI_ZONE zone; + FeaturePacket_PerLED_761 packet; +}; + +struct FeaturePacket_761 +{ + FeaturePacket_Zone_761 jargb1; + FeaturePacket_Zone_761 jargb2; + FeaturePacket_Zone_761 jargb3; + FeaturePacket_Zone_761 jaf; +}; + #define MSI_USB_PID_COMMON 0x0076 // Common PID for a certain set of 185-byte boards diff --git a/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp b/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp index c333efa6..90755816 100644 --- a/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp +++ b/Controllers/MSIMysticLightController/MSIMysticLightControllerDetect.cpp @@ -12,10 +12,12 @@ #include "MSIMysticLight112Controller.h" #include "MSIMysticLight162Controller.h" #include "MSIMysticLight185Controller.h" +#include "MSIMysticLight761Controller.h" #include "RGBController_MSIMysticLight64.h" #include "RGBController_MSIMysticLight112.h" #include "RGBController_MSIMysticLight162.h" #include "RGBController_MSIMysticLight185.h" +#include "RGBController_MSIMysticLight761.h" #include "dmiinfo.h" #include "LogManager.h" @@ -52,7 +54,7 @@ void DetectMSIMysticLightControllers size_t packet_length = hid_get_feature_report(dev, temp_buffer, 200); DMIInfo dmi; - if((packet_length >= sizeof(FeaturePacket_185)) && (packet_length <= (sizeof(FeaturePacket_185) + 1))) + if((packet_length >= sizeof(FeaturePacket_185)) && (packet_length <= (sizeof(FeaturePacket_185) + 1))) //WHY r we doing this ? why not == { MSIMysticLight185Controller* controller = new MSIMysticLight185Controller(dev, info->path, info->product_id); RGBController_MSIMysticLight185* rgb_controller = new RGBController_MSIMysticLight185(controller); @@ -75,9 +77,31 @@ void DetectMSIMysticLightControllers } else // no supported length returned { - std::string name = "MSI " + dmi.getMainboard(); - LOG_INFO("No matching driver found for %s, packet length = %d", name.c_str(), packet_length); - return; + + unsigned char second_buffer [1000]; + second_buffer[0] = 0x51; + + for(int i = 1; i < 1000; i++) + { + second_buffer[i] = 0x0; + } + + size_t packet_length_new_attempt = hid_get_feature_report(dev, second_buffer, 1000); + + if(packet_length_new_attempt >=290 && packet_length_new_attempt <= 291) + { + MSIMysticLight761Controller* controller = new MSIMysticLight761Controller(dev, info->path, info->product_id); + RGBController_MSIMysticLight761* rgb_controller = new RGBController_MSIMysticLight761(controller); + rgb_controller->name = "MSI " + dmi.getMainboard(); + ResourceManager::get()->RegisterRGBController(rgb_controller); + + } + else + { + std::string name = "MSI " + dmi.getMainboard(); + LOG_INFO("No matching driver found for %s, packet length = %d", name.c_str(), packet_length); + return; + } } } } @@ -196,6 +220,7 @@ REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_7E10", DetectMSIMysticLightCont REGISTER_HID_DETECTOR_PU("MSI Mystic Light MS_B926", DetectMSIMysticLightControllers, MSI_USB_VID, 0xB926, 0x0001, 0x00); // Detector for the set of common boards REGISTER_HID_DETECTOR_PU("MSI Mystic Light Common", DetectMSIMysticLightControllers, MSI_USB_VID_COMMON, MSI_USB_PID_COMMON, 0x0001, 0x00); +REGISTER_HID_DETECTOR_PU("MSI Mystic Light X870", DetectMSIMysticLightControllers, MSI_USB_VID_COMMON, MSI_USB_PID_COMMON, 0xFF00, 0x01); /*---------------------------------------------------------------------------------------------------------*\ | Dummy entries for boards using commwn VID and PID | | |