diff --git a/LibreHardwareMonitor/Resources/powermonitor.png b/LibreHardwareMonitor/Resources/powermonitor.png
new file mode 100644
index 0000000..ed99dd7
Binary files /dev/null and b/LibreHardwareMonitor/Resources/powermonitor.png differ
diff --git a/LibreHardwareMonitor/UI/HardwareTypeImage.cs b/LibreHardwareMonitor/UI/HardwareTypeImage.cs
index 0f8b8fc..3d867b8 100644
--- a/LibreHardwareMonitor/UI/HardwareTypeImage.cs
+++ b/LibreHardwareMonitor/UI/HardwareTypeImage.cs
@@ -63,6 +63,9 @@ public class HardwareTypeImage
case HardwareType.Battery:
image = Utilities.EmbeddedResources.GetImage("battery.png");
break;
+ case HardwareType.PowerMonitor:
+ image = Utilities.EmbeddedResources.GetImage("powermonitor.png");
+ break;
default:
image = new Bitmap(1, 1);
break;
@@ -70,4 +73,4 @@ public class HardwareTypeImage
_images.Add(hardwareType, image);
return image;
}
-}
\ No newline at end of file
+}
diff --git a/LibreHardwareMonitor/UI/MainForm.Designer.cs b/LibreHardwareMonitor/UI/MainForm.Designer.cs
index b9cca1d..0135057 100644
--- a/LibreHardwareMonitor/UI/MainForm.Designer.cs
+++ b/LibreHardwareMonitor/UI/MainForm.Designer.cs
@@ -56,6 +56,7 @@ namespace LibreHardwareMonitor.UI
this.cpuMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.ramMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.gpuMenuItem = new System.Windows.Forms.ToolStripMenuItem();
+ this.powerMonitorMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.fanControllerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.hddMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.nicMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -292,6 +293,7 @@ namespace LibreHardwareMonitor.UI
this.cpuMenuItem,
this.ramMenuItem,
this.gpuMenuItem,
+ this.powerMonitorMenuItem,
this.fanControllerMenuItem,
this.hddMenuItem,
this.nicMenuItem,
@@ -325,6 +327,12 @@ namespace LibreHardwareMonitor.UI
this.gpuMenuItem.Size = new System.Drawing.Size(180, 22);
this.gpuMenuItem.Text = "GPU";
//
+ // powerMonitorMenuItem
+ //
+ this.powerMonitorMenuItem.Name = "powerMonitorMenuItem";
+ this.powerMonitorMenuItem.Size = new System.Drawing.Size(180, 22);
+ this.powerMonitorMenuItem.Text = "Power Monitors";
+ //
// fanControllerMenuItem
//
this.fanControllerMenuItem.Name = "fanControllerMenuItem";
@@ -1176,6 +1184,7 @@ namespace LibreHardwareMonitor.UI
private System.Windows.Forms.ToolStripMenuItem mainboardMenuItem;
private System.Windows.Forms.ToolStripMenuItem cpuMenuItem;
private System.Windows.Forms.ToolStripMenuItem gpuMenuItem;
+ private System.Windows.Forms.ToolStripMenuItem powerMonitorMenuItem;
private System.Windows.Forms.ToolStripMenuItem fanControllerMenuItem;
private System.Windows.Forms.ToolStripMenuItem ramMenuItem;
private System.Windows.Forms.ToolStripMenuItem logSensorsMenuItem;
diff --git a/LibreHardwareMonitor/UI/MainForm.cs b/LibreHardwareMonitor/UI/MainForm.cs
index 72230a8..b98afb5 100644
--- a/LibreHardwareMonitor/UI/MainForm.cs
+++ b/LibreHardwareMonitor/UI/MainForm.cs
@@ -40,6 +40,7 @@ public sealed partial class MainForm : Form
private readonly UserOption _readCpuSensors;
private readonly UserOption _readFanControllersSensors;
private readonly UserOption _readGpuSensors;
+ private readonly UserOption _readPowerMonitorSensors;
private readonly UserOption _readHddSensors;
private readonly UserOption _readMainboardSensors;
private readonly UserOption _readNicSensors;
@@ -265,6 +266,9 @@ public sealed partial class MainForm : Form
_readGpuSensors = new UserOption("gpuMenuItem", true, gpuMenuItem, _settings);
_readGpuSensors.Changed += delegate { _computer.IsGpuEnabled = _readGpuSensors.Value; };
+ _readPowerMonitorSensors = new UserOption("powerMonitorMenuItem", true, powerMonitorMenuItem, _settings);
+ _readPowerMonitorSensors.Changed += delegate { _computer.IsPowerMonitorEnabled = _readPowerMonitorSensors.Value; };
+
_readFanControllersSensors = new UserOption("fanControllerMenuItem", true, fanControllerMenuItem, _settings);
_readFanControllersSensors.Changed += delegate { _computer.IsControllerEnabled = _readFanControllersSensors.Value; };
diff --git a/LibreHardwareMonitor/Utilities/HttpServer.cs b/LibreHardwareMonitor/Utilities/HttpServer.cs
index 51b7c04..a21af16 100644
--- a/LibreHardwareMonitor/Utilities/HttpServer.cs
+++ b/LibreHardwareMonitor/Utilities/HttpServer.cs
@@ -883,6 +883,8 @@ public class HttpServer
return "power-supply.png";
case HardwareType.Battery:
return "battery.png";
+ case HardwareType.PowerMonitor:
+ return "powermonitor.png";
default:
return "cpu.png";
}
@@ -896,6 +898,7 @@ public class HttpServer
case SensorType.Current:
return "voltage.png";
case SensorType.Clock:
+ case SensorType.Timing:
return "clock.png";
case SensorType.Load:
return "load.png";
diff --git a/LibreHardwareMonitorLib/Hardware/Computer.cs b/LibreHardwareMonitorLib/Hardware/Computer.cs
index 3790b9d..bb87340 100644
--- a/LibreHardwareMonitorLib/Hardware/Computer.cs
+++ b/LibreHardwareMonitorLib/Hardware/Computer.cs
@@ -23,6 +23,7 @@ using LibreHardwareMonitor.Hardware.Gpu;
using LibreHardwareMonitor.Hardware.Memory;
using LibreHardwareMonitor.Hardware.Motherboard;
using LibreHardwareMonitor.Hardware.Network;
+using LibreHardwareMonitor.Hardware.PowerMonitor;
using LibreHardwareMonitor.Hardware.Psu.Corsair;
using LibreHardwareMonitor.Hardware.Psu.Msi;
using LibreHardwareMonitor.Hardware.Storage;
@@ -42,6 +43,7 @@ public class Computer : IComputer
private bool _controllerEnabled;
private bool _cpuEnabled;
private bool _gpuEnabled;
+ private bool _powerMonitorEnabled;
private bool _memoryEnabled;
private bool _motherboardEnabled;
private bool _networkEnabled;
@@ -194,6 +196,24 @@ public class Computer : IComputer
}
}
+ ///
+ public bool IsPowerMonitorEnabled
+ {
+ get { return _powerMonitorEnabled; }
+ set
+ {
+ if (_open && value != _powerMonitorEnabled)
+ {
+ if (value)
+ Add(new PowerMonitorGroup(_settings));
+ else
+ RemoveType();
+ }
+
+ _powerMonitorEnabled = value;
+ }
+ }
+
///
public bool IsMemoryEnabled
{
@@ -520,6 +540,9 @@ public class Computer : IComputer
Add(new IntelGpuGroup(GetIntelCpus(), _settings));
}
+ if (_powerMonitorEnabled)
+ Add(new PowerMonitorGroup(_settings));
+
if (_controllerEnabled)
{
Add(new TBalancerGroup(_settings));
diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs
index e70e246..8e9b479 100644
--- a/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs
+++ b/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs
@@ -3,15 +3,10 @@
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
-using System.Collections.Generic;
-using LibreHardwareMonitor.Hardware.Gpu.PowerMonitor;
-
namespace LibreHardwareMonitor.Hardware.Gpu;
public abstract class GenericGpu : Hardware
{
- readonly List _subHardware = new();
-
///
/// Initializes a new instance of the class.
///
@@ -20,7 +15,6 @@ public abstract class GenericGpu : Hardware
/// Additional settings passed by the .
protected GenericGpu(string name, Identifier identifier, ISettings settings) : base(name, identifier, settings)
{
- TryAddSubHardware();
}
///
@@ -28,21 +22,8 @@ public abstract class GenericGpu : Hardware
///
public abstract string DeviceId { get; }
- public override IHardware[] SubHardware => _subHardware.ToArray();
-
public override void Close()
{
- _subHardware.ForEach(h => h.Close());
-
base.Close();
}
-
- private void TryAddSubHardware()
- {
- var wireViewPro2 = WireViewPro2.TryFindDevice(_settings);
- if (wireViewPro2 != null && wireViewPro2.IsConnected)
- {
- _subHardware.Add(wireViewPro2);
- }
- }
}
diff --git a/LibreHardwareMonitorLib/Hardware/HardwareType.cs b/LibreHardwareMonitorLib/Hardware/HardwareType.cs
index e6fec96..e775271 100644
--- a/LibreHardwareMonitorLib/Hardware/HardwareType.cs
+++ b/LibreHardwareMonitorLib/Hardware/HardwareType.cs
@@ -24,5 +24,5 @@ public enum HardwareType
EmbeddedController,
Psu,
Battery,
- GpuPowerMonitor,
+ PowerMonitor,
}
diff --git a/LibreHardwareMonitorLib/Hardware/IComputer.cs b/LibreHardwareMonitorLib/Hardware/IComputer.cs
index e3a0738..d8933d8 100644
--- a/LibreHardwareMonitorLib/Hardware/IComputer.cs
+++ b/LibreHardwareMonitorLib/Hardware/IComputer.cs
@@ -78,6 +78,12 @@ public interface IComputer : IElement
/// if a given category of devices is already enabled.
bool IsGpuEnabled { get; }
+ ///
+ /// Gets or sets a value indicating whether collecting information about devices should be enabled and updated.
+ ///
+ /// if a given category of devices is already enabled.
+ bool IsPowerMonitorEnabled { get; }
+
///
/// Gets or sets a value indicating whether collecting information about devices should be enabled and updated.
///
diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/IPowerMonitor.cs b/LibreHardwareMonitorLib/Hardware/PowerMonitor/IPowerMonitor.cs
similarity index 88%
rename from LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/IPowerMonitor.cs
rename to LibreHardwareMonitorLib/Hardware/PowerMonitor/IPowerMonitor.cs
index 1f69105..a7356bb 100644
--- a/LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/IPowerMonitor.cs
+++ b/LibreHardwareMonitorLib/Hardware/PowerMonitor/IPowerMonitor.cs
@@ -4,7 +4,7 @@
// Partial Copyright (C) Michael Möller and Contributors.
// All Rights Reserved.
-namespace LibreHardwareMonitor.Hardware.Gpu.PowerMonitor;
+namespace LibreHardwareMonitor.Hardware.PowerMonitor;
internal interface IPowerMonitor
{
diff --git a/LibreHardwareMonitorLib/Hardware/PowerMonitor/PowerMonitorGroup.cs b/LibreHardwareMonitorLib/Hardware/PowerMonitor/PowerMonitorGroup.cs
new file mode 100644
index 0000000..9fc2fa2
--- /dev/null
+++ b/LibreHardwareMonitorLib/Hardware/PowerMonitor/PowerMonitorGroup.cs
@@ -0,0 +1,54 @@
+// 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;
+using System.Linq;
+using System.Text;
+
+namespace LibreHardwareMonitor.Hardware.PowerMonitor;
+
+internal class PowerMonitorGroup : IGroup
+{
+ private readonly List _hardware = new();
+ private readonly StringBuilder _report = new();
+
+ public PowerMonitorGroup(ISettings settings)
+ {
+ _report.AppendLine("Power Monitors:");
+ _report.AppendLine();
+
+ var devices = WireViewPro2.TryFindDevices(settings);
+
+ devices.ForEach(wvp2 =>
+ {
+ if (wvp2.IsConnected)
+ {
+ _report.AppendLine($"Power Monitor for '{wvp2.Name}' initialized successfully");
+
+ _hardware.Add(wvp2);
+ }
+ });
+ }
+
+ 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/Gpu/PowerMonitor/SharedSerialPort.cs b/LibreHardwareMonitorLib/Hardware/PowerMonitor/SharedSerialPort.cs
similarity index 97%
rename from LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/SharedSerialPort.cs
rename to LibreHardwareMonitorLib/Hardware/PowerMonitor/SharedSerialPort.cs
index 8bb3be6..84ea4e5 100644
--- a/LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/SharedSerialPort.cs
+++ b/LibreHardwareMonitorLib/Hardware/PowerMonitor/SharedSerialPort.cs
@@ -1,6 +1,6 @@
using System.IO.Ports;
-namespace LibreHardwareMonitor.Hardware.Gpu.PowerMonitor;
+namespace LibreHardwareMonitor.Hardware.PowerMonitor;
internal sealed class SharedSerialPort : SerialPort
{
diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/WireViewPro2.cs b/LibreHardwareMonitorLib/Hardware/PowerMonitor/WireViewPro2.cs
similarity index 60%
rename from LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/WireViewPro2.cs
rename to LibreHardwareMonitorLib/Hardware/PowerMonitor/WireViewPro2.cs
index 81c3825..b5da949 100644
--- a/LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/WireViewPro2.cs
+++ b/LibreHardwareMonitorLib/Hardware/PowerMonitor/WireViewPro2.cs
@@ -1,13 +1,19 @@
-using System;
+// 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.Diagnostics;
+using System.IO;
using System.IO.Ports;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using LibreHardwareMonitor.Interop.PowerMonitor;
-namespace LibreHardwareMonitor.Hardware.Gpu.PowerMonitor;
+namespace LibreHardwareMonitor.Hardware.PowerMonitor;
///
/// Thermal Grizzly WireView Pro II power monitor.
@@ -16,9 +22,22 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
{
public const string WelcomeMessage = "Thermal Grizzly WireView Pro II";
+ ///
+ /// Max RPM according to the8auer. This is a custom made fan.
+ ///
+ private const int MaxFanRPM = 5000;
+
private const byte VendorID = 0xEF;
private const byte ProductID = 0x05;
+ ///
+ /// Time the fan needs to ramp up by 10%.
+ ///
+ private static readonly TimeSpan FanRampupTime = TimeSpan.FromSeconds(3.5);
+
+ private double _lastFanSpeedRpm;
+ private DateTime _lastFanUpdateTime = DateTime.MinValue;
+
private readonly int _baudRate;
private readonly string _portName;
private readonly List _sensors = [];
@@ -39,7 +58,7 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
}
}
- public override HardwareType HardwareType => HardwareType.GpuPowerMonitor;
+ public override HardwareType HardwareType => HardwareType.PowerMonitor;
public bool IsConnected { get; private set; }
@@ -49,11 +68,13 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
public int ConfigVersion => VendorData?.FwVersion > 2 ? 1 : 0;
- public static WireViewPro2 TryFindDevice(ISettings settings)
+ public static List TryFindDevices(ISettings settings)
{
+ var devices = new List();
+
if (!Software.OperatingSystem.IsWindows8OrGreater)
{
- return null; //No Linux implementation yet
+ return devices; //No Linux implementation yet
}
List matches = Stm32PortFinder.FindMatchingComPorts(0x0483, 0x5740);
@@ -67,7 +88,8 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
wireViewPro2 = new WireViewPro2(port, settings);
if (wireViewPro2.IsConnected)
{
- break;
+ devices.Add(wireViewPro2);
+ continue;
}
wireViewPro2.Close();
@@ -80,7 +102,7 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
}
}
- return wireViewPro2;
+ return devices;
}
public override string GetReport()
@@ -93,6 +115,15 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
sb.AppendLine($" Sensor: {sensor.Name} = {sensor.Value}");
}
+ if (VendorData.HasValue)
+ {
+ sb.AppendLine($" {nameof(VendorData.Value.VendorId)} = {VendorData.Value.VendorId}");
+ sb.AppendLine($" {nameof(VendorData.Value.ProductId)} = {VendorData.Value.ProductId}");
+ sb.AppendLine($" {nameof(VendorData.Value.FwVersion)} = {VendorData.Value.FwVersion}");
+ }
+
+ sb.AppendLine($" {nameof(UniqueID)} = {UniqueID}");
+
return sb.ToString();
}
@@ -105,15 +136,43 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
public override void Update()
{
- SensorStruct? sensorValues = ReadSensorValues();
- if (sensorValues.HasValue)
- {
- DeviceData deviceData = MapSensorStructure(sensorValues.Value);
+ var deviceData = GetDeviceData();
+ if (deviceData != null)
+ {
_sensors.ForEach(wvps => wvps.Update(deviceData));
}
}
+ public DeviceData GetDeviceData()
+ {
+ SensorStruct? sensorValues = null;
+ DeviceConfigStructV2? config = null;
+
+ try
+ {
+ sensorValues = ReadSensorValues();
+
+ config = ReadConfig();
+ }
+ catch (IOException)
+ {
+ //"A device attached to the system is not functioning."
+ //Can happen rarely
+ }
+ catch (InvalidOperationException)
+ {
+ //Can happen sometimes if the device is disconnecting while reading
+ }
+
+ if (sensorValues.HasValue && config.HasValue)
+ {
+ return MapSensorStructure(sensorValues.Value, config.Value);
+ }
+
+ return null;
+ }
+
public DeviceConfigStructV2? ReadConfig()
{
if (!IsConnected)
@@ -123,41 +182,34 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
int size = 0;
- try
+ switch (ConfigVersion)
{
- switch (ConfigVersion)
- {
- case 0:
- size = Marshal.SizeOf();
- break;
- case 1:
- size = Marshal.SizeOf();
- break;
- default:
- return null;
- }
-
- var buf = SendCmd(UsbCmd.CMD_READ_CONFIG, size);
-
- if (buf == null)
- {
+ case 0:
+ size = Marshal.SizeOf();
+ break;
+ case 1:
+ size = Marshal.SizeOf();
+ break;
+ default:
return null;
- }
-
- switch (ConfigVersion)
- {
- case 0:
- var s = BytesToStructure(buf);
- return StructureConversion.ConvertConfigV1ToV2(s);
- case 1:
- return BytesToStructure(buf);
- default:
- return null;
- }
}
- finally
+
+ var buf = SendCmd(UsbCmd.CMD_READ_CONFIG, size);
+
+ if (buf == null)
{
- _serialPort.Close();
+ return null;
+ }
+
+ switch (ConfigVersion)
+ {
+ case 0:
+ var s = BytesToStructure(buf);
+ return StructureConversion.ConvertConfigV1ToV2(s);
+ case 1:
+ return BytesToStructure(buf);
+ default:
+ return null;
}
}
@@ -283,15 +335,204 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
//Power
AddSensor("Total Power", 30, SensorType.Power, dd => (float)dd.SumPowerW);
+
+ //Fan
+ var fan = AddSensor("Fan", 40, SensorType.Fan, dd => CalculateFanSpeed(dd));
+ var fanControl = new Control(fan, _settings, 0, 100);
+
+ fan.Control = fanControl;
+ fanControl.ControlModeChanged += OnFanControlModeChanged;
+ fanControl.SoftwareControlValueChanged += OnSoftwareControlValueChanged;
}
- private void AddSensor(string name, int index, SensorType sensorType, GetWireViewPro2SensorValue getValue)
+ private WireViewPro2Sensor AddSensor(string name, int index, SensorType sensorType, GetWireViewPro2SensorValue getValue)
{
var sensor = new WireViewPro2Sensor(name, index, sensorType, this, _settings, getValue);
_sensors.Add(sensor);
ActivateSensor(sensor);
+
+ return sensor;
+ }
+
+ private double FromTemp(short temp)
+ {
+ return temp == 0 ? 0 : temp / 10.0;
+ }
+
+ private short ToTemp(double temp)
+ {
+ return (short)(temp * 10);
+ }
+
+ private void OnFanControlModeChanged(Control control)
+ {
+ var deviceData = GetDeviceData();
+
+ if (deviceData == null)
+ {
+ return;
+ }
+
+ switch (control.ControlMode)
+ {
+ case ControlMode.Software:
+ deviceData.Config.FanConfig.Mode = FanMode.FanModeFixed;
+ break;
+ case ControlMode.Default:
+ //Set default values of TG Software
+ deviceData.Config.FanConfig.Mode = FanMode.FanModeCurve;
+ deviceData.Config.FanConfig.TempSource = TempSource.TempSourceTmax;
+
+ deviceData.Config.FanConfig.TempMin = ToTemp(50);
+ deviceData.Config.FanConfig.TempMax = ToTemp(80);
+
+ deviceData.Config.FanConfig.DutyMin = 0;
+ deviceData.Config.FanConfig.DutyMax = 100;
+ break;
+ default:
+ break;
+ }
+
+ WriteConfig(deviceData.Config);
+ }
+
+ private void OnSoftwareControlValueChanged(Control control)
+ {
+ var deviceData = GetDeviceData();
+
+ if (deviceData == null)
+ {
+ return;
+ }
+
+ byte value = (byte)control.SoftwareValue;
+
+ if (value < 0)
+ {
+ value = 0;
+ }
+ else if (value > 100)
+ {
+ value = 100;
+ }
+
+ deviceData.Config.FanConfig.TempMin = ToTemp(0);
+ deviceData.Config.FanConfig.TempMax = ToTemp(80);
+
+ deviceData.Config.FanConfig.DutyMin = value;
+ deviceData.Config.FanConfig.DutyMax = value;
+
+ WriteConfig(deviceData.Config);
+ }
+
+ ///
+ /// Fan speed for this device is an approximation based on the curve configuration and current temperatures.
+ /// The device itself does not report actual fan speed.
+ ///
+ private float CalculateFanSpeed(DeviceData dd)
+ {
+ var fanConfig = dd.Config.FanConfig;
+ double targetRpm;
+
+ switch (fanConfig.Mode)
+ {
+ case FanMode.FanModeCurve:
+ var tempMin = FromTemp(fanConfig.TempMin);
+ var tempMax = FromTemp(fanConfig.TempMax);
+ var currentTemperature = GetActiveTemperature(dd);
+
+ if (tempMax <= tempMin || currentTemperature <= tempMin)
+ {
+ targetRpm = fanConfig.DutyMin;
+ }
+ else if (currentTemperature >= tempMax)
+ {
+ targetRpm = fanConfig.DutyMax;
+ }
+ else
+ {
+ var temp = (currentTemperature - tempMin) / (tempMax - tempMin);
+ var fanSpeedInPercent = fanConfig.DutyMin + temp * (fanConfig.DutyMax - fanConfig.DutyMin);
+ targetRpm = fanSpeedInPercent;
+ }
+
+ targetRpm = targetRpm == 0 ? 0 : targetRpm / 100.0 * MaxFanRPM;
+ break;
+ case FanMode.FanModeFixed:
+ targetRpm = fanConfig.DutyMin == 0 ? 0 : fanConfig.DutyMin / 100.0 * MaxFanRPM;
+ break;
+ default:
+ return -1;
+ }
+
+ return (float)ApplyFanRamp(targetRpm);
+ }
+
+ private double ApplyFanRamp(double targetRpm)
+ {
+ var now = DateTime.UtcNow;
+
+ if (_lastFanUpdateTime == DateTime.MinValue)
+ {
+ _lastFanSpeedRpm = targetRpm;
+ _lastFanUpdateTime = now;
+ return targetRpm;
+ }
+
+ var elapsed = now - _lastFanUpdateTime;
+
+ if (elapsed <= TimeSpan.Zero)
+ {
+ return _lastFanSpeedRpm;
+ }
+
+ var maxPercentDeltaPerSecond = 0.1 / FanRampupTime.TotalSeconds; //10% per FanRampupTime
+ var allowedPercentDelta = elapsed.TotalSeconds * maxPercentDeltaPerSecond;
+
+ var rpmDelta = targetRpm - _lastFanSpeedRpm;
+ var percentDelta = rpmDelta / MaxFanRPM;
+
+ if (Math.Abs(percentDelta) > allowedPercentDelta)
+ {
+ rpmDelta = Math.Sign(percentDelta) * allowedPercentDelta * MaxFanRPM;
+ }
+
+ _lastFanSpeedRpm += rpmDelta;
+ _lastFanUpdateTime = now;
+
+ return _lastFanSpeedRpm;
+ }
+
+ private double GetActiveTemperature(DeviceData dd)
+ {
+ double temperature = 0;
+
+ switch (dd.Config.FanConfig.TempSource)
+ {
+ case TempSource.TempSourceTsIn:
+ temperature = dd.OnboardTempInC;
+ break;
+ case TempSource.TempSourceTsOut:
+ temperature = dd.OnboardTempOutC;
+ break;
+ case TempSource.TempSourceTs1:
+ temperature = dd.ExternalTemp1C;
+ break;
+ case TempSource.TempSourceTs2:
+ temperature = dd.ExternalTemp2C;
+ break;
+ case TempSource.TempSourceTmax:
+ temperature = Math.Max(
+ Math.Max(dd.OnboardTempInC, dd.OnboardTempOutC),
+ Math.Max(dd.ExternalTemp1C, dd.ExternalTemp2C));
+ break;
+ default:
+ break;
+ }
+
+ return temperature;
}
private void Connect()
@@ -408,7 +649,7 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
return bytes == null ? null : BytesToStructure(bytes);
}
- private DeviceData MapSensorStructure(SensorStruct sensorStruct)
+ private DeviceData MapSensorStructure(SensorStruct sensorStruct, DeviceConfigStructV2 config)
{
var deviceData = new DeviceData
{
@@ -421,6 +662,7 @@ public sealed class WireViewPro2 : Hardware, IPowerMonitor
ExternalTemp2C = sensorStruct.Ts[(int)SensorTs.SENSOR_TS4] / 10.0,
FaultStatus = sensorStruct.FaultStatus,
FaultLog = sensorStruct.FaultLog,
+ Config = config,
};
switch (sensorStruct.HpwrCapability)
diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/WireViewPro2Sensor.cs b/LibreHardwareMonitorLib/Hardware/PowerMonitor/WireViewPro2Sensor.cs
similarity index 94%
rename from LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/WireViewPro2Sensor.cs
rename to LibreHardwareMonitorLib/Hardware/PowerMonitor/WireViewPro2Sensor.cs
index e074a59..88d414a 100644
--- a/LibreHardwareMonitorLib/Hardware/Gpu/PowerMonitor/WireViewPro2Sensor.cs
+++ b/LibreHardwareMonitorLib/Hardware/PowerMonitor/WireViewPro2Sensor.cs
@@ -6,7 +6,7 @@
using LibreHardwareMonitor.Interop.PowerMonitor;
-namespace LibreHardwareMonitor.Hardware.Gpu.PowerMonitor;
+namespace LibreHardwareMonitor.Hardware.PowerMonitor;
internal delegate float GetWireViewPro2SensorValue(DeviceData wvp);
diff --git a/LibreHardwareMonitorLib/Interop/PowerMonitor/DeviceData.cs b/LibreHardwareMonitorLib/Interop/PowerMonitor/DeviceData.cs
index 63d5d6e..4e97d21 100644
--- a/LibreHardwareMonitorLib/Interop/PowerMonitor/DeviceData.cs
+++ b/LibreHardwareMonitorLib/Interop/PowerMonitor/DeviceData.cs
@@ -9,7 +9,7 @@ using System.Linq;
namespace LibreHardwareMonitor.Interop.PowerMonitor;
-internal sealed class DeviceData
+public sealed class DeviceData
{
public DateTime Timestamp { get; set; } = DateTime.UtcNow;
@@ -40,4 +40,6 @@ internal sealed class DeviceData
public ushort FaultStatus { get; set; }
public ushort FaultLog { get; set; }
+
+ public DeviceConfigStructV2 Config;
}