From 9af84004a5fdaf6f68de8b967ad2be5eed141b64 Mon Sep 17 00:00:00 2001 From: Blacktempel <6657796+Blacktempel@users.noreply.github.com> Date: Wed, 11 Feb 2026 12:39:29 +0100 Subject: [PATCH] Add MSI controller for AIOs. (#2207) * Add MSI controller for AIOs. Fan RPM read, thermal sensor & fan control. * PR comments & rename controller. * PR review * PR review * PR review --- LibreHardwareMonitorLib/Hardware/Computer.cs | 4 + .../Hardware/Controller/MSI/MsiConstants.cs | 22 + .../Controller/MSI/MsiCoreLiquidController.cs | 441 ++++++++++++++++++ .../Hardware/Controller/MSI/MsiDevice.cs | 80 ++++ .../Hardware/Controller/MSI/MsiFan.cs | 48 ++ .../Hardware/Controller/MSI/MsiFanControl.cs | 21 + .../Hardware/Controller/MSI/MsiFanMode.cs | 16 + .../Hardware/Controller/MSI/MsiGroup.cs | 70 +++ .../Hardware/Controller/MSI/MsiSensor.cs | 26 ++ 9 files changed, 728 insertions(+) create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiConstants.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiCoreLiquidController.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiDevice.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFan.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanControl.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanMode.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiGroup.cs create mode 100644 LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiSensor.cs diff --git a/LibreHardwareMonitorLib/Hardware/Computer.cs b/LibreHardwareMonitorLib/Hardware/Computer.cs index 64994c2..3790b9d 100644 --- a/LibreHardwareMonitorLib/Hardware/Computer.cs +++ b/LibreHardwareMonitorLib/Hardware/Computer.cs @@ -14,6 +14,7 @@ using LibreHardwareMonitor.Hardware.Controller.AeroCool; using LibreHardwareMonitor.Hardware.Controller.AquaComputer; using LibreHardwareMonitor.Hardware.Controller.Arctic; using LibreHardwareMonitor.Hardware.Controller.Heatmaster; +using LibreHardwareMonitor.Hardware.Controller.MSI; using LibreHardwareMonitor.Hardware.Controller.Nzxt; using LibreHardwareMonitor.Hardware.Controller.Razer; using LibreHardwareMonitor.Hardware.Controller.TBalancer; @@ -128,6 +129,7 @@ public class Computer : IComputer Add(new NzxtGroup(_settings)); Add(new RazerGroup(_settings)); Add(new ArcticGroup(_settings)); + Add(new MsiGroup(_settings)); } else { @@ -138,6 +140,7 @@ public class Computer : IComputer RemoveType(); RemoveType(); RemoveType(); + RemoveType(); } } @@ -526,6 +529,7 @@ public class Computer : IComputer Add(new NzxtGroup(_settings)); Add(new RazerGroup(_settings)); Add(new ArcticGroup(_settings)); + Add(new MsiGroup(_settings)); } if (_storageEnabled) diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiConstants.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiConstants.cs new file mode 100644 index 0000000..608f720 --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiConstants.cs @@ -0,0 +1,22 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +using System.Collections.Generic; + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +internal static class MsiConstants +{ + public static readonly IReadOnlyList SupportedDevices = new List + { + new MsiDevice(MsiDeviceType.S280, 0x0DB0, 0x75B6, 0x6A04), + new MsiDevice(MsiDeviceType.S360, 0x0DB0, 0x9BA6, 0x6A05), + new MsiDevice(MsiDeviceType.S360MEG, 0x1462, 0x9BA6, 0x6A05), + new MsiDevice(MsiDeviceType.X360, 0x0DB0, 0x5259, 0x6A11), + new MsiDevice(MsiDeviceType.X240, 0x0DB0, 0xC7B2, 0x6A10), + new MsiDevice(MsiDeviceType.D360, 0x0DB0, 0x8DBF, 0x6A15), + new MsiDevice(MsiDeviceType.D240, 0x0DB0, 0xD085, 0x6A16), + }; +} diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiCoreLiquidController.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiCoreLiquidController.cs new file mode 100644 index 0000000..c5913b3 --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiCoreLiquidController.cs @@ -0,0 +1,441 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading; +using HidSharp; + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +internal class MsiCoreLiquidController : Hardware +{ + private const int MutexTimeout = 500; + private const int DataLength = 64; + + private readonly MsiDevice _msiDevice; + private readonly HidDevice _hidDevice; + + private readonly List _sensors = []; + + private Sensor _fan1; + private Sensor _fan2; + private Sensor _fan3; + private Sensor _fan4; + private Sensor _fan5; + + public MsiCoreLiquidController(MsiDevice msiDevice, HidDevice hidDevice, ISettings settings) + : base(msiDevice.Name, new(hidDevice), settings) + { + _msiDevice = msiDevice; + _hidDevice = hidDevice; + + CreateSensors(); + } + + public MsiDevice MsiDevice => _msiDevice; + + public override HardwareType HardwareType => HardwareType.Cooler; + + public override void Update() + { + var msi = new MsiFanControl(); + + if (GetCoolerStatus(msi) && GetFanConfigure(msi) && GetFanTemperatureConfigure(msi)) + { + _sensors.ForEach(s => s.Update(msi)); + } + } + + public override string GetReport() + { + var sb = new StringBuilder(); + + sb.AppendLine($"{MsiDevice.Name} - ({MsiDevice.VendorId:X4}:{MsiDevice.ProductIdController:X4})"); + + foreach (var sensor in _sensors) + { + sb.AppendLine($"{sensor.Name}: {sensor.Value?.ToString() ?? "No value"}"); + } + + return sb.ToString(); + } + + private void CreateSensors() + { + if (MsiDevice.DeviceType == MsiDeviceType.S360) + { + _fan1 = AddSensor("Radiator Fan", 10, SensorType.Fan, m => m.Fan1.Speed); + _fan4 = AddSensor("Pump Fan", 13, SensorType.Fan, m => m.Fan4.Speed); + _fan5 = AddSensor("Pump", 14, SensorType.Fan, m => m.Fan5.Speed); + } + else //May need other mapping for different devices + { + _fan1 = AddSensor("Fan 1", 10, SensorType.Fan, m => m.Fan1.Speed); + _fan2 = AddSensor("Fan 2", 11, SensorType.Fan, m => m.Fan2.Speed); + _fan3 = AddSensor("Fan 3", 12, SensorType.Fan, m => m.Fan3.Speed); + _fan4 = AddSensor("Fan 4", 13, SensorType.Fan, m => m.Fan4.Speed); + _fan5 = AddSensor("Fan 5", 14, SensorType.Fan, m => m.Fan5.Speed); + } + + AddSensor("Inlet Temperature", 0, SensorType.Temperature, m => m.TemperatureInlet); + AddSensor("Liquid Temperature", 1, SensorType.Temperature, m => m.TemperatureOutlet); //Msi: "Liquid_Temp" + AddSensor("Temperature Sensor 1", 2, SensorType.Temperature, m => m.TemperatureSensor1 == 125 ? -100 : m.TemperatureSensor1); + AddSensor("Temperature Sensor 2", 3, SensorType.Temperature, m => m.TemperatureSensor2 == 125 ? -100 : m.TemperatureSensor2); + + void TryAddFanControl(Sensor fan) + { + if (fan != null) + { + var fanControl = new Control(fan, _settings, 0, 100); + fan.Control = fanControl; + fanControl.ControlModeChanged += OnFanControlModeChanged; + fanControl.SoftwareControlValueChanged += OnSoftwareControlValueChanged; + } + } + + //Fan Controls + TryAddFanControl(_fan1); + TryAddFanControl(_fan2); + TryAddFanControl(_fan3); + TryAddFanControl(_fan4); + TryAddFanControl(_fan5); + } + + private MsiSensor AddSensor(string name, int index, SensorType sensorType, GetMsiSensorValue getValue) + { + var sensor = new MsiSensor(name, index, sensorType, this, _settings, getValue); + + _sensors.Add(sensor); + + ActivateSensor(sensor); + + return sensor; + } + + private void OnFanControlModeChanged(Control control) + { + var msi = new MsiFanControl(); + + if (GetFanConfigure(msi) && GetFanTemperatureConfigure(msi)) + { + var fan = GetFanFromControl(msi, control); + + if (fan == null) + { + return; + } + + switch (control.ControlMode) + { + case ControlMode.Software: + fan.ConfigureDuty.Mode = MsiFanMode.Custom; + break; + case ControlMode.Default: + fan.ConfigureDuty.Mode = MsiFanMode.Bios; + break; + default: + return; + } + + SetFanConfigure(msi); + } + } + + private void OnSoftwareControlValueChanged(Control control) + { + var msi = new MsiFanControl(); + + if (GetFanConfigure(msi) && GetFanTemperatureConfigure(msi)) + { + var fan = GetFanFromControl(msi, control); + + if (fan == null) + { + return; + } + + byte value = (byte)control.SoftwareValue; + + if (value < 0) + { + value = 0; + } + else if (value > 100) + { + value = 100; + } + + //Set requested speed in % and CPU temperature in degrees Celsius + fan.ConfigureDuty.Item0 = value; + fan.ConfigureTemp.Item0 = 0; //Set temperature to 0 to use fixed duty instead of temperature curve + + fan.ConfigureDuty.Item1 = value; + fan.ConfigureTemp.Item1 = 90; + + //Add failsafe to prevent fan from stopping at high temperatures if user sets low duty + fan.ConfigureDuty.Item2 = 100; //Max fan + fan.ConfigureTemp.Item2 = 91; + + fan.ConfigureDuty.Item3 = 100; //Max fan + fan.ConfigureTemp.Item3 = 95; + + SetFanConfigure(msi); + SetFanTemperatureConfigure(msi); + } + } + + private MsiFan GetFanFromControl(MsiFanControl msi, Control control) + { + MsiFan fan = null; + + if (control.Sensor == _fan1) + fan = msi.Fan1; + else if (control.Sensor == _fan2) + fan = msi.Fan2; + else if (control.Sensor == _fan3) + fan = msi.Fan3; + else if (control.Sensor == _fan4) + fan = msi.Fan4; + else if (control.Sensor == _fan5) + fan = msi.Fan5; + + return fan; + } + + private bool GetCoolerStatus(MsiFanControl msi) + { + var buffer = GetBuffer(); + buffer[0] = 0xD0; + buffer[1] = 0x31; + + var data = GetData(buffer); + + if (data == null || data[1] != buffer[1]) + { + return false; + } + + msi.Fan1.Speed = GetInt16(data, 2); + msi.Fan2.Speed = GetInt16(data, 4); + msi.Fan3.Speed = GetInt16(data, 6); + msi.Fan4.Speed = GetInt16(data, 8); + msi.Fan5.Speed = GetInt16(data, 10); + + msi.TemperatureInlet = data[12]; + msi.TemperatureOutlet = data[14]; + msi.TemperatureSensor1 = GetInt16(data, 16); + msi.TemperatureSensor2 = GetInt16(data, 18); + + msi.Fan1.Duty = GetInt16(data, 22); + msi.Fan2.Duty = GetInt16(data, 24); + msi.Fan3.Duty = GetInt16(data, 26); + msi.Fan4.Duty = GetInt16(data, 28); + msi.Fan5.Duty = GetInt16(data, 30); + + return true; + } + + private bool GetFanConfigure(MsiFanControl msi) + { + var buffer = GetBuffer(); + buffer[0] = 0xD0; + buffer[1] = 0x32; + + var data = GetData(buffer); + + if (data == null || data[1] != buffer[1]) + { + return false; + } + + int startIndex = 2; + + msi.Fan1.ConfigureDuty = BytesToStruct(data, startIndex); + msi.Fan2.ConfigureDuty = BytesToStruct(data, startIndex += Marshal.SizeOf()); + msi.Fan3.ConfigureDuty = BytesToStruct(data, startIndex += Marshal.SizeOf()); + msi.Fan4.ConfigureDuty = BytesToStruct(data, startIndex += Marshal.SizeOf()); + msi.Fan5.ConfigureDuty = BytesToStruct(data, startIndex += Marshal.SizeOf()); + + return true; + } + + private bool GetFanTemperatureConfigure(MsiFanControl msi) + { + var buffer = GetBuffer(); + buffer[0] = 0xD0; + buffer[1] = 0x33; + + var data = GetData(buffer); + + if (data == null || (data[1] != buffer[1] && data[1] != 0x32)) + { + return false; + } + + int startIndex = 2; + + msi.Fan1.ConfigureTemp = BytesToStruct(data, startIndex); + msi.Fan2.ConfigureTemp = BytesToStruct(data, startIndex += Marshal.SizeOf()); + msi.Fan3.ConfigureTemp = BytesToStruct(data, startIndex += Marshal.SizeOf()); + msi.Fan4.ConfigureTemp = BytesToStruct(data, startIndex += Marshal.SizeOf()); + msi.Fan5.ConfigureTemp = BytesToStruct(data, startIndex += Marshal.SizeOf()); + + return true; + } + + private void SetFanConfigure(MsiFanControl msi) + { + var buffer = GetBuffer(); + buffer[0] = 0xD0; + buffer[1] = 0x40; + + int startIndex = 2; + + StructToBytes(msi.Fan1.ConfigureDuty, buffer, startIndex); + StructToBytes(msi.Fan2.ConfigureDuty, buffer, startIndex += Marshal.SizeOf()); + StructToBytes(msi.Fan3.ConfigureDuty, buffer, startIndex += Marshal.SizeOf()); + StructToBytes(msi.Fan4.ConfigureDuty, buffer, startIndex += Marshal.SizeOf()); + StructToBytes(msi.Fan5.ConfigureDuty, buffer, startIndex += Marshal.SizeOf()); + + SetData(buffer); + } + + private void SetFanTemperatureConfigure(MsiFanControl msi) + { + var buffer = GetBuffer(); + buffer[0] = 0xD0; + buffer[1] = 0x41; + + int startIndex = 2; + + StructToBytes(msi.Fan1.ConfigureTemp, buffer, startIndex); + StructToBytes(msi.Fan2.ConfigureTemp, buffer, startIndex += Marshal.SizeOf()); + StructToBytes(msi.Fan3.ConfigureTemp, buffer, startIndex += Marshal.SizeOf()); + StructToBytes(msi.Fan4.ConfigureTemp, buffer, startIndex += Marshal.SizeOf()); + StructToBytes(msi.Fan5.ConfigureTemp, buffer, startIndex += Marshal.SizeOf()); + + SetData(buffer); + } + + private static T BytesToStruct(byte[] data, int startIndex) where T : struct + { + int size = Marshal.SizeOf(); + + if (startIndex < 0 || startIndex + size > data.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + var handle = GCHandle.Alloc(data, GCHandleType.Pinned); + try + { + IntPtr ptr = handle.AddrOfPinnedObject() + startIndex; + return Marshal.PtrToStructure(ptr); + } + finally + { + handle.Free(); + } + } + + private static void StructToBytes(in T value, byte[] buffer, int startIndex) where T : struct + { + int size = Marshal.SizeOf(); + + if (startIndex < 0 || startIndex + size > buffer.Length) + { + throw new ArgumentOutOfRangeException(nameof(startIndex)); + } + + var handle = GCHandle.Alloc(buffer, GCHandleType.Pinned); + try + { + IntPtr ptr = handle.AddrOfPinnedObject() + startIndex; + Marshal.StructureToPtr(value, ptr, false); + } + finally + { + handle.Free(); + } + } + + private byte[] GetData(byte[] inbuf) + { + HidStream stream = null; + + if (!Mutexes.WaitUsbSensors(MutexTimeout)) + { + return null; + } + + try + { + var outBuf = new byte[DataLength]; + + if (!_hidDevice.TryOpen(out stream)) + { + return null; + } + + stream.Write(inbuf); + Thread.Sleep(10); //Msi is using that interval + var readResult = stream.Read(outBuf); + + if (readResult <= 0) + { + return null; + } + + return outBuf; + } + finally + { + stream?.Close(); + stream?.Dispose(); + + Mutexes.ReleaseUsbSensors(); + } + } + + private void SetData(byte[] buf) + { + HidStream stream = null; + + if (!Mutexes.WaitUsbSensors(MutexTimeout)) + { + return; + } + + try + { + if (!_hidDevice.TryOpen(out stream)) + { + return; + } + + stream.Write(buf); + } + finally + { + stream?.Close(); + stream?.Dispose(); + + Mutexes.ReleaseUsbSensors(); + } + } + + private byte[] GetBuffer() + { + return new byte[DataLength]; + } + + private static int GetInt16(byte[] buffer, int offset) + { + return buffer[offset] + (buffer[offset + 1] << 8); + } +} diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiDevice.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiDevice.cs new file mode 100644 index 0000000..575f69b --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiDevice.cs @@ -0,0 +1,80 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +public enum MsiDeviceType +{ + S280, + S360, + S360MEG, + X360, + X240, + D360, + D240, +} + +public class MsiDevice +{ + public MsiDevice(MsiDeviceType msiDeviceType, int vendorId, int productId, int productIdController) + { + DeviceType = msiDeviceType; + VendorId = vendorId; + ProductId = productId; + ProductIdController = productIdController; + } + + public MsiDeviceType DeviceType { get; } + public int VendorId { get; } + public int ProductId { get; } + public int ProductIdController { get; } + + public string Name + { + get + { + switch (DeviceType) + { + case MsiDeviceType.S280: + return "MSI CoreLiquid S280"; + case MsiDeviceType.S360: + return "MSI CoreLiquid S360"; + case MsiDeviceType.S360MEG: + return "MSI CoreLiquid S360 MEG"; + case MsiDeviceType.X360: + return "MSI CoreLiquid X360"; + case MsiDeviceType.X240: + return "MSI CoreLiquid X240"; + case MsiDeviceType.D360: + return "MSI CoreLiquid D360"; + case MsiDeviceType.D240: + return "MSI CoreLiquid D240"; + default: + return "Other"; + } + } + } + + //Relevant for further HWMonitoring later + public bool SupportsHWMonitorIndex13and14(uint firmwareVersion) + { + switch (DeviceType) + { + case MsiDeviceType.S280: + case MsiDeviceType.S360: + return (firmwareVersion & byte.MaxValue) >= 10; + case MsiDeviceType.S360MEG: + return (firmwareVersion & byte.MaxValue) >= 7; + case MsiDeviceType.X360: + case MsiDeviceType.X240: + return (firmwareVersion & byte.MaxValue) >= 3; + case MsiDeviceType.D360: + case MsiDeviceType.D240: + return true; + } + + return false; + } +} diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFan.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFan.cs new file mode 100644 index 0000000..9b59387 --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFan.cs @@ -0,0 +1,48 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +using System; +using System.Runtime.InteropServices; + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +public class MsiFan +{ + /// + /// Speed of Fan in RPM. + /// + public int Speed { get; set; } + public int Duty { get; set; } + + /// + /// Speed of Fan in percentage 0-100. This can e.g. be used to set fan curve when is . + /// + public MsiFanConfigure ConfigureDuty; + + /// + /// Temperature of Fan in degrees Celsius. This can e.g. be used to set fan curve when is . + /// + public MsiFanConfigure ConfigureTemp; +} + +public struct MsiFanConfigure +{ + public MsiFanConfigure() + { + if (Marshal.SizeOf() != 8) + { + throw new InvalidOperationException($"{nameof(MsiFanConfigure)} struct size is invalid."); + } + } + + public MsiFanMode Mode = MsiFanMode.Unknown; + public byte Item0; + public byte Item1; + public byte Item2; + public byte Item3; + public byte Item4; + public byte Item5; + public byte Item6; +} diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanControl.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanControl.cs new file mode 100644 index 0000000..e705e51 --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanControl.cs @@ -0,0 +1,21 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +public class MsiFanControl +{ + public MsiFan Fan1 { get; set; } = new(); + public MsiFan Fan2 { get; set; } = new(); + public MsiFan Fan3 { get; set; } = new(); + public MsiFan Fan4 { get; set; } = new(); + public MsiFan Fan5 { get; set; } = new(); + + public int TemperatureInlet { get; set; } + public int TemperatureOutlet { get; set; } + + public int TemperatureSensor1 { get; set; } + public int TemperatureSensor2 { get; set; } +} diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanMode.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanMode.cs new file mode 100644 index 0000000..ed4599f --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiFanMode.cs @@ -0,0 +1,16 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +public enum MsiFanMode : byte +{ + Silent = 0, + Bios = 1, + Game = 2, + Custom = 3, + Unknown = 4, + Smart = 5, +} diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiGroup.cs new file mode 100644 index 0000000..ecbf670 --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiGroup.cs @@ -0,0 +1,70 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using HidSharp; + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +internal class MsiGroup : IGroup +{ + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public MsiGroup(ISettings settings) + { + _report.AppendLine("MSI Hardware:"); + _report.AppendLine(); + + //Get all HID devices + var hidDevices = DeviceList.Local.GetHidDevices(); + + foreach (var hidDevice in hidDevices) + { + //Check if the device is in the supported devices list + var found = MsiConstants.SupportedDevices.FirstOrDefault(md => md.VendorId == hidDevice.VendorID && md.ProductIdController == hidDevice.ProductID); + + if (found == null) + { + continue; + } + + try + { + var coreLiquidController = new MsiCoreLiquidController(found, hidDevice, settings); + + _hardware.Add(coreLiquidController); + _report.AppendLine($"MSI Controller for '{hidDevice.GetProductName()}' ({hidDevice.VendorID:X4}:{hidDevice.ProductID:X4}) initialized successfully"); + } + catch (Exception e) + { + _report.AppendLine($"Msi Controller Plugin initialization failed: {e.Message}"); + } + } + } + + public IReadOnlyList Hardware => _hardware; + + public void Close() + { + foreach (Hardware hw in _hardware.OfType()) + { + hw.Close(); + } + } + + public string GetReport() + { + var sb = new StringBuilder(); + sb.AppendLine(_report.ToString()); + + _hardware.ForEach(hw => sb.AppendLine(hw.GetReport())); + + return sb.ToString(); + } +} diff --git a/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiSensor.cs b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiSensor.cs new file mode 100644 index 0000000..8c6bcae --- /dev/null +++ b/LibreHardwareMonitorLib/Hardware/Controller/MSI/MsiSensor.cs @@ -0,0 +1,26 @@ +// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. +// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/. +// Copyright (C) Florian K. (Blacktempel) +// All Rights Reserved. + +namespace LibreHardwareMonitor.Hardware.Controller.MSI; + +internal delegate float GetMsiSensorValue(MsiFanControl msi); + +internal class MsiSensor : Sensor +{ + private readonly GetMsiSensorValue _getValue; + + public MsiSensor(string name, int index, SensorType sensorType, Hardware hardware, ISettings settings, GetMsiSensorValue getValue) + : base(name, index, sensorType, hardware, settings) + { + _getValue = getValue; + } + + internal void Update(MsiFanControl msi) + { + float value = _getValue(msi); + + Value = value; + } +}