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
This commit is contained in:
@@ -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<NzxtGroup>();
|
||||
RemoveType<RazerGroup>();
|
||||
RemoveType<ArcticGroup>();
|
||||
RemoveType<MsiGroup>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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<MsiDevice> SupportedDevices = new List<MsiDevice>
|
||||
{
|
||||
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),
|
||||
};
|
||||
}
|
||||
@@ -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<MsiSensor> _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<MsiFanConfigure>(data, startIndex);
|
||||
msi.Fan2.ConfigureDuty = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
msi.Fan3.ConfigureDuty = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
msi.Fan4.ConfigureDuty = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
msi.Fan5.ConfigureDuty = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
|
||||
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<MsiFanConfigure>(data, startIndex);
|
||||
msi.Fan2.ConfigureTemp = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
msi.Fan3.ConfigureTemp = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
msi.Fan4.ConfigureTemp = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
msi.Fan5.ConfigureTemp = BytesToStruct<MsiFanConfigure>(data, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
|
||||
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<MsiFanConfigure>());
|
||||
StructToBytes(msi.Fan3.ConfigureDuty, buffer, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
StructToBytes(msi.Fan4.ConfigureDuty, buffer, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
StructToBytes(msi.Fan5.ConfigureDuty, buffer, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
|
||||
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<MsiFanConfigure>());
|
||||
StructToBytes(msi.Fan3.ConfigureTemp, buffer, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
StructToBytes(msi.Fan4.ConfigureTemp, buffer, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
StructToBytes(msi.Fan5.ConfigureTemp, buffer, startIndex += Marshal.SizeOf<MsiFanConfigure>());
|
||||
|
||||
SetData(buffer);
|
||||
}
|
||||
|
||||
private static T BytesToStruct<T>(byte[] data, int startIndex) where T : struct
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
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<T>(ptr);
|
||||
}
|
||||
finally
|
||||
{
|
||||
handle.Free();
|
||||
}
|
||||
}
|
||||
|
||||
private static void StructToBytes<T>(in T value, byte[] buffer, int startIndex) where T : struct
|
||||
{
|
||||
int size = Marshal.SizeOf<T>();
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Speed of Fan in RPM.
|
||||
/// </summary>
|
||||
public int Speed { get; set; }
|
||||
public int Duty { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Speed of Fan in percentage 0-100. This can e.g. be used to set fan curve when <see cref="MsiFanConfigure.Mode"/> is <see cref="MsiFanMode.Custom"/>.
|
||||
/// </summary>
|
||||
public MsiFanConfigure ConfigureDuty;
|
||||
|
||||
/// <summary>
|
||||
/// Temperature of Fan in degrees Celsius. This can e.g. be used to set fan curve when <see cref="MsiFanConfigure.Mode"/> is <see cref="MsiFanMode.Custom"/>.
|
||||
/// </summary>
|
||||
public MsiFanConfigure ConfigureTemp;
|
||||
}
|
||||
|
||||
public struct MsiFanConfigure
|
||||
{
|
||||
public MsiFanConfigure()
|
||||
{
|
||||
if (Marshal.SizeOf<MsiFanConfigure>() != 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;
|
||||
}
|
||||
@@ -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; }
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
@@ -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<IHardware> _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<IHardware> Hardware => _hardware;
|
||||
|
||||
public void Close()
|
||||
{
|
||||
foreach (Hardware hw in _hardware.OfType<Hardware>())
|
||||
{
|
||||
hw.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public string GetReport()
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
sb.AppendLine(_report.ToString());
|
||||
|
||||
_hardware.ForEach(hw => sb.AppendLine(hw.GetReport()));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user