From 58cef111a12e541bb3d1c1723a05fc4c543fb045 Mon Sep 17 00:00:00 2001 From: PhyxionNL <7643972+PhyxionNL@users.noreply.github.com> Date: Sun, 9 Oct 2022 13:22:57 +0200 Subject: [PATCH] Use file-scoped namespaces (#842) --- .editorconfig | 1 - LibreHardwareMonitor/Program.cs | 91 +- LibreHardwareMonitor/UI/AboutBox.cs | 45 +- LibreHardwareMonitor/UI/AuthForm.cs | 69 +- LibreHardwareMonitor/UI/Gadget.cs | 329 +- LibreHardwareMonitor/UI/GadgetWindow.cs | 1059 ++- LibreHardwareMonitor/UI/HardwareNode.cs | 241 +- LibreHardwareMonitor/UI/HardwareTypeImage.cs | 117 +- LibreHardwareMonitor/UI/IExpandPersistNode.cs | 11 +- LibreHardwareMonitor/UI/MainForm.cs | 2043 +++--- LibreHardwareMonitor/UI/Node.cs | 295 +- .../UI/NodeToolTipProvider.cs | 11 +- LibreHardwareMonitor/UI/NotifyIconAdv.cs | 1463 ++-- LibreHardwareMonitor/UI/ParameterForm.cs | 225 +- LibreHardwareMonitor/UI/PlotPanel.cs | 711 +- LibreHardwareMonitor/UI/PortForm.cs | 135 +- LibreHardwareMonitor/UI/ScaledPlotModel.cs | 45 +- LibreHardwareMonitor/UI/SensorGadget.cs | 1386 ++-- LibreHardwareMonitor/UI/SensorNode.cs | 433 +- LibreHardwareMonitor/UI/SensorNotifyIcon.cs | 497 +- LibreHardwareMonitor/UI/ShowDesktop.cs | 277 +- LibreHardwareMonitor/UI/SplitContainerAdv.cs | 221 +- LibreHardwareMonitor/UI/StartupManager.cs | 267 +- LibreHardwareMonitor/UI/SystemTray.cs | 307 +- .../UI/ToolStripRadioButtonMenuItem.cs | 445 +- LibreHardwareMonitor/UI/TreeModel.cs | 189 +- LibreHardwareMonitor/UI/TypeNode.cs | 241 +- LibreHardwareMonitor/UI/UnitManager.cs | 54 +- LibreHardwareMonitor/UI/UpdateVisitor.cs | 35 +- LibreHardwareMonitor/UI/UserOption.cs | 89 +- LibreHardwareMonitor/UI/UserRadioGroup.cs | 93 +- .../Utilities/EmbeddedResources.cs | 75 +- LibreHardwareMonitor/Utilities/HttpServer.cs | 1065 ++- LibreHardwareMonitor/Utilities/IconFactory.cs | 355 +- LibreHardwareMonitor/Utilities/Logger.cs | 317 +- .../Utilities/PersistentSettings.cs | 369 +- LibreHardwareMonitor/WMI/Hardware.cs | 47 +- LibreHardwareMonitor/WMI/IWmiObject.cs | 21 +- LibreHardwareMonitor/WMI/Sensor.cs | 77 +- .../Hardware/Battery/Battery.cs | 399 +- .../Hardware/Battery/BatteryGroup.cs | 321 +- .../Hardware/CompositeSensor.cs | 57 +- LibreHardwareMonitorLib/Hardware/Computer.cs | 1299 ++-- LibreHardwareMonitorLib/Hardware/Control.cs | 153 +- .../Controller/AeroCool/AeroCoolGroup.cs | 73 +- .../Hardware/Controller/AeroCool/P7-H1.cs | 153 +- .../AquaComputer/AquaComputerGroup.cs | 155 +- .../Controller/AquaComputer/AquastreamXT.cs | 270 +- .../Controller/AquaComputer/D5Next.cs | 99 +- .../Hardware/Controller/AquaComputer/MPS.cs | 173 +- .../Hardware/Controller/AquaComputer/Octo.cs | 339 +- .../Controller/Heatmaster/Heatmaster.cs | 507 +- .../Controller/Heatmaster/HeatmasterGroup.cs | 289 +- .../Hardware/Controller/Nzxt/GridV3.cs | 305 +- .../Hardware/Controller/Nzxt/KrakenX3.cs | 269 +- .../Hardware/Controller/Nzxt/NzxtGroup.cs | 115 +- .../Controller/TBalancer/TBalancer.cs | 583 +- .../Controller/TBalancer/TBalancerGroup.cs | 259 +- .../Hardware/Cpu/Amd0FCpu.cs | 259 +- .../Hardware/Cpu/Amd10Cpu.cs | 839 ++- .../Hardware/Cpu/Amd17Cpu.cs | 1027 ++- .../Hardware/Cpu/AmdCpu.cs | 49 +- .../Hardware/Cpu/CpuGroup.cs | 383 +- LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs | 479 +- .../Hardware/Cpu/CpuLoad.cs | 183 +- .../Hardware/Cpu/GenericCpu.cs | 513 +- .../Hardware/Cpu/IntelCpu.cs | 1299 ++-- .../Hardware/D3DDisplayDevice.cs | 461 +- .../Hardware/FirmwareTable.cs | 145 +- .../Hardware/Gpu/AmdGpu.cs | 1387 ++-- .../Hardware/Gpu/AmdGpuGroup.cs | 179 +- .../Hardware/Gpu/GenericGpu.cs | 35 +- .../Hardware/Gpu/IntelGpuGroup.cs | 123 +- .../Hardware/Gpu/IntelIntegratedGpu.cs | 203 +- .../Hardware/Gpu/NvidiaGpu.cs | 2131 +++--- .../Hardware/Gpu/NvidiaGroup.cs | 133 +- .../Hardware/GroupAffinity.cs | 163 +- LibreHardwareMonitorLib/Hardware/Hardware.cs | 203 +- .../Hardware/HardwareType.cs | 41 +- LibreHardwareMonitorLib/Hardware/IComputer.cs | 183 +- LibreHardwareMonitorLib/Hardware/IControl.cs | 51 +- LibreHardwareMonitorLib/Hardware/IElement.cs | 31 +- LibreHardwareMonitorLib/Hardware/IGroup.cs | 37 +- LibreHardwareMonitorLib/Hardware/IHardware.cs | 117 +- .../Hardware/IHardwareChanged.cs | 13 +- .../Hardware/IParameter.cs | 67 +- LibreHardwareMonitorLib/Hardware/ISensor.cs | 231 +- .../Hardware/ISensorLimits.cs | 53 +- LibreHardwareMonitorLib/Hardware/ISettings.cs | 55 +- LibreHardwareMonitorLib/Hardware/IVisitor.cs | 51 +- .../Hardware/Identifier.cs | 211 +- LibreHardwareMonitorLib/Hardware/InpOut.cs | 327 +- .../Hardware/KernelDriver.cs | 309 +- .../Hardware/Memory/GenericLinuxMemory.cs | 129 +- .../Hardware/Memory/GenericWindowsMemory.cs | 91 +- .../Hardware/Memory/MemoryGroup.cs | 35 +- .../Hardware/Motherboard/Identification.cs | 723 +- .../Hardware/Motherboard/Lpc/Chip.cs | 257 +- .../Motherboard/Lpc/EC/EmbeddedController.cs | 851 ++- .../Lpc/EC/EmbeddedControllerReader.cs | 7 +- .../Lpc/EC/EmbeddedControllerSource.cs | 45 +- .../Lpc/EC/IEmbeddedControllerIO.cs | 11 +- .../Lpc/EC/WindowsEmbeddedController.cs | 21 +- .../Lpc/EC/WindowsEmbeddedControllerIO.cs | 447 +- .../Hardware/Motherboard/Lpc/F718XX.cs | 301 +- .../Hardware/Motherboard/Lpc/ISuperIO.cs | 35 +- .../Hardware/Motherboard/Lpc/IT87XX.cs | 933 ++- .../Hardware/Motherboard/Lpc/LMSensors.cs | 511 +- .../Hardware/Motherboard/Lpc/LPcPort.cs | 181 +- .../Hardware/Motherboard/Lpc/LpcIO.cs | 1197 ++- .../Hardware/Motherboard/Lpc/Nct677X.cs | 1807 +++-- .../Hardware/Motherboard/Lpc/W836XX.cs | 905 ++- .../Hardware/Motherboard/Manufacturer.cs | 95 +- .../Hardware/Motherboard/Model.cs | 287 +- .../Hardware/Motherboard/Motherboard.cs | 299 +- .../Hardware/Motherboard/MotherboardGroup.cs | 45 +- .../Hardware/Motherboard/SuperIOHardware.cs | 6459 ++++++++--------- .../Hardware/Network/Network.cs | 177 +- .../Hardware/Network/NetworkGroup.cs | 235 +- LibreHardwareMonitorLib/Hardware/OpCode.cs | 527 +- LibreHardwareMonitorLib/Hardware/Parameter.cs | 149 +- .../Hardware/ParameterDescription.cs | 61 +- .../Hardware/Psu/Corsair/CorsairPsu.cs | 887 ++- .../Hardware/Psu/Corsair/CorsairPsuGroup.cs | 103 +- LibreHardwareMonitorLib/Hardware/Ring0.cs | 977 ++- LibreHardwareMonitorLib/Hardware/RyzenSMU.cs | 1365 ++-- LibreHardwareMonitorLib/Hardware/SMBios.cs | 2839 ++++---- LibreHardwareMonitorLib/Hardware/Sensor.cs | 491 +- .../Hardware/SensorVisitor.cs | 113 +- .../Hardware/Storage/ATAStorage.cs | 485 +- .../Hardware/Storage/AbstractStorage.cs | 519 +- .../Hardware/Storage/GenericHardDisk.cs | 157 +- .../Hardware/Storage/INVMeDrive.cs | 15 +- .../Hardware/Storage/ISmart.cs | 21 +- .../Hardware/Storage/NVMeGeneric.cs | 309 +- .../Hardware/Storage/NVMeHealthInfo.cs | 45 +- .../Hardware/Storage/NVMeInfo.cs | 31 +- .../Hardware/Storage/NVMeIntel.cs | 275 +- .../Hardware/Storage/NVMeIntelRst.cs | 275 +- .../Hardware/Storage/NVMeSamsung.cs | 397 +- .../Hardware/Storage/NVMeSmart.cs | 311 +- .../Hardware/Storage/NVMeWindows.cs | 231 +- .../Hardware/Storage/NamePrefixAttribute.cs | 21 +- .../Hardware/Storage/RequireSmartAttribute.cs | 21 +- .../Hardware/Storage/SmartAttribute.cs | 181 +- .../Hardware/Storage/SmartNames.cs | 265 +- .../Hardware/Storage/SsdIndilinx.cs | 67 +- .../Hardware/Storage/SsdIntel.cs | 79 +- .../Hardware/Storage/SsdMicron.cs | 185 +- .../Hardware/Storage/SsdPlextor.cs | 33 +- .../Hardware/Storage/SsdSamsung.cs | 89 +- .../Hardware/Storage/SsdSandforce.cs | 111 +- .../Hardware/Storage/StorageGeneric.cs | 37 +- .../Hardware/Storage/StorageGroup.cs | 67 +- .../Hardware/Storage/StorageInfo.cs | 33 +- .../Hardware/Storage/WindowsSmart.cs | 295 +- .../Hardware/Storage/WindowsStorage.cs | 135 +- .../Hardware/ThreadAffinity.cs | 195 +- LibreHardwareMonitorLib/Interop/AdvApi32.cs | 275 +- LibreHardwareMonitorLib/Interop/AtiAdlxx.cs | 1041 ++- LibreHardwareMonitorLib/Interop/CfgMgr32.cs | 29 +- LibreHardwareMonitorLib/Interop/D3dkmdt.cs | 69 +- LibreHardwareMonitorLib/Interop/D3dkmth.cs | 969 ++- LibreHardwareMonitorLib/Interop/Ftd2xx.cs | 339 +- LibreHardwareMonitorLib/Interop/Gdi32.cs | 35 +- LibreHardwareMonitorLib/Interop/InpOut.cs | 23 +- LibreHardwareMonitorLib/Interop/Kernel32.cs | 3071 ++++---- LibreHardwareMonitorLib/Interop/LibC.cs | 19 +- LibreHardwareMonitorLib/Interop/NtDll.cs | 137 +- LibreHardwareMonitorLib/Interop/NvApi.cs | 1195 ++- LibreHardwareMonitorLib/Interop/NvidiaML.cs | 769 +- LibreHardwareMonitorLib/Interop/Ring0.cs | 35 +- LibreHardwareMonitorLib/Interop/SetupApi.cs | 93 +- LibreHardwareMonitorLib/Interop/WinNt.cs | 61 +- .../Software/OperatingSystem.cs | 49 +- 175 files changed, 34026 insertions(+), 34204 deletions(-) diff --git a/.editorconfig b/.editorconfig index 9422b2d..e326842 100644 --- a/.editorconfig +++ b/.editorconfig @@ -38,7 +38,6 @@ csharp_indent_labels = one_less_than_current # Modifier preferences csharp_preferred_modifier_order = public,private,protected,internal,static,extern,new,virtual,abstract,sealed,override,readonly,unsafe,volatile,async:suggestion - # avoid this. unless absolutely necessary dotnet_style_qualification_for_field = false:suggestion dotnet_style_qualification_for_property = false:suggestion diff --git a/LibreHardwareMonitor/Program.cs b/LibreHardwareMonitor/Program.cs index 25ce6f2..d4a3bda 100644 --- a/LibreHardwareMonitor/Program.cs +++ b/LibreHardwareMonitor/Program.cs @@ -9,56 +9,55 @@ using System.IO; using System.Windows.Forms; using LibreHardwareMonitor.UI; -namespace LibreHardwareMonitor +namespace LibreHardwareMonitor; + +public static class Program { - public static class Program + [STAThread] + public static void Main() { - [STAThread] - public static void Main() - { - if (!AllRequiredFilesAvailable()) - Environment.Exit(0); + if (!AllRequiredFilesAvailable()) + Environment.Exit(0); - Application.EnableVisualStyles(); - Application.SetCompatibleTextRenderingDefault(false); - using (MainForm form = new MainForm()) + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + using (MainForm form = new MainForm()) + { + form.FormClosed += delegate { - form.FormClosed += delegate - { - Application.Exit(); - }; - Application.Run(); - } - } - - private static bool IsFileAvailable(string fileName) - { - string path = Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar; - if (!File.Exists(path + fileName)) - { - MessageBox.Show("The following file could not be found: " + fileName + - "\nPlease extract all files from the archive.", "Error", - MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } - return true; - } - - private static bool AllRequiredFilesAvailable() - { - if (!IsFileAvailable("Aga.Controls.dll")) - return false; - - if (!IsFileAvailable("LibreHardwareMonitorLib.dll")) - return false; - - if (!IsFileAvailable("OxyPlot.dll")) - return false; - - if (!IsFileAvailable("OxyPlot.WindowsForms.dll")) - return false; - - return true; + Application.Exit(); + }; + Application.Run(); } } + + private static bool IsFileAvailable(string fileName) + { + string path = Path.GetDirectoryName(Application.ExecutablePath) + Path.DirectorySeparatorChar; + if (!File.Exists(path + fileName)) + { + MessageBox.Show("The following file could not be found: " + fileName + + "\nPlease extract all files from the archive.", "Error", + MessageBoxButtons.OK, MessageBoxIcon.Error); + return false; + } + return true; + } + + private static bool AllRequiredFilesAvailable() + { + if (!IsFileAvailable("Aga.Controls.dll")) + return false; + + if (!IsFileAvailable("LibreHardwareMonitorLib.dll")) + return false; + + if (!IsFileAvailable("OxyPlot.dll")) + return false; + + if (!IsFileAvailable("OxyPlot.WindowsForms.dll")) + return false; + + return true; + } } diff --git a/LibreHardwareMonitor/UI/AboutBox.cs b/LibreHardwareMonitor/UI/AboutBox.cs index d664227..41cf6f0 100644 --- a/LibreHardwareMonitor/UI/AboutBox.cs +++ b/LibreHardwareMonitor/UI/AboutBox.cs @@ -8,28 +8,27 @@ using System.Diagnostics; using System.Drawing; using System.Windows.Forms; -namespace LibreHardwareMonitor.UI -{ - public sealed partial class AboutBox : Form - { - public AboutBox() - { - InitializeComponent(); - Font = SystemFonts.MessageBoxFont; - label3.Text = "Version " + Application.ProductVersion; - projectLinkLabel.Links.Remove(projectLinkLabel.Links[0]); - projectLinkLabel.Links.Add(0, projectLinkLabel.Text.Length, "https://github.com/LibreHardwareMonitor/LibreHardwareMonitor"); - licenseLinkLabel.Links.Remove(licenseLinkLabel.Links[0]); - licenseLinkLabel.Links.Add(0, licenseLinkLabel.Text.Length, "https://www.mozilla.org/en-US/MPL/2.0/"); - } +namespace LibreHardwareMonitor.UI; - private void LinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - try - { - Process.Start(new ProcessStartInfo(e.Link.LinkData.ToString())); - } - catch { } - } +public sealed partial class AboutBox : Form +{ + public AboutBox() + { + InitializeComponent(); + Font = SystemFonts.MessageBoxFont; + label3.Text = "Version " + Application.ProductVersion; + projectLinkLabel.Links.Remove(projectLinkLabel.Links[0]); + projectLinkLabel.Links.Add(0, projectLinkLabel.Text.Length, "https://github.com/LibreHardwareMonitor/LibreHardwareMonitor"); + licenseLinkLabel.Links.Remove(licenseLinkLabel.Links[0]); + licenseLinkLabel.Links.Add(0, licenseLinkLabel.Text.Length, "https://www.mozilla.org/en-US/MPL/2.0/"); } -} + + private void LinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + try + { + Process.Start(new ProcessStartInfo(e.Link.LinkData.ToString())); + } + catch { } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/AuthForm.cs b/LibreHardwareMonitor/UI/AuthForm.cs index ffc9b12..b590495 100644 --- a/LibreHardwareMonitor/UI/AuthForm.cs +++ b/LibreHardwareMonitor/UI/AuthForm.cs @@ -7,41 +7,40 @@ using System; using System.Windows.Forms; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public partial class AuthForm : Form { - public partial class AuthForm : Form + private readonly MainForm _parent; + + public AuthForm(MainForm m) { - private readonly MainForm _parent; - - public AuthForm(MainForm m) - { - InitializeComponent(); - _parent = m; - } - - private void AuthForm_Load(object sender, EventArgs e) - { - httpAuthUsernameTextBox.Enabled = httpAuthPasswordTextBox.Enabled = enableHTTPAuthCheckBox.Checked = _parent.Server.AuthEnabled; - httpAuthUsernameTextBox.Text = _parent.Server.UserName; - } - - private void HttpAuthCancelButton_Click(object sender, EventArgs e) - { - Close(); - } - - private void HttpAuthOkButton_Click(object sender, EventArgs e) - { - _parent.Server.UserName = httpAuthUsernameTextBox.Text; - _parent.Server.Password = httpAuthPasswordTextBox.Text; - _parent.Server.AuthEnabled = enableHTTPAuthCheckBox.Checked; - _parent.AuthWebServerMenuItemChecked = _parent.Server.AuthEnabled; - Close(); - } - - private void EnableHTTPAuthCheckBox_CheckedChanged(object sender, EventArgs e) - { - httpAuthUsernameTextBox.Enabled = httpAuthPasswordTextBox.Enabled = enableHTTPAuthCheckBox.Checked; - } + InitializeComponent(); + _parent = m; } -} + + private void AuthForm_Load(object sender, EventArgs e) + { + httpAuthUsernameTextBox.Enabled = httpAuthPasswordTextBox.Enabled = enableHTTPAuthCheckBox.Checked = _parent.Server.AuthEnabled; + httpAuthUsernameTextBox.Text = _parent.Server.UserName; + } + + private void HttpAuthCancelButton_Click(object sender, EventArgs e) + { + Close(); + } + + private void HttpAuthOkButton_Click(object sender, EventArgs e) + { + _parent.Server.UserName = httpAuthUsernameTextBox.Text; + _parent.Server.Password = httpAuthPasswordTextBox.Text; + _parent.Server.AuthEnabled = enableHTTPAuthCheckBox.Checked; + _parent.AuthWebServerMenuItemChecked = _parent.Server.AuthEnabled; + Close(); + } + + private void EnableHTTPAuthCheckBox_CheckedChanged(object sender, EventArgs e) + { + httpAuthUsernameTextBox.Enabled = httpAuthPasswordTextBox.Enabled = enableHTTPAuthCheckBox.Checked; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/Gadget.cs b/LibreHardwareMonitor/UI/Gadget.cs index a69c5cc..f701690 100644 --- a/LibreHardwareMonitor/UI/Gadget.cs +++ b/LibreHardwareMonitor/UI/Gadget.cs @@ -8,172 +8,171 @@ using System; using System.Drawing; using System.Windows.Forms; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public abstract class Gadget : IDisposable { - public abstract class Gadget : IDisposable + private readonly GadgetWindow _window; + + public event EventHandler VisibleChanged; + + protected Gadget() { - private readonly GadgetWindow _window; - - public event EventHandler VisibleChanged; - - protected Gadget() + _window = new GadgetWindow(); + _window.Paint += delegate (object sender, PaintEventArgs e) { - _window = new GadgetWindow(); - _window.Paint += delegate (object sender, PaintEventArgs e) - { - OnPaint(e); - }; - } - - public virtual void Dispose() - { - _window.Dispose(); - } - - public Point Location - { - get - { - return _window.Location; - } - set - { - _window.Location = value; - } - } - - public event EventHandler LocationChanged - { - add - { - _window.LocationChanged += value; - } - remove - { - _window.LocationChanged -= value; - } - } - - public virtual Size Size - { - get - { - return _window.Size; - } - set - { - _window.Size = value; - } - } - - public event EventHandler SizeChanged - { - add - { - _window.SizeChanged += value; - } - remove - { - _window.SizeChanged -= value; - } - } - - public byte Opacity - { - get - { - return _window.Opacity; - } - set - { - _window.Opacity = value; - } - } - - public bool LockPositionAndSize - { - get - { - return _window.LockPositionAndSize; - } - set - { - _window.LockPositionAndSize = value; - } - } - - public bool AlwaysOnTop - { - get - { - return _window.AlwaysOnTop; - } - set - { - _window.AlwaysOnTop = value; - } - } - - public ContextMenuStrip ContextMenuStrip - { - get - { - return _window.ContextMenuStrip; - } - set - { - _window.ContextMenuStrip = value; - } - } - - public event HitTestEventHandler HitTest - { - add - { - _window.HitTest += value; - } - remove - { - _window.HitTest -= value; - } - } - - public event MouseEventHandler MouseDoubleClick - { - add - { - _window.MouseDoubleClick += value; - } - remove - { - _window.MouseDoubleClick -= value; - } - } - - public bool Visible - { - get - { - return _window.Visible; - } - set - { - if (value != _window.Visible) - { - _window.Visible = value; - VisibleChanged?.Invoke(this, EventArgs.Empty); - - if (value) - Redraw(); - } - } - } - - public void Redraw() - { - _window.Redraw(); - } - - protected abstract void OnPaint(PaintEventArgs e); + OnPaint(e); + }; } -} + + public virtual void Dispose() + { + _window.Dispose(); + } + + public Point Location + { + get + { + return _window.Location; + } + set + { + _window.Location = value; + } + } + + public event EventHandler LocationChanged + { + add + { + _window.LocationChanged += value; + } + remove + { + _window.LocationChanged -= value; + } + } + + public virtual Size Size + { + get + { + return _window.Size; + } + set + { + _window.Size = value; + } + } + + public event EventHandler SizeChanged + { + add + { + _window.SizeChanged += value; + } + remove + { + _window.SizeChanged -= value; + } + } + + public byte Opacity + { + get + { + return _window.Opacity; + } + set + { + _window.Opacity = value; + } + } + + public bool LockPositionAndSize + { + get + { + return _window.LockPositionAndSize; + } + set + { + _window.LockPositionAndSize = value; + } + } + + public bool AlwaysOnTop + { + get + { + return _window.AlwaysOnTop; + } + set + { + _window.AlwaysOnTop = value; + } + } + + public ContextMenuStrip ContextMenuStrip + { + get + { + return _window.ContextMenuStrip; + } + set + { + _window.ContextMenuStrip = value; + } + } + + public event HitTestEventHandler HitTest + { + add + { + _window.HitTest += value; + } + remove + { + _window.HitTest -= value; + } + } + + public event MouseEventHandler MouseDoubleClick + { + add + { + _window.MouseDoubleClick += value; + } + remove + { + _window.MouseDoubleClick -= value; + } + } + + public bool Visible + { + get + { + return _window.Visible; + } + set + { + if (value != _window.Visible) + { + _window.Visible = value; + VisibleChanged?.Invoke(this, EventArgs.Empty); + + if (value) + Redraw(); + } + } + } + + public void Redraw() + { + _window.Redraw(); + } + + protected abstract void OnPaint(PaintEventArgs e); +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/GadgetWindow.cs b/LibreHardwareMonitor/UI/GadgetWindow.cs index 19e3c00..45a302b 100644 --- a/LibreHardwareMonitor/UI/GadgetWindow.cs +++ b/LibreHardwareMonitor/UI/GadgetWindow.cs @@ -12,564 +12,563 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Windows.Forms; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public sealed class GadgetWindow : NativeWindow, IDisposable { - public sealed class GadgetWindow : NativeWindow, IDisposable + private bool _visible; + private bool _alwaysOnTop; + private byte _opacity = 255; + private Point _location = new Point(100, 100); + private Size _size = new Size(130, 84); + private readonly MethodInfo _commandDispatch; + private IntPtr _handleBitmapDC; + private Size _bufferSize; + private Graphics _graphics; + + public event EventHandler SizeChanged; + public event EventHandler LocationChanged; + public event HitTestEventHandler HitTest; + public event MouseEventHandler MouseDoubleClick; + + public GadgetWindow() { - private bool _visible; - private bool _alwaysOnTop; - private byte _opacity = 255; - private Point _location = new Point(100, 100); - private Size _size = new Size(130, 84); - private readonly MethodInfo _commandDispatch; - private IntPtr _handleBitmapDC; - private Size _bufferSize; - private Graphics _graphics; + Type commandType = typeof(Form).Assembly.GetType("System.Windows.Forms.Command"); + _commandDispatch = commandType.GetMethod("DispatchID", + BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, + null, new[] { typeof(int) }, null); - public event EventHandler SizeChanged; - public event EventHandler LocationChanged; - public event HitTestEventHandler HitTest; - public event MouseEventHandler MouseDoubleClick; + CreateHandle(CreateParams); - public GadgetWindow() + // move window to the bottom + MoveToBottom(Handle); + + // prevent window from fading to a glass sheet when peek is invoked + try { - Type commandType = typeof(Form).Assembly.GetType("System.Windows.Forms.Command"); - _commandDispatch = commandType.GetMethod("DispatchID", - BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, - null, new[] { typeof(int) }, null); + bool value = true; + NativeMethods.DwmSetWindowAttribute(Handle, WindowAttribute.DWMWA_EXCLUDED_FROM_PEEK, ref value, Marshal.SizeOf(true)); + } + catch (DllNotFoundException) { } + catch (EntryPointNotFoundException) { } - CreateHandle(CreateParams); + CreateBuffer(); + } - // move window to the bottom + private void ShowDesktopChanged(bool showDesktop) + { + if (showDesktop) + MoveToTopMost(Handle); + else MoveToBottom(Handle); + } - // prevent window from fading to a glass sheet when peek is invoked - try + private void MoveToBottom(IntPtr handle) + { + NativeMethods.SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); + } + + private void MoveToTopMost(IntPtr handle) + { + NativeMethods.SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); + } + + private CreateParams CreateParams + { + get + { + CreateParams cp = new CreateParams { - bool value = true; - NativeMethods.DwmSetWindowAttribute(Handle, WindowAttribute.DWMWA_EXCLUDED_FROM_PEEK, ref value, Marshal.SizeOf(true)); - } - catch (DllNotFoundException) { } - catch (EntryPointNotFoundException) { } + Width = 4096, + Height = 4096, + X = _location.X, + Y = _location.Y, + ExStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW + }; + return cp; + } + } + + protected override void WndProc(ref Message message) + { + switch (message.Msg) + { + case WM_COMMAND: + { + // need to dispatch the message for the context menu + if (message.LParam == IntPtr.Zero) + _commandDispatch.Invoke(null, new object[] {message.WParam.ToInt32() & 0xFFFF }); + } + break; + case WM_NCHITTEST: + { + message.Result = (IntPtr)HitResult.Caption; + if (HitTest != null) + { + Point p = new Point( + Macros.GET_X_LPARAM(message.LParam) - _location.X, + Macros.GET_Y_LPARAM(message.LParam) - _location.Y + ); + HitTestEventArgs e = new HitTestEventArgs(p, HitResult.Caption); + HitTest(this, e); + message.Result = (IntPtr)e.HitResult; + } + } + break; + case WM_NCLBUTTONDBLCLK: + { + MouseDoubleClick?.Invoke(this, new MouseEventArgs(MouseButtons.Left, 2, Macros.GET_X_LPARAM(message.LParam) - _location.X, Macros.GET_Y_LPARAM(message.LParam) - _location.Y, 0)); + message.Result = IntPtr.Zero; + } + break; + case WM_NCRBUTTONDOWN: + { + message.Result = IntPtr.Zero; + } + break; + case WM_NCRBUTTONUP: + { + ContextMenuStrip?.Show(new Point(Macros.GET_X_LPARAM(message.LParam), Macros.GET_Y_LPARAM(message.LParam))); + message.Result = IntPtr.Zero; + } + break; + case WM_WINDOWPOSCHANGING: + { + WINDOWPOS wp = (WINDOWPOS)Marshal.PtrToStructure(message.LParam, typeof(WINDOWPOS)); + if (!LockPositionAndSize) + { + // prevent the window from leaving the screen + if ((wp.flags & SWP_NOMOVE) == 0) + { + Rectangle rect = Screen.GetWorkingArea(new Rectangle(wp.x, wp.y, wp.cx, wp.cy)); + const int margin = 16; + wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin); + wp.x = Math.Min(wp.x, rect.Right - margin); + wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin); + wp.y = Math.Min(wp.y, rect.Bottom - margin); + } + + // update location and fire event + if ((wp.flags & SWP_NOMOVE) == 0) + { + if (_location.X != wp.x || _location.Y != wp.y) + { + _location = new Point(wp.x, wp.y); + LocationChanged?.Invoke(this, EventArgs.Empty); + } + } + + // update size and fire event + if ((wp.flags & SWP_NOSIZE) == 0) + { + if (_size.Width != wp.cx || _size.Height != wp.cy) + { + _size = new Size(wp.cx, wp.cy); + SizeChanged?.Invoke(this, EventArgs.Empty); + } + } + + // update the size of the layered window + if ((wp.flags & SWP_NOSIZE) == 0) + NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, ref _size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); + + // update the position of the layered window + if ((wp.flags & SWP_NOMOVE) == 0) + NativeMethods.SetWindowPos(Handle, IntPtr.Zero, _location.X, _location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING); + } + + // do not forward any move or size messages + wp.flags |= SWP_NOSIZE | SWP_NOMOVE; + + // suppress any frame changed events + wp.flags &= ~SWP_FRAMECHANGED; + + Marshal.StructureToPtr(wp, message.LParam, false); + message.Result = IntPtr.Zero; + } + break; + default: + { + base.WndProc(ref message); + } + break; + } + } + + private BlendFunction CreateBlendFunction() + { + return new BlendFunction { BlendOp = AC_SRC_OVER, BlendFlags = 0, SourceConstantAlpha = _opacity, AlphaFormat = AC_SRC_ALPHA }; + } + + private void CreateBuffer() + { + IntPtr handleScreenDC = NativeMethods.GetDC(IntPtr.Zero); + _handleBitmapDC = NativeMethods.CreateCompatibleDC(handleScreenDC); + NativeMethods.ReleaseDC(IntPtr.Zero, handleScreenDC); + _bufferSize = _size; + + BITMAPINFO info = new BITMAPINFO(); + info.Size = Marshal.SizeOf(info); + info.Width = _size.Width; + info.Height = -_size.Height; + info.BitCount = 32; + info.Planes = 1; + + IntPtr hBmp = NativeMethods.CreateDIBSection(_handleBitmapDC, ref info, 0, out IntPtr _, IntPtr.Zero, 0); + IntPtr hBmpOld = NativeMethods.SelectObject(_handleBitmapDC, hBmp); + NativeMethods.DeleteObject(hBmpOld); + + _graphics = Graphics.FromHdc(_handleBitmapDC); + + if (Environment.OSVersion.Version.Major > 5) + { + _graphics.TextRenderingHint = TextRenderingHint.SystemDefault; + _graphics.SmoothingMode = SmoothingMode.HighQuality; + } + } + + private void DisposeBuffer() + { + _graphics.Dispose(); + NativeMethods.DeleteDC(_handleBitmapDC); + } + + public void Dispose() + { + DisposeBuffer(); + } + + public PaintEventHandler Paint; + + public void Redraw() + { + if (!_visible || Paint == null) + return; + + if (_size != _bufferSize) + { + DisposeBuffer(); CreateBuffer(); } - private void ShowDesktopChanged(bool showDesktop) - { - if (showDesktop) - MoveToTopMost(Handle); - else - MoveToBottom(Handle); - } + Paint(this, new PaintEventArgs(_graphics, new Rectangle(Point.Empty, _size))); + Point pointSource = Point.Empty; + BlendFunction blend = CreateBlendFunction(); + NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, ref _size, _handleBitmapDC, ref pointSource, 0, ref blend, ULW_ALPHA); + // make sure the window is at the right location + NativeMethods.SetWindowPos(Handle, IntPtr.Zero, _location.X, _location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING); + } - private void MoveToBottom(IntPtr handle) + public byte Opacity + { + get { - NativeMethods.SetWindowPos(handle, HWND_BOTTOM, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); + return _opacity; } - - private void MoveToTopMost(IntPtr handle) + set { - NativeMethods.SetWindowPos(handle, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING); - } - - private CreateParams CreateParams - { - get + if (_opacity != value) { - CreateParams cp = new CreateParams - { - Width = 4096, - Height = 4096, - X = _location.X, - Y = _location.Y, - ExStyle = WS_EX_LAYERED | WS_EX_TOOLWINDOW - }; - - return cp; + _opacity = value; + BlendFunction blend = CreateBlendFunction(); + NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, ref blend, ULW_ALPHA); } } - - protected override void WndProc(ref Message message) - { - switch (message.Msg) - { - case WM_COMMAND: - { - // need to dispatch the message for the context menu - if (message.LParam == IntPtr.Zero) - _commandDispatch.Invoke(null, new object[] {message.WParam.ToInt32() & 0xFFFF }); - } - break; - case WM_NCHITTEST: - { - message.Result = (IntPtr)HitResult.Caption; - if (HitTest != null) - { - Point p = new Point( - Macros.GET_X_LPARAM(message.LParam) - _location.X, - Macros.GET_Y_LPARAM(message.LParam) - _location.Y - ); - HitTestEventArgs e = new HitTestEventArgs(p, HitResult.Caption); - HitTest(this, e); - message.Result = (IntPtr)e.HitResult; - } - } - break; - case WM_NCLBUTTONDBLCLK: - { - MouseDoubleClick?.Invoke(this, new MouseEventArgs(MouseButtons.Left, 2, Macros.GET_X_LPARAM(message.LParam) - _location.X, Macros.GET_Y_LPARAM(message.LParam) - _location.Y, 0)); - message.Result = IntPtr.Zero; - } - break; - case WM_NCRBUTTONDOWN: - { - message.Result = IntPtr.Zero; - } - break; - case WM_NCRBUTTONUP: - { - ContextMenuStrip?.Show(new Point(Macros.GET_X_LPARAM(message.LParam), Macros.GET_Y_LPARAM(message.LParam))); - message.Result = IntPtr.Zero; - } - break; - case WM_WINDOWPOSCHANGING: - { - WINDOWPOS wp = (WINDOWPOS)Marshal.PtrToStructure(message.LParam, typeof(WINDOWPOS)); - if (!LockPositionAndSize) - { - // prevent the window from leaving the screen - if ((wp.flags & SWP_NOMOVE) == 0) - { - Rectangle rect = Screen.GetWorkingArea(new Rectangle(wp.x, wp.y, wp.cx, wp.cy)); - const int margin = 16; - wp.x = Math.Max(wp.x, rect.Left - wp.cx + margin); - wp.x = Math.Min(wp.x, rect.Right - margin); - wp.y = Math.Max(wp.y, rect.Top - wp.cy + margin); - wp.y = Math.Min(wp.y, rect.Bottom - margin); - } - - // update location and fire event - if ((wp.flags & SWP_NOMOVE) == 0) - { - if (_location.X != wp.x || _location.Y != wp.y) - { - _location = new Point(wp.x, wp.y); - LocationChanged?.Invoke(this, EventArgs.Empty); - } - } - - // update size and fire event - if ((wp.flags & SWP_NOSIZE) == 0) - { - if (_size.Width != wp.cx || _size.Height != wp.cy) - { - _size = new Size(wp.cx, wp.cy); - SizeChanged?.Invoke(this, EventArgs.Empty); - } - } - - // update the size of the layered window - if ((wp.flags & SWP_NOSIZE) == 0) - NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, ref _size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); - - // update the position of the layered window - if ((wp.flags & SWP_NOMOVE) == 0) - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, _location.X, _location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING); - } - - // do not forward any move or size messages - wp.flags |= SWP_NOSIZE | SWP_NOMOVE; - - // suppress any frame changed events - wp.flags &= ~SWP_FRAMECHANGED; - - Marshal.StructureToPtr(wp, message.LParam, false); - message.Result = IntPtr.Zero; - } - break; - default: - { - base.WndProc(ref message); - } - break; - } - } - - private BlendFunction CreateBlendFunction() - { - return new BlendFunction { BlendOp = AC_SRC_OVER, BlendFlags = 0, SourceConstantAlpha = _opacity, AlphaFormat = AC_SRC_ALPHA }; - } - - private void CreateBuffer() - { - IntPtr handleScreenDC = NativeMethods.GetDC(IntPtr.Zero); - _handleBitmapDC = NativeMethods.CreateCompatibleDC(handleScreenDC); - NativeMethods.ReleaseDC(IntPtr.Zero, handleScreenDC); - _bufferSize = _size; - - BITMAPINFO info = new BITMAPINFO(); - info.Size = Marshal.SizeOf(info); - info.Width = _size.Width; - info.Height = -_size.Height; - info.BitCount = 32; - info.Planes = 1; - - IntPtr hBmp = NativeMethods.CreateDIBSection(_handleBitmapDC, ref info, 0, out IntPtr _, IntPtr.Zero, 0); - IntPtr hBmpOld = NativeMethods.SelectObject(_handleBitmapDC, hBmp); - NativeMethods.DeleteObject(hBmpOld); - - _graphics = Graphics.FromHdc(_handleBitmapDC); - - if (Environment.OSVersion.Version.Major > 5) - { - _graphics.TextRenderingHint = TextRenderingHint.SystemDefault; - _graphics.SmoothingMode = SmoothingMode.HighQuality; - } - } - - private void DisposeBuffer() - { - _graphics.Dispose(); - NativeMethods.DeleteDC(_handleBitmapDC); - } - - public void Dispose() - { - DisposeBuffer(); - } - - public PaintEventHandler Paint; - - public void Redraw() - { - if (!_visible || Paint == null) - return; - - if (_size != _bufferSize) - { - DisposeBuffer(); - CreateBuffer(); - } - - Paint(this, new PaintEventArgs(_graphics, new Rectangle(Point.Empty, _size))); - Point pointSource = Point.Empty; - BlendFunction blend = CreateBlendFunction(); - NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, ref _size, _handleBitmapDC, ref pointSource, 0, ref blend, ULW_ALPHA); - // make sure the window is at the right location - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, _location.X, _location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING); - } - - public byte Opacity - { - get - { - return _opacity; - } - set - { - if (_opacity != value) - { - _opacity = value; - BlendFunction blend = CreateBlendFunction(); - NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, 0, ref blend, ULW_ALPHA); - } - } - } - - public bool Visible - { - get - { - return _visible; - } - set - { - if (_visible != value) - { - _visible = value; - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | (value ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); - - if (value) - { - if (!_alwaysOnTop) - ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged; - } - else - { - if (!_alwaysOnTop) - ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged; - } - } - } - } - - // if locked, the window can not be moved or resized - public bool LockPositionAndSize { get; set; } - - public bool AlwaysOnTop - { - get - { - return _alwaysOnTop; - } - set - { - if (value != _alwaysOnTop) - { - _alwaysOnTop = value; - - if (_alwaysOnTop) - { - if (_visible) - ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged; - - MoveToTopMost(Handle); - } - else - { - MoveToBottom(Handle); - - if (_visible) - ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged; - } - } - } - } - - public Size Size - { - get - { - return _size; - } - set - { - if (_size != value) - { - _size = value; - NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, ref _size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); - SizeChanged?.Invoke(this, EventArgs.Empty); - } - } - } - - public Point Location - { - get - { - return _location; - } - set - { - if (_location != value) - { - _location = value; - NativeMethods.SetWindowPos(Handle, IntPtr.Zero, _location.X, _location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING); - LocationChanged?.Invoke(this, EventArgs.Empty); - } - } - } - - public ContextMenuStrip ContextMenuStrip { get; set; } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - private struct BlendFunction - { - public byte BlendOp; - public byte BlendFlags; - public byte SourceConstantAlpha; - public byte AlphaFormat; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - private struct WINDOWPOS - { - public readonly IntPtr hwnd; - public readonly IntPtr hwndInsertAfter; - public int x; - public int y; - public readonly int cx; - public readonly int cy; - public uint flags; - } - - [StructLayout(LayoutKind.Sequential)] - public struct BITMAPINFO - { - public int Size; - public int Width; - public int Height; - public short Planes; - public short BitCount; - public int Compression; - public int SizeImage; - public int XPelsPerMeter; - public int YPelsPerMeter; - public int ClrUsed; - public int ClrImportant; - public int Colors; - } - - public static readonly IntPtr HWND_BOTTOM = (IntPtr)1; - public static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1); - - public const int WS_EX_LAYERED = 0x00080000; - public const int WS_EX_TOOLWINDOW = 0x00000080; - - public const uint SWP_NOSIZE = 0x0001; - public const uint SWP_NOMOVE = 0x0002; - public const uint SWP_NOACTIVATE = 0x0010; - public const uint SWP_FRAMECHANGED = 0x0020; - public const uint SWP_HIDEWINDOW = 0x0080; - public const uint SWP_SHOWWINDOW = 0x0040; - public const uint SWP_NOZORDER = 0x0004; - public const uint SWP_NOSENDCHANGING = 0x0400; - - public const int ULW_COLORKEY = 0x00000001; - public const int ULW_ALPHA = 0x00000002; - public const int ULW_OPAQUE = 0x00000004; - - public const byte AC_SRC_OVER = 0x00; - public const byte AC_SRC_ALPHA = 0x01; - - public const int WM_NCHITTEST = 0x0084; - public const int WM_NCLBUTTONDBLCLK = 0x00A3; - public const int WM_NCLBUTTONDOWN = 0x00A1; - public const int WM_NCLBUTTONUP = 0x00A2; - public const int WM_NCRBUTTONDOWN = 0x00A4; - public const int WM_NCRBUTTONUP = 0x00A5; - public const int WM_WINDOWPOSCHANGING = 0x0046; - public const int WM_COMMAND = 0x0111; - - public const int TPM_RIGHTBUTTON = 0x0002; - public const int TPM_VERTICAL = 0x0040; - - private enum WindowAttribute : int - { - DWMWA_NCRENDERING_ENABLED = 1, - DWMWA_NCRENDERING_POLICY, - DWMWA_TRANSITIONS_FORCEDISABLED, - DWMWA_ALLOW_NCPAINT, - DWMWA_CAPTION_BUTTON_BOUNDS, - DWMWA_NONCLIENT_RTL_LAYOUT, - DWMWA_FORCE_ICONIC_REPRESENTATION, - DWMWA_FLIP3D_POLICY, - DWMWA_EXTENDED_FRAME_BOUNDS, - DWMWA_HAS_ICONIC_BITMAP, - DWMWA_DISALLOW_PEEK, - DWMWA_EXCLUDED_FROM_PEEK, - DWMWA_LAST - } - - /// - /// Some macros imported and converted from the Windows SDK - /// - private static class Macros - { - public static ushort LOWORD(IntPtr l) - { - return (ushort)((ulong)l & 0xFFFF); - } - - public static ushort HIWORD(IntPtr l) - { - return (ushort)(((ulong)l >> 16) & 0xFFFF); - } - - public static int GET_X_LPARAM(IntPtr lp) - { - return (short)LOWORD(lp); - } - - public static int GET_Y_LPARAM(IntPtr lp) - { - return (short)HIWORD(lp); - } - } - - /// - /// Imported native methods - /// - private static class NativeMethods - { - private const string USER = "user32.dll"; - private const string GDI = "gdi32.dll"; - private const string DWMAPI = "dwmapi.dll"; - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, IntPtr pptDst, ref Size psize, IntPtr hdcSrc, IntPtr pprSrc, int crKey, IntPtr pblend, int dwFlags); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, IntPtr pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, int crKey, ref BlendFunction pblend, int dwFlags); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, IntPtr pptDst, IntPtr psize, IntPtr hdcSrc, IntPtr pprSrc, int crKey, ref BlendFunction pblend, int dwFlags); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr GetDC(IntPtr hWnd); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern bool TrackPopupMenuEx(IntPtr hMenu, uint uFlags, int x, int y, IntPtr hWnd, IntPtr tpmParams); - - [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr CreateCompatibleDC(IntPtr hDC); - - [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr CreateDIBSection(IntPtr hdc, [In] ref BITMAPINFO pbmi, uint pila, out IntPtr ppvBits, IntPtr hSection, uint dwOffset); - - [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeleteDC(IntPtr hdc); - - [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); - - [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool DeleteObject(IntPtr hObject); - - [DllImport(DWMAPI, CallingConvention = CallingConvention.Winapi)] - public static extern int DwmSetWindowAttribute(IntPtr hwnd, WindowAttribute dwAttribute, ref bool pvAttribute, int cbAttribute); - } } - public delegate void HitTestEventHandler(object sender, HitTestEventArgs e); - - public enum HitResult + public bool Visible { - Transparent = -1, - Nowhere = 0, - Client = 1, - Caption = 2, - Left = 10, - Right = 11, - Top = 12, - TopLeft = 13, - TopRight = 14, - Bottom = 15, - BottomLeft = 16, - BottomRight = 17, - Border = 18 + get + { + return _visible; + } + set + { + if (_visible != value) + { + _visible = value; + NativeMethods.SetWindowPos(Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | (value ? SWP_SHOWWINDOW : SWP_HIDEWINDOW)); + + if (value) + { + if (!_alwaysOnTop) + ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged; + } + else + { + if (!_alwaysOnTop) + ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged; + } + } + } } - public class HitTestEventArgs : EventArgs + // if locked, the window can not be moved or resized + public bool LockPositionAndSize { get; set; } + + public bool AlwaysOnTop { - public HitTestEventArgs(Point location, HitResult hitResult) + get { - Location = location; - HitResult = hitResult; + return _alwaysOnTop; } - public Point Location { get; } - public HitResult HitResult { get; set; } + set + { + if (value != _alwaysOnTop) + { + _alwaysOnTop = value; + + if (_alwaysOnTop) + { + if (_visible) + ShowDesktop.Instance.ShowDesktopChanged -= ShowDesktopChanged; + + MoveToTopMost(Handle); + } + else + { + MoveToBottom(Handle); + + if (_visible) + ShowDesktop.Instance.ShowDesktopChanged += ShowDesktopChanged; + } + } + } + } + + public Size Size + { + get + { + return _size; + } + set + { + if (_size != value) + { + _size = value; + NativeMethods.UpdateLayeredWindow(Handle, IntPtr.Zero, IntPtr.Zero, ref _size, IntPtr.Zero, IntPtr.Zero, 0, IntPtr.Zero, 0); + SizeChanged?.Invoke(this, EventArgs.Empty); + } + } + } + + public Point Location + { + get + { + return _location; + } + set + { + if (_location != value) + { + _location = value; + NativeMethods.SetWindowPos(Handle, IntPtr.Zero, _location.X, _location.Y, 0, 0, SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOSENDCHANGING); + LocationChanged?.Invoke(this, EventArgs.Empty); + } + } + } + + public ContextMenuStrip ContextMenuStrip { get; set; } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct BlendFunction + { + public byte BlendOp; + public byte BlendFlags; + public byte SourceConstantAlpha; + public byte AlphaFormat; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct WINDOWPOS + { + public readonly IntPtr hwnd; + public readonly IntPtr hwndInsertAfter; + public int x; + public int y; + public readonly int cx; + public readonly int cy; + public uint flags; + } + + [StructLayout(LayoutKind.Sequential)] + public struct BITMAPINFO + { + public int Size; + public int Width; + public int Height; + public short Planes; + public short BitCount; + public int Compression; + public int SizeImage; + public int XPelsPerMeter; + public int YPelsPerMeter; + public int ClrUsed; + public int ClrImportant; + public int Colors; + } + + public static readonly IntPtr HWND_BOTTOM = (IntPtr)1; + public static readonly IntPtr HWND_TOPMOST = (IntPtr)(-1); + + public const int WS_EX_LAYERED = 0x00080000; + public const int WS_EX_TOOLWINDOW = 0x00000080; + + public const uint SWP_NOSIZE = 0x0001; + public const uint SWP_NOMOVE = 0x0002; + public const uint SWP_NOACTIVATE = 0x0010; + public const uint SWP_FRAMECHANGED = 0x0020; + public const uint SWP_HIDEWINDOW = 0x0080; + public const uint SWP_SHOWWINDOW = 0x0040; + public const uint SWP_NOZORDER = 0x0004; + public const uint SWP_NOSENDCHANGING = 0x0400; + + public const int ULW_COLORKEY = 0x00000001; + public const int ULW_ALPHA = 0x00000002; + public const int ULW_OPAQUE = 0x00000004; + + public const byte AC_SRC_OVER = 0x00; + public const byte AC_SRC_ALPHA = 0x01; + + public const int WM_NCHITTEST = 0x0084; + public const int WM_NCLBUTTONDBLCLK = 0x00A3; + public const int WM_NCLBUTTONDOWN = 0x00A1; + public const int WM_NCLBUTTONUP = 0x00A2; + public const int WM_NCRBUTTONDOWN = 0x00A4; + public const int WM_NCRBUTTONUP = 0x00A5; + public const int WM_WINDOWPOSCHANGING = 0x0046; + public const int WM_COMMAND = 0x0111; + + public const int TPM_RIGHTBUTTON = 0x0002; + public const int TPM_VERTICAL = 0x0040; + + private enum WindowAttribute : int + { + DWMWA_NCRENDERING_ENABLED = 1, + DWMWA_NCRENDERING_POLICY, + DWMWA_TRANSITIONS_FORCEDISABLED, + DWMWA_ALLOW_NCPAINT, + DWMWA_CAPTION_BUTTON_BOUNDS, + DWMWA_NONCLIENT_RTL_LAYOUT, + DWMWA_FORCE_ICONIC_REPRESENTATION, + DWMWA_FLIP3D_POLICY, + DWMWA_EXTENDED_FRAME_BOUNDS, + DWMWA_HAS_ICONIC_BITMAP, + DWMWA_DISALLOW_PEEK, + DWMWA_EXCLUDED_FROM_PEEK, + DWMWA_LAST + } + + /// + /// Some macros imported and converted from the Windows SDK + /// + private static class Macros + { + public static ushort LOWORD(IntPtr l) + { + return (ushort)((ulong)l & 0xFFFF); + } + + public static ushort HIWORD(IntPtr l) + { + return (ushort)(((ulong)l >> 16) & 0xFFFF); + } + + public static int GET_X_LPARAM(IntPtr lp) + { + return (short)LOWORD(lp); + } + + public static int GET_Y_LPARAM(IntPtr lp) + { + return (short)HIWORD(lp); + } + } + + /// + /// Imported native methods + /// + private static class NativeMethods + { + private const string USER = "user32.dll"; + private const string GDI = "gdi32.dll"; + private const string DWMAPI = "dwmapi.dll"; + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, IntPtr pptDst, ref Size psize, IntPtr hdcSrc, IntPtr pprSrc, int crKey, IntPtr pblend, int dwFlags); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, IntPtr pptDst, ref Size psize, IntPtr hdcSrc, ref Point pprSrc, int crKey, ref BlendFunction pblend, int dwFlags); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UpdateLayeredWindow(IntPtr hwnd, IntPtr hdcDst, IntPtr pptDst, IntPtr psize, IntPtr hdcSrc, IntPtr pprSrc, int crKey, ref BlendFunction pblend, int dwFlags); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr GetDC(IntPtr hWnd); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern bool TrackPopupMenuEx(IntPtr hMenu, uint uFlags, int x, int y, IntPtr hWnd, IntPtr tpmParams); + + [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr CreateCompatibleDC(IntPtr hDC); + + [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr CreateDIBSection(IntPtr hdc, [In] ref BITMAPINFO pbmi, uint pila, out IntPtr ppvBits, IntPtr hSection, uint dwOffset); + + [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteDC(IntPtr hdc); + + [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject); + + [DllImport(GDI, CallingConvention = CallingConvention.Winapi)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool DeleteObject(IntPtr hObject); + + [DllImport(DWMAPI, CallingConvention = CallingConvention.Winapi)] + public static extern int DwmSetWindowAttribute(IntPtr hwnd, WindowAttribute dwAttribute, ref bool pvAttribute, int cbAttribute); } } + +public delegate void HitTestEventHandler(object sender, HitTestEventArgs e); + +public enum HitResult +{ + Transparent = -1, + Nowhere = 0, + Client = 1, + Caption = 2, + Left = 10, + Right = 11, + Top = 12, + TopLeft = 13, + TopRight = 14, + Bottom = 15, + BottomLeft = 16, + BottomRight = 17, + Border = 18 +} + +public class HitTestEventArgs : EventArgs +{ + public HitTestEventArgs(Point location, HitResult hitResult) + { + Location = location; + HitResult = hitResult; + } + public Point Location { get; } + public HitResult HitResult { get; set; } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/HardwareNode.cs b/LibreHardwareMonitor/UI/HardwareNode.cs index fc2ed6c..86f3e11 100644 --- a/LibreHardwareMonitor/UI/HardwareNode.cs +++ b/LibreHardwareMonitor/UI/HardwareNode.cs @@ -10,149 +10,148 @@ using System; using System.Collections.Generic; using System.Text; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class HardwareNode : Node, IExpandPersistNode { - public class HardwareNode : Node, IExpandPersistNode + private readonly PersistentSettings _settings; + private readonly UnitManager _unitManager; + private readonly List _typeNodes = new List(); + private readonly string _expandedIdentifier; + private bool _expanded; + + public event EventHandler PlotSelectionChanged; + + public HardwareNode(IHardware hardware, PersistentSettings settings, UnitManager unitManager) { - private readonly PersistentSettings _settings; - private readonly UnitManager _unitManager; - private readonly List _typeNodes = new List(); - private readonly string _expandedIdentifier; - private bool _expanded; + _settings = settings; + _unitManager = unitManager; + _expandedIdentifier = new Identifier(hardware.Identifier, "expanded").ToString(); + Hardware = hardware; + Image = HardwareTypeImage.Instance.GetImage(hardware.HardwareType); - public event EventHandler PlotSelectionChanged; + foreach (SensorType sensorType in Enum.GetValues(typeof(SensorType))) + _typeNodes.Add(new TypeNode(sensorType, hardware.Identifier, _settings)); - public HardwareNode(IHardware hardware, PersistentSettings settings, UnitManager unitManager) + foreach (ISensor sensor in hardware.Sensors) + SensorAdded(sensor); + + hardware.SensorAdded += SensorAdded; + hardware.SensorRemoved += SensorRemoved; + + _expanded = settings.GetValue(_expandedIdentifier, true); + } + + + public override string Text + { + get { return Hardware.Name; } + set { Hardware.Name = value; } + } + + public override string ToolTip + { + get { - _settings = settings; - _unitManager = unitManager; - _expandedIdentifier = new Identifier(hardware.Identifier, "expanded").ToString(); - Hardware = hardware; - Image = HardwareTypeImage.Instance.GetImage(hardware.HardwareType); + IDictionary properties = Hardware.Properties; - foreach (SensorType sensorType in Enum.GetValues(typeof(SensorType))) - _typeNodes.Add(new TypeNode(sensorType, hardware.Identifier, _settings)); - - foreach (ISensor sensor in hardware.Sensors) - SensorAdded(sensor); - - hardware.SensorAdded += SensorAdded; - hardware.SensorRemoved += SensorRemoved; - - _expanded = settings.GetValue(_expandedIdentifier, true); - } - - - public override string Text - { - get { return Hardware.Name; } - set { Hardware.Name = value; } - } - - public override string ToolTip - { - get + if (properties.Count > 0) { - IDictionary properties = Hardware.Properties; - - if (properties.Count > 0) - { - StringBuilder stringBuilder = new(); - stringBuilder.AppendLine("Hardware properties:"); + StringBuilder stringBuilder = new(); + stringBuilder.AppendLine("Hardware properties:"); - foreach (KeyValuePair property in properties) - stringBuilder.AppendFormat(" • {0}: {1}\n", property.Key, property.Value); + foreach (KeyValuePair property in properties) + stringBuilder.AppendFormat(" • {0}: {1}\n", property.Key, property.Value); - return stringBuilder.ToString(); - } + return stringBuilder.ToString(); + } - return null; + return null; + } + } + + public IHardware Hardware { get; } + + public bool Expanded + { + get => _expanded; + set + { + _expanded = value; + _settings.SetValue(_expandedIdentifier, _expanded); + } + } + + private void UpdateNode(TypeNode node) + { + if (node.Nodes.Count > 0) + { + if (!Nodes.Contains(node)) + { + int i = 0; + while (i < Nodes.Count && ((TypeNode)Nodes[i]).SensorType < node.SensorType) + i++; + + Nodes.Insert(i, node); } } - - public IHardware Hardware { get; } - - public bool Expanded + else { - get => _expanded; - set - { - _expanded = value; - _settings.SetValue(_expandedIdentifier, _expanded); - } + if (Nodes.Contains(node)) + Nodes.Remove(node); } + } - private void UpdateNode(TypeNode node) + private void SensorRemoved(ISensor sensor) + { + foreach (TypeNode typeNode in _typeNodes) { - if (node.Nodes.Count > 0) + if (typeNode.SensorType == sensor.SensorType) { - if (!Nodes.Contains(node)) + SensorNode sensorNode = null; + foreach (Node node in typeNode.Nodes) { - int i = 0; - while (i < Nodes.Count && ((TypeNode)Nodes[i]).SensorType < node.SensorType) - i++; - - Nodes.Insert(i, node); + if (node is SensorNode n && n.Sensor == sensor) + sensorNode = n; } - } - else - { - if (Nodes.Contains(node)) - Nodes.Remove(node); - } - } - - private void SensorRemoved(ISensor sensor) - { - foreach (TypeNode typeNode in _typeNodes) - { - if (typeNode.SensorType == sensor.SensorType) + if (sensorNode != null) { - SensorNode sensorNode = null; - foreach (Node node in typeNode.Nodes) - { - if (node is SensorNode n && n.Sensor == sensor) - sensorNode = n; - } - if (sensorNode != null) - { - sensorNode.PlotSelectionChanged -= SensorPlotSelectionChanged; - typeNode.Nodes.Remove(sensorNode); - UpdateNode(typeNode); - } - } - } - PlotSelectionChanged?.Invoke(this, null); - } - - private void InsertSorted(Node node, ISensor sensor) - { - int i = 0; - while (i < node.Nodes.Count && ((SensorNode)node.Nodes[i]).Sensor.Index < sensor.Index) - i++; - - SensorNode sensorNode = new SensorNode(sensor, _settings, _unitManager); - sensorNode.PlotSelectionChanged += SensorPlotSelectionChanged; - node.Nodes.Insert(i, sensorNode); - } - - private void SensorPlotSelectionChanged(object sender, EventArgs e) - { - PlotSelectionChanged?.Invoke(this, null); - } - - private void SensorAdded(ISensor sensor) - { - foreach (TypeNode typeNode in _typeNodes) - { - if (typeNode.SensorType == sensor.SensorType) - { - InsertSorted(typeNode, sensor); + sensorNode.PlotSelectionChanged -= SensorPlotSelectionChanged; + typeNode.Nodes.Remove(sensorNode); UpdateNode(typeNode); } } - - PlotSelectionChanged?.Invoke(this, null); } + PlotSelectionChanged?.Invoke(this, null); } -} + + private void InsertSorted(Node node, ISensor sensor) + { + int i = 0; + while (i < node.Nodes.Count && ((SensorNode)node.Nodes[i]).Sensor.Index < sensor.Index) + i++; + + SensorNode sensorNode = new SensorNode(sensor, _settings, _unitManager); + sensorNode.PlotSelectionChanged += SensorPlotSelectionChanged; + node.Nodes.Insert(i, sensorNode); + } + + private void SensorPlotSelectionChanged(object sender, EventArgs e) + { + PlotSelectionChanged?.Invoke(this, null); + } + + private void SensorAdded(ISensor sensor) + { + foreach (TypeNode typeNode in _typeNodes) + { + if (typeNode.SensorType == sensor.SensorType) + { + InsertSorted(typeNode, sensor); + UpdateNode(typeNode); + } + } + + PlotSelectionChanged?.Invoke(this, null); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/HardwareTypeImage.cs b/LibreHardwareMonitor/UI/HardwareTypeImage.cs index 7e947ef..0f8b8fc 100644 --- a/LibreHardwareMonitor/UI/HardwareTypeImage.cs +++ b/LibreHardwareMonitor/UI/HardwareTypeImage.cs @@ -8,67 +8,66 @@ using System.Drawing; using System.Collections.Generic; using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class HardwareTypeImage { - public class HardwareTypeImage + private readonly IDictionary _images = new Dictionary(); + + private HardwareTypeImage() { } + + public static HardwareTypeImage Instance { get; } = new HardwareTypeImage(); + + public Image GetImage(HardwareType hardwareType) { - private readonly IDictionary _images = new Dictionary(); - - private HardwareTypeImage() { } - - public static HardwareTypeImage Instance { get; } = new HardwareTypeImage(); - - public Image GetImage(HardwareType hardwareType) - { - if (_images.TryGetValue(hardwareType, out Image image)) - return image; - - - switch (hardwareType) - { - case HardwareType.Cpu: - image = Utilities.EmbeddedResources.GetImage("cpu.png"); - break; - case HardwareType.GpuNvidia: - image = Utilities.EmbeddedResources.GetImage("nvidia.png"); - break; - case HardwareType.GpuAmd: - image = Utilities.EmbeddedResources.GetImage("amd.png"); - break; - case HardwareType.GpuIntel: - image = Utilities.EmbeddedResources.GetImage("intel.png"); - break; - case HardwareType.Storage: - image = Utilities.EmbeddedResources.GetImage("hdd.png"); - break; - case HardwareType.Motherboard: - image = Utilities.EmbeddedResources.GetImage("mainboard.png"); - break; - case HardwareType.SuperIO: - case HardwareType.EmbeddedController: - image = Utilities.EmbeddedResources.GetImage("chip.png"); - break; - case HardwareType.Memory: - image = Utilities.EmbeddedResources.GetImage("ram.png"); - break; - case HardwareType.Network: - image = Utilities.EmbeddedResources.GetImage("nic.png"); - break; - case HardwareType.Cooler: - image = Utilities.EmbeddedResources.GetImage("fan.png"); - break; - case HardwareType.Psu: - image = Utilities.EmbeddedResources.GetImage("power-supply.png"); - break; - case HardwareType.Battery: - image = Utilities.EmbeddedResources.GetImage("battery.png"); - break; - default: - image = new Bitmap(1, 1); - break; - } - _images.Add(hardwareType, image); + if (_images.TryGetValue(hardwareType, out Image image)) return image; + + + switch (hardwareType) + { + case HardwareType.Cpu: + image = Utilities.EmbeddedResources.GetImage("cpu.png"); + break; + case HardwareType.GpuNvidia: + image = Utilities.EmbeddedResources.GetImage("nvidia.png"); + break; + case HardwareType.GpuAmd: + image = Utilities.EmbeddedResources.GetImage("amd.png"); + break; + case HardwareType.GpuIntel: + image = Utilities.EmbeddedResources.GetImage("intel.png"); + break; + case HardwareType.Storage: + image = Utilities.EmbeddedResources.GetImage("hdd.png"); + break; + case HardwareType.Motherboard: + image = Utilities.EmbeddedResources.GetImage("mainboard.png"); + break; + case HardwareType.SuperIO: + case HardwareType.EmbeddedController: + image = Utilities.EmbeddedResources.GetImage("chip.png"); + break; + case HardwareType.Memory: + image = Utilities.EmbeddedResources.GetImage("ram.png"); + break; + case HardwareType.Network: + image = Utilities.EmbeddedResources.GetImage("nic.png"); + break; + case HardwareType.Cooler: + image = Utilities.EmbeddedResources.GetImage("fan.png"); + break; + case HardwareType.Psu: + image = Utilities.EmbeddedResources.GetImage("power-supply.png"); + break; + case HardwareType.Battery: + image = Utilities.EmbeddedResources.GetImage("battery.png"); + break; + default: + image = new Bitmap(1, 1); + break; } + _images.Add(hardwareType, image); + return image; } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/IExpandPersistNode.cs b/LibreHardwareMonitor/UI/IExpandPersistNode.cs index 63c0441..63b433b 100644 --- a/LibreHardwareMonitor/UI/IExpandPersistNode.cs +++ b/LibreHardwareMonitor/UI/IExpandPersistNode.cs @@ -1,7 +1,6 @@ -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public interface IExpandPersistNode { - public interface IExpandPersistNode - { - bool Expanded { get; set; } - } -} + bool Expanded { get; set; } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/MainForm.cs b/LibreHardwareMonitor/UI/MainForm.cs index 6c3ee79..3d7c4d9 100644 --- a/LibreHardwareMonitor/UI/MainForm.cs +++ b/LibreHardwareMonitor/UI/MainForm.cs @@ -17,1096 +17,1095 @@ using LibreHardwareMonitor.Hardware; using LibreHardwareMonitor.Utilities; using LibreHardwareMonitor.Wmi; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public sealed partial class MainForm : Form { - public sealed partial class MainForm : Form + private readonly UserOption _autoStart; + private readonly Computer _computer; + private readonly SensorGadget _gadget; + private readonly Logger _logger; + private readonly UserRadioGroup _loggingInterval; + private readonly UserOption _logSensors; + private readonly UserOption _minimizeOnClose; + private readonly UserOption _minimizeToTray; + private readonly Color[] _plotColorPalette; + private readonly PlotPanel _plotPanel; + private readonly UserOption _readBatterySensors; + private readonly UserOption _readCpuSensors; + private readonly UserOption _readFanControllersSensors; + private readonly UserOption _readGpuSensors; + private readonly UserOption _readHddSensors; + private readonly UserOption _readMainboardSensors; + private readonly UserOption _readNicSensors; + private readonly UserOption _readPsuSensors; + private readonly UserOption _readRamSensors; + private readonly Node _root; + private readonly UserOption _runWebServer; + private readonly UserRadioGroup _sensorValuesTimeWindow; + private readonly PersistentSettings _settings; + private readonly UserOption _showGadget; + private readonly StartupManager _startupManager = new(); + private readonly SystemTray _systemTray; + private readonly UnitManager _unitManager; + private readonly UpdateVisitor _updateVisitor = new(); + private readonly WmiProvider _wmiProvider; + + private int _delayCount; + private Form _plotForm; + private UserRadioGroup _plotLocation; + private bool _selectionDragging; + private IDictionary _sensorPlotColors = new Dictionary(); + private UserOption _showPlot; + + public MainForm() { - private readonly UserOption _autoStart; - private readonly Computer _computer; - private readonly SensorGadget _gadget; - private readonly Logger _logger; - private readonly UserRadioGroup _loggingInterval; - private readonly UserOption _logSensors; - private readonly UserOption _minimizeOnClose; - private readonly UserOption _minimizeToTray; - private readonly Color[] _plotColorPalette; - private readonly PlotPanel _plotPanel; - private readonly UserOption _readBatterySensors; - private readonly UserOption _readCpuSensors; - private readonly UserOption _readFanControllersSensors; - private readonly UserOption _readGpuSensors; - private readonly UserOption _readHddSensors; - private readonly UserOption _readMainboardSensors; - private readonly UserOption _readNicSensors; - private readonly UserOption _readPsuSensors; - private readonly UserOption _readRamSensors; - private readonly Node _root; - private readonly UserOption _runWebServer; - private readonly UserRadioGroup _sensorValuesTimeWindow; - private readonly PersistentSettings _settings; - private readonly UserOption _showGadget; - private readonly StartupManager _startupManager = new(); - private readonly SystemTray _systemTray; - private readonly UnitManager _unitManager; - private readonly UpdateVisitor _updateVisitor = new(); - private readonly WmiProvider _wmiProvider; + InitializeComponent(); - private int _delayCount; - private Form _plotForm; - private UserRadioGroup _plotLocation; - private bool _selectionDragging; - private IDictionary _sensorPlotColors = new Dictionary(); - private UserOption _showPlot; + _settings = new PersistentSettings(); + _settings.Load(Path.ChangeExtension(Application.ExecutablePath, ".config")); - public MainForm() + _unitManager = new UnitManager(_settings); + + // make sure the buffers used for double buffering are not disposed + // after each draw call + BufferedGraphicsManager.Current.MaximumBuffer = Screen.PrimaryScreen.Bounds.Size; + + // set the DockStyle here, to avoid conflicts with the MainMenu + splitContainer.Dock = DockStyle.Fill; + + Font = SystemFonts.MessageBoxFont; + treeView.Font = SystemFonts.MessageBoxFont; + + // Set the bounds immediately, so that our child components can be + // properly placed. + Bounds = new Rectangle { - InitializeComponent(); + X = _settings.GetValue("mainForm.Location.X", Location.X), + Y = _settings.GetValue("mainForm.Location.Y", Location.Y), + Width = _settings.GetValue("mainForm.Width", 470), + Height = _settings.GetValue("mainForm.Height", 640) + }; - _settings = new PersistentSettings(); - _settings.Load(Path.ChangeExtension(Application.ExecutablePath, ".config")); + _plotPanel = new PlotPanel(_settings, _unitManager) { Font = SystemFonts.MessageBoxFont, Dock = DockStyle.Fill }; - _unitManager = new UnitManager(_settings); + nodeCheckBox.IsVisibleValueNeeded += NodeCheckBox_IsVisibleValueNeeded; + nodeTextBoxText.DrawText += NodeTextBoxText_DrawText; + nodeTextBoxValue.DrawText += NodeTextBoxText_DrawText; + nodeTextBoxMin.DrawText += NodeTextBoxText_DrawText; + nodeTextBoxMax.DrawText += NodeTextBoxText_DrawText; + nodeTextBoxText.EditorShowing += NodeTextBoxText_EditorShowing; - // make sure the buffers used for double buffering are not disposed - // after each draw call - BufferedGraphicsManager.Current.MaximumBuffer = Screen.PrimaryScreen.Bounds.Size; + foreach (TreeColumn column in treeView.Columns) + column.Width = Math.Max(20, Math.Min(400, _settings.GetValue("treeView.Columns." + column.Header + ".Width", column.Width))); - // set the DockStyle here, to avoid conflicts with the MainMenu - splitContainer.Dock = DockStyle.Fill; + TreeModel treeModel = new(); + _root = new Node(Environment.MachineName) { Image = EmbeddedResources.GetImage("computer.png") }; - Font = SystemFonts.MessageBoxFont; - treeView.Font = SystemFonts.MessageBoxFont; + treeModel.Nodes.Add(_root); + treeView.Model = treeModel; - // Set the bounds immediately, so that our child components can be - // properly placed. - Bounds = new Rectangle - { - X = _settings.GetValue("mainForm.Location.X", Location.X), - Y = _settings.GetValue("mainForm.Location.Y", Location.Y), - Width = _settings.GetValue("mainForm.Width", 470), - Height = _settings.GetValue("mainForm.Height", 640) - }; + _computer = new Computer(_settings); - _plotPanel = new PlotPanel(_settings, _unitManager) { Font = SystemFonts.MessageBoxFont, Dock = DockStyle.Fill }; + _systemTray = new SystemTray(_computer, _settings, _unitManager); + _systemTray.HideShowCommand += HideShowClick; + _systemTray.ExitCommand += ExitClick; - nodeCheckBox.IsVisibleValueNeeded += NodeCheckBox_IsVisibleValueNeeded; - nodeTextBoxText.DrawText += NodeTextBoxText_DrawText; - nodeTextBoxValue.DrawText += NodeTextBoxText_DrawText; - nodeTextBoxMin.DrawText += NodeTextBoxText_DrawText; - nodeTextBoxMax.DrawText += NodeTextBoxText_DrawText; - nodeTextBoxText.EditorShowing += NodeTextBoxText_EditorShowing; - - foreach (TreeColumn column in treeView.Columns) - column.Width = Math.Max(20, Math.Min(400, _settings.GetValue("treeView.Columns." + column.Header + ".Width", column.Width))); - - TreeModel treeModel = new(); - _root = new Node(Environment.MachineName) { Image = EmbeddedResources.GetImage("computer.png") }; - - treeModel.Nodes.Add(_root); - treeView.Model = treeModel; - - _computer = new Computer(_settings); - - _systemTray = new SystemTray(_computer, _settings, _unitManager); - _systemTray.HideShowCommand += HideShowClick; - _systemTray.ExitCommand += ExitClick; - - if (Software.OperatingSystem.IsUnix) - { - // Unix - treeView.RowHeight = Math.Max(treeView.RowHeight, 18); - splitContainer.BorderStyle = BorderStyle.None; - splitContainer.Border3DStyle = Border3DStyle.Adjust; - splitContainer.SplitterWidth = 4; - treeView.BorderStyle = BorderStyle.Fixed3D; - _plotPanel.BorderStyle = BorderStyle.Fixed3D; - gadgetMenuItem.Visible = false; - minCloseMenuItem.Visible = false; - minTrayMenuItem.Visible = false; - startMinMenuItem.Visible = false; - } - else - { - // Windows - treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 18); - _gadget = new SensorGadget(_computer, _settings, _unitManager); - _gadget.HideShowCommand += HideShowClick; - _wmiProvider = new WmiProvider(_computer); - } - - treeView.ShowNodeToolTips = true; - NodeToolTipProvider tooltipProvider = new(); - nodeTextBoxText.ToolTipProvider = tooltipProvider; - nodeTextBoxValue.ToolTipProvider = tooltipProvider; - _logger = new Logger(_computer); - - _plotColorPalette = new Color[13]; - _plotColorPalette[0] = Color.Blue; - _plotColorPalette[1] = Color.OrangeRed; - _plotColorPalette[2] = Color.Green; - _plotColorPalette[3] = Color.LightSeaGreen; - _plotColorPalette[4] = Color.Goldenrod; - _plotColorPalette[5] = Color.DarkViolet; - _plotColorPalette[6] = Color.YellowGreen; - _plotColorPalette[7] = Color.SaddleBrown; - _plotColorPalette[8] = Color.RoyalBlue; - _plotColorPalette[9] = Color.DeepPink; - _plotColorPalette[10] = Color.MediumSeaGreen; - _plotColorPalette[11] = Color.Olive; - _plotColorPalette[12] = Color.Firebrick; - - _computer.HardwareAdded += HardwareAdded; - _computer.HardwareRemoved += HardwareRemoved; - _computer.Open(); - - backgroundUpdater.DoWork += BackgroundUpdater_DoWork; - timer.Enabled = true; - - UserOption showHiddenSensors = new("hiddenMenuItem", false, hiddenMenuItem, _settings); - showHiddenSensors.Changed += delegate { treeModel.ForceVisible = showHiddenSensors.Value; }; - - UserOption showValue = new("valueMenuItem", true, valueMenuItem, _settings); - showValue.Changed += delegate { treeView.Columns[1].IsVisible = showValue.Value; }; - - UserOption showMin = new("minMenuItem", false, minMenuItem, _settings); - showMin.Changed += delegate { treeView.Columns[2].IsVisible = showMin.Value; }; - - UserOption showMax = new("maxMenuItem", true, maxMenuItem, _settings); - showMax.Changed += delegate { treeView.Columns[3].IsVisible = showMax.Value; }; - - var _ = new UserOption("startMinMenuItem", false, startMinMenuItem, _settings); - _minimizeToTray = new UserOption("minTrayMenuItem", true, minTrayMenuItem, _settings); - _minimizeToTray.Changed += delegate { _systemTray.IsMainIconEnabled = _minimizeToTray.Value; }; - - _minimizeOnClose = new UserOption("minCloseMenuItem", false, minCloseMenuItem, _settings); - - _autoStart = new UserOption(null, _startupManager.Startup, startupMenuItem, _settings); - _autoStart.Changed += delegate - { - try - { - _startupManager.Startup = _autoStart.Value; - } - catch (InvalidOperationException) - { - MessageBox.Show("Updating the auto-startup option failed.", - "Error", - MessageBoxButtons.OK, - MessageBoxIcon.Error); - - _autoStart.Value = _startupManager.Startup; - } - }; - - _readMainboardSensors = new UserOption("mainboardMenuItem", true, mainboardMenuItem, _settings); - _readMainboardSensors.Changed += delegate { _computer.IsMotherboardEnabled = _readMainboardSensors.Value; }; - - _readCpuSensors = new UserOption("cpuMenuItem", true, cpuMenuItem, _settings); - _readCpuSensors.Changed += delegate { _computer.IsCpuEnabled = _readCpuSensors.Value; }; - - _readRamSensors = new UserOption("ramMenuItem", true, ramMenuItem, _settings); - _readRamSensors.Changed += delegate { _computer.IsMemoryEnabled = _readRamSensors.Value; }; - - _readGpuSensors = new UserOption("gpuMenuItem", true, gpuMenuItem, _settings); - _readGpuSensors.Changed += delegate { _computer.IsGpuEnabled = _readGpuSensors.Value; }; - - _readFanControllersSensors = new UserOption("fanControllerMenuItem", true, fanControllerMenuItem, _settings); - _readFanControllersSensors.Changed += delegate { _computer.IsControllerEnabled = _readFanControllersSensors.Value; }; - - _readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem, _settings); - _readHddSensors.Changed += delegate { _computer.IsStorageEnabled = _readHddSensors.Value; }; - - _readNicSensors = new UserOption("nicMenuItem", true, nicMenuItem, _settings); - _readNicSensors.Changed += delegate { _computer.IsNetworkEnabled = _readNicSensors.Value; }; - - _readPsuSensors = new UserOption("psuMenuItem", true, psuMenuItem, _settings); - _readPsuSensors.Changed += delegate { _computer.IsPsuEnabled = _readPsuSensors.Value; }; - - _readBatterySensors = new UserOption("batteryMenuItem", true, batteryMenuItem, _settings); - _readBatterySensors.Changed += delegate { _computer.IsBatteryEnabled = _readBatterySensors.Value; }; - - _showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem, _settings); - _showGadget.Changed += delegate - { - if (_gadget != null) - _gadget.Visible = _showGadget.Value; - }; - - celsiusMenuItem.Checked = _unitManager.TemperatureUnit == TemperatureUnit.Celsius; - fahrenheitMenuItem.Checked = !celsiusMenuItem.Checked; - - Server = new HttpServer(_root, - _settings.GetValue("listenerPort", 8085), - _settings.GetValue("authenticationEnabled", false), - _settings.GetValue("authenticationUserName", ""), - _settings.GetValue("authenticationPassword", "")); - - if (Server.PlatformNotSupported) - { - webMenuItemSeparator.Visible = false; - webMenuItem.Visible = false; - } - - _runWebServer = new UserOption("runWebServerMenuItem", false, runWebServerMenuItem, _settings); - _runWebServer.Changed += delegate - { - if (_runWebServer.Value) - Server.StartHttpListener(); - else - Server.StopHttpListener(); - }; - - authWebServerMenuItem.Checked = _settings.GetValue("authenticationEnabled", false); - - _logSensors = new UserOption("logSensorsMenuItem", false, logSensorsMenuItem, _settings); - - _loggingInterval = new UserRadioGroup("loggingInterval", - 0, - new[] - { - log1sMenuItem, - log2sMenuItem, - log5sMenuItem, - log10sMenuItem, - log30sMenuItem, - log1minMenuItem, - log2minMenuItem, - log5minMenuItem, - log10minMenuItem, - log30minMenuItem, - log1hMenuItem, - log2hMenuItem, - log6hMenuItem - }, - _settings); - - _loggingInterval.Changed += (sender, e) => - { - switch (_loggingInterval.Value) - { - case 0: - _logger.LoggingInterval = new TimeSpan(0, 0, 1); - break; - case 1: - _logger.LoggingInterval = new TimeSpan(0, 0, 2); - break; - case 2: - _logger.LoggingInterval = new TimeSpan(0, 0, 5); - break; - case 3: - _logger.LoggingInterval = new TimeSpan(0, 0, 10); - break; - case 4: - _logger.LoggingInterval = new TimeSpan(0, 0, 30); - break; - case 5: - _logger.LoggingInterval = new TimeSpan(0, 1, 0); - break; - case 6: - _logger.LoggingInterval = new TimeSpan(0, 2, 0); - break; - case 7: - _logger.LoggingInterval = new TimeSpan(0, 5, 0); - break; - case 8: - _logger.LoggingInterval = new TimeSpan(0, 10, 0); - break; - case 9: - _logger.LoggingInterval = new TimeSpan(0, 30, 0); - break; - case 10: - _logger.LoggingInterval = new TimeSpan(1, 0, 0); - break; - case 11: - _logger.LoggingInterval = new TimeSpan(2, 0, 0); - break; - case 12: - _logger.LoggingInterval = new TimeSpan(6, 0, 0); - break; - } - }; - - _sensorValuesTimeWindow = new UserRadioGroup("sensorValuesTimeWindow", - 10, - new[] - { - timeWindow30sMenuItem, - timeWindow1minMenuItem, - timeWindow2minMenuItem, - timeWindow5minMenuItem, - timeWindow10minMenuItem, - timeWindow30minMenuItem, - timeWindow1hMenuItem, - timeWindow2hMenuItem, - timeWindow6hMenuItem, - timeWindow12hMenuItem, - timeWindow24hMenuItem - }, - _settings); - - _sensorValuesTimeWindow.Changed += (sender, e) => - { - TimeSpan timeWindow = TimeSpan.Zero; - switch (_sensorValuesTimeWindow.Value) - { - case 0: - timeWindow = new TimeSpan(0, 0, 30); - break; - case 1: - timeWindow = new TimeSpan(0, 1, 0); - break; - case 2: - timeWindow = new TimeSpan(0, 2, 0); - break; - case 3: - timeWindow = new TimeSpan(0, 5, 0); - break; - case 4: - timeWindow = new TimeSpan(0, 10, 0); - break; - case 5: - timeWindow = new TimeSpan(0, 30, 0); - break; - case 6: - timeWindow = new TimeSpan(1, 0, 0); - break; - case 7: - timeWindow = new TimeSpan(2, 0, 0); - break; - case 8: - timeWindow = new TimeSpan(6, 0, 0); - break; - case 9: - timeWindow = new TimeSpan(12, 0, 0); - break; - case 10: - timeWindow = new TimeSpan(24, 0, 0); - break; - } - - _computer.Accept(new SensorVisitor(delegate(ISensor sensor) { sensor.ValuesTimeWindow = timeWindow; })); - }; - - InitializePlotForm(); - InitializeSplitter(); - - startupMenuItem.Visible = _startupManager.IsAvailable; - - if (startMinMenuItem.Checked) - { - if (!minTrayMenuItem.Checked) - { - WindowState = FormWindowState.Minimized; - Show(); - } - } - else - { - Show(); - } - - // Create a handle, otherwise calling Close() does not fire FormClosed - - // Make sure the settings are saved when the user logs off - Microsoft.Win32.SystemEvents.SessionEnded += delegate - { - _computer.Close(); - SaveConfiguration(); - if (_runWebServer.Value) - Server.Quit(); - }; - - Microsoft.Win32.SystemEvents.PowerModeChanged += PowerModeChanged; + if (Software.OperatingSystem.IsUnix) + { + // Unix + treeView.RowHeight = Math.Max(treeView.RowHeight, 18); + splitContainer.BorderStyle = BorderStyle.None; + splitContainer.Border3DStyle = Border3DStyle.Adjust; + splitContainer.SplitterWidth = 4; + treeView.BorderStyle = BorderStyle.Fixed3D; + _plotPanel.BorderStyle = BorderStyle.Fixed3D; + gadgetMenuItem.Visible = false; + minCloseMenuItem.Visible = false; + minTrayMenuItem.Visible = false; + startMinMenuItem.Visible = false; + } + else + { + // Windows + treeView.RowHeight = Math.Max(treeView.Font.Height + 1, 18); + _gadget = new SensorGadget(_computer, _settings, _unitManager); + _gadget.HideShowCommand += HideShowClick; + _wmiProvider = new WmiProvider(_computer); } - public bool AuthWebServerMenuItemChecked + treeView.ShowNodeToolTips = true; + NodeToolTipProvider tooltipProvider = new(); + nodeTextBoxText.ToolTipProvider = tooltipProvider; + nodeTextBoxValue.ToolTipProvider = tooltipProvider; + _logger = new Logger(_computer); + + _plotColorPalette = new Color[13]; + _plotColorPalette[0] = Color.Blue; + _plotColorPalette[1] = Color.OrangeRed; + _plotColorPalette[2] = Color.Green; + _plotColorPalette[3] = Color.LightSeaGreen; + _plotColorPalette[4] = Color.Goldenrod; + _plotColorPalette[5] = Color.DarkViolet; + _plotColorPalette[6] = Color.YellowGreen; + _plotColorPalette[7] = Color.SaddleBrown; + _plotColorPalette[8] = Color.RoyalBlue; + _plotColorPalette[9] = Color.DeepPink; + _plotColorPalette[10] = Color.MediumSeaGreen; + _plotColorPalette[11] = Color.Olive; + _plotColorPalette[12] = Color.Firebrick; + + _computer.HardwareAdded += HardwareAdded; + _computer.HardwareRemoved += HardwareRemoved; + _computer.Open(); + + backgroundUpdater.DoWork += BackgroundUpdater_DoWork; + timer.Enabled = true; + + UserOption showHiddenSensors = new("hiddenMenuItem", false, hiddenMenuItem, _settings); + showHiddenSensors.Changed += delegate { treeModel.ForceVisible = showHiddenSensors.Value; }; + + UserOption showValue = new("valueMenuItem", true, valueMenuItem, _settings); + showValue.Changed += delegate { treeView.Columns[1].IsVisible = showValue.Value; }; + + UserOption showMin = new("minMenuItem", false, minMenuItem, _settings); + showMin.Changed += delegate { treeView.Columns[2].IsVisible = showMin.Value; }; + + UserOption showMax = new("maxMenuItem", true, maxMenuItem, _settings); + showMax.Changed += delegate { treeView.Columns[3].IsVisible = showMax.Value; }; + + var _ = new UserOption("startMinMenuItem", false, startMinMenuItem, _settings); + _minimizeToTray = new UserOption("minTrayMenuItem", true, minTrayMenuItem, _settings); + _minimizeToTray.Changed += delegate { _systemTray.IsMainIconEnabled = _minimizeToTray.Value; }; + + _minimizeOnClose = new UserOption("minCloseMenuItem", false, minCloseMenuItem, _settings); + + _autoStart = new UserOption(null, _startupManager.Startup, startupMenuItem, _settings); + _autoStart.Changed += delegate { - get { return authWebServerMenuItem.Checked; } - set { authWebServerMenuItem.Checked = value; } - } - - public HttpServer Server { get; } - - private void BackgroundUpdater_DoWork(object sender, DoWorkEventArgs e) - { - _computer.Accept(_updateVisitor); - - if (_logSensors != null && _logSensors.Value && _delayCount >= 4) - _logger.Log(); - - if (_delayCount < 4) - _delayCount++; - - _plotPanel.InvalidatePlot(); - } - - private void PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs eventArgs) - { - if (eventArgs.Mode == Microsoft.Win32.PowerModes.Resume) - { - _computer.Reset(); - } - } - - private void InitializeSplitter() - { - splitContainer.SplitterDistance = _settings.GetValue("splitContainer.SplitterDistance", 400); - splitContainer.SplitterMoved += delegate { _settings.SetValue("splitContainer.SplitterDistance", splitContainer.SplitterDistance); }; - } - - private void InitializePlotForm() - { - _plotForm = new Form { FormBorderStyle = FormBorderStyle.SizableToolWindow, ShowInTaskbar = false, StartPosition = FormStartPosition.Manual }; - AddOwnedForm(_plotForm); - _plotForm.Bounds = new Rectangle - { - X = _settings.GetValue("plotForm.Location.X", -100000), - Y = _settings.GetValue("plotForm.Location.Y", 100), - Width = _settings.GetValue("plotForm.Width", 600), - Height = _settings.GetValue("plotForm.Height", 400) - }; - - _showPlot = new UserOption("plotMenuItem", false, plotMenuItem, _settings); - _plotLocation = new UserRadioGroup("plotLocation", 0, new[] { plotWindowMenuItem, plotBottomMenuItem, plotRightMenuItem }, _settings); - - _showPlot.Changed += delegate - { - if (_plotLocation.Value == 0) - { - if (_showPlot.Value && Visible) - _plotForm.Show(); - else - _plotForm.Hide(); - } - else - { - splitContainer.Panel2Collapsed = !_showPlot.Value; - } - - treeView.Invalidate(); - }; - - _plotLocation.Changed += delegate - { - switch (_plotLocation.Value) - { - case 0: - splitContainer.Panel2.Controls.Clear(); - splitContainer.Panel2Collapsed = true; - _plotForm.Controls.Add(_plotPanel); - if (_showPlot.Value && Visible) - _plotForm.Show(); - - break; - case 1: - _plotForm.Controls.Clear(); - _plotForm.Hide(); - splitContainer.Orientation = Orientation.Horizontal; - splitContainer.Panel2.Controls.Add(_plotPanel); - splitContainer.Panel2Collapsed = !_showPlot.Value; - break; - case 2: - _plotForm.Controls.Clear(); - _plotForm.Hide(); - splitContainer.Orientation = Orientation.Vertical; - splitContainer.Panel2.Controls.Add(_plotPanel); - splitContainer.Panel2Collapsed = !_showPlot.Value; - break; - } - }; - - _plotForm.FormClosing += delegate(object sender, FormClosingEventArgs e) - { - if (e.CloseReason == CloseReason.UserClosing) - { - // just switch off the plotting when the user closes the form - if (_plotLocation.Value == 0) - { - _showPlot.Value = false; - } - - e.Cancel = true; - } - }; - - void MoveOrResizePlotForm(object sender, EventArgs e) - { - if (_plotForm.WindowState != FormWindowState.Minimized) - { - _settings.SetValue("plotForm.Location.X", _plotForm.Bounds.X); - _settings.SetValue("plotForm.Location.Y", _plotForm.Bounds.Y); - _settings.SetValue("plotForm.Width", _plotForm.Bounds.Width); - _settings.SetValue("plotForm.Height", _plotForm.Bounds.Height); - } - } - - _plotForm.Move += MoveOrResizePlotForm; - _plotForm.Resize += MoveOrResizePlotForm; - - _plotForm.VisibleChanged += delegate - { - Rectangle bounds = new(_plotForm.Location, _plotForm.Size); - Screen screen = Screen.FromRectangle(bounds); - Rectangle intersection = Rectangle.Intersect(screen.WorkingArea, bounds); - if (intersection.Width < Math.Min(16, bounds.Width) || - intersection.Height < Math.Min(16, bounds.Height)) - { - _plotForm.Location = new Point(screen.WorkingArea.Width / 2 - bounds.Width / 2, - screen.WorkingArea.Height / 2 - bounds.Height / 2); - } - }; - - VisibleChanged += delegate - { - if (Visible && _showPlot.Value && _plotLocation.Value == 0) - _plotForm.Show(); - else - _plotForm.Hide(); - }; - } - - private void InsertSorted(IList nodes, HardwareNode node) - { - int i = 0; - while (i < nodes.Count && nodes[i] is HardwareNode && ((HardwareNode)nodes[i]).Hardware.HardwareType <= node.Hardware.HardwareType) - i++; - - nodes.Insert(i, node); - } - - private void SubHardwareAdded(IHardware hardware, Node node) - { - HardwareNode hardwareNode = new(hardware, _settings, _unitManager); - hardwareNode.PlotSelectionChanged += PlotSelectionChanged; - InsertSorted(node.Nodes, hardwareNode); - foreach (IHardware subHardware in hardware.SubHardware) - SubHardwareAdded(subHardware, hardwareNode); - } - - private void HardwareAdded(IHardware hardware) - { - SubHardwareAdded(hardware, _root); - PlotSelectionChanged(this, null); - } - - private void HardwareRemoved(IHardware hardware) - { - List nodesToRemove = new(); - foreach (Node node in _root.Nodes) - { - if (node is HardwareNode hardwareNode && hardwareNode.Hardware == hardware) - nodesToRemove.Add(hardwareNode); - } - - foreach (HardwareNode hardwareNode in nodesToRemove) - { - _root.Nodes.Remove(hardwareNode); - hardwareNode.PlotSelectionChanged -= PlotSelectionChanged; - } - - PlotSelectionChanged(this, null); - } - - private void NodeTextBoxText_DrawText(object sender, DrawEventArgs e) - { - if (e.Node.Tag is Node node) - { - if (node.IsVisible) - { - if (plotMenuItem.Checked && node is SensorNode sensorNode && _sensorPlotColors.TryGetValue(sensorNode.Sensor, out Color color)) - e.TextColor = color; - } - else - e.TextColor = Color.DarkGray; - } - } - - private void PlotSelectionChanged(object sender, EventArgs e) - { - List selected = new(); - IDictionary colors = new Dictionary(); - int colorIndex = 0; - - foreach (TreeNodeAdv node in treeView.AllNodes) - { - if (node.Tag is SensorNode sensorNode) - { - if (sensorNode.Plot) - { - if (!sensorNode.PenColor.HasValue) - { - colors.Add(sensorNode.Sensor, - _plotColorPalette[colorIndex % _plotColorPalette.Length]); - } - - selected.Add(sensorNode.Sensor); - } - - colorIndex++; - } - } - - // if a sensor is assigned a color that's already being used by another - // sensor, try to assign it a new color. This is done only after the - // previous loop sets an unchanging default color for all sensors, so that - // colors jump around as little as possible as sensors get added/removed - // from the plot - var usedColors = new List(); - foreach (ISensor curSelectedSensor in selected) - { - if (!colors.ContainsKey(curSelectedSensor)) - continue; - - Color curColor = colors[curSelectedSensor]; - if (usedColors.Contains(curColor)) - { - foreach (Color potentialNewColor in _plotColorPalette) - { - if (!colors.Values.Contains(potentialNewColor)) - { - colors[curSelectedSensor] = potentialNewColor; - usedColors.Add(potentialNewColor); - break; - } - } - } - else - { - usedColors.Add(curColor); - } - } - - foreach (TreeNodeAdv node in treeView.AllNodes) - { - if (node.Tag is SensorNode sensorNode && sensorNode.Plot && sensorNode.PenColor.HasValue) - colors.Add(sensorNode.Sensor, sensorNode.PenColor.Value); - } - - _sensorPlotColors = colors; - _plotPanel.SetSensors(selected, colors); - } - - private void NodeTextBoxText_EditorShowing(object sender, CancelEventArgs e) - { - e.Cancel = !(treeView.CurrentNode != null && (treeView.CurrentNode.Tag is SensorNode || treeView.CurrentNode.Tag is HardwareNode)); - } - - private void NodeCheckBox_IsVisibleValueNeeded(object sender, NodeControlValueEventArgs e) - { - e.Value = e.Node.Tag is SensorNode && plotMenuItem.Checked; - } - - private void ExitClick(object sender, EventArgs e) - { - CloseApplication(); - } - - private void Timer_Tick(object sender, EventArgs e) - { - treeView.Invalidate(); - _systemTray.Redraw(); - _gadget?.Redraw(); - _wmiProvider?.Update(); - - if (!backgroundUpdater.IsBusy) - backgroundUpdater.RunWorkerAsync(); - - RestoreCollapsedNodeState(treeView); - } - - private void SaveConfiguration() - { - if (_plotPanel == null || _settings == null) - return; - - _plotPanel.SetCurrentSettings(); - - foreach (TreeColumn column in treeView.Columns) - _settings.SetValue("treeView.Columns." + column.Header + ".Width", column.Width); - - _settings.SetValue("listenerPort", Server.ListenerPort); - _settings.SetValue("authenticationEnabled", Server.AuthEnabled); - _settings.SetValue("authenticationUserName", Server.UserName); - _settings.SetValue("authenticationPassword", Server.Password); - - string fileName = Path.ChangeExtension(Application.ExecutablePath, ".config"); - try { - _settings.Save(fileName); + _startupManager.Startup = _autoStart.Value; } - catch (UnauthorizedAccessException) + catch (InvalidOperationException) { - MessageBox.Show("Access to the path '" + - fileName + - "' is denied. " + - "The current settings could not be saved.", - "Error", - MessageBoxButtons.OK, - MessageBoxIcon.Error); - } - catch (IOException) - { - MessageBox.Show("The path '" + - fileName + - "' is not writeable. " + - "The current settings could not be saved.", + MessageBox.Show("Updating the auto-startup option failed.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); + + _autoStart.Value = _startupManager.Startup; } + }; + + _readMainboardSensors = new UserOption("mainboardMenuItem", true, mainboardMenuItem, _settings); + _readMainboardSensors.Changed += delegate { _computer.IsMotherboardEnabled = _readMainboardSensors.Value; }; + + _readCpuSensors = new UserOption("cpuMenuItem", true, cpuMenuItem, _settings); + _readCpuSensors.Changed += delegate { _computer.IsCpuEnabled = _readCpuSensors.Value; }; + + _readRamSensors = new UserOption("ramMenuItem", true, ramMenuItem, _settings); + _readRamSensors.Changed += delegate { _computer.IsMemoryEnabled = _readRamSensors.Value; }; + + _readGpuSensors = new UserOption("gpuMenuItem", true, gpuMenuItem, _settings); + _readGpuSensors.Changed += delegate { _computer.IsGpuEnabled = _readGpuSensors.Value; }; + + _readFanControllersSensors = new UserOption("fanControllerMenuItem", true, fanControllerMenuItem, _settings); + _readFanControllersSensors.Changed += delegate { _computer.IsControllerEnabled = _readFanControllersSensors.Value; }; + + _readHddSensors = new UserOption("hddMenuItem", true, hddMenuItem, _settings); + _readHddSensors.Changed += delegate { _computer.IsStorageEnabled = _readHddSensors.Value; }; + + _readNicSensors = new UserOption("nicMenuItem", true, nicMenuItem, _settings); + _readNicSensors.Changed += delegate { _computer.IsNetworkEnabled = _readNicSensors.Value; }; + + _readPsuSensors = new UserOption("psuMenuItem", true, psuMenuItem, _settings); + _readPsuSensors.Changed += delegate { _computer.IsPsuEnabled = _readPsuSensors.Value; }; + + _readBatterySensors = new UserOption("batteryMenuItem", true, batteryMenuItem, _settings); + _readBatterySensors.Changed += delegate { _computer.IsBatteryEnabled = _readBatterySensors.Value; }; + + _showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem, _settings); + _showGadget.Changed += delegate + { + if (_gadget != null) + _gadget.Visible = _showGadget.Value; + }; + + celsiusMenuItem.Checked = _unitManager.TemperatureUnit == TemperatureUnit.Celsius; + fahrenheitMenuItem.Checked = !celsiusMenuItem.Checked; + + Server = new HttpServer(_root, + _settings.GetValue("listenerPort", 8085), + _settings.GetValue("authenticationEnabled", false), + _settings.GetValue("authenticationUserName", ""), + _settings.GetValue("authenticationPassword", "")); + + if (Server.PlatformNotSupported) + { + webMenuItemSeparator.Visible = false; + webMenuItem.Visible = false; } - private void MainForm_Load(object sender, EventArgs e) + _runWebServer = new UserOption("runWebServerMenuItem", false, runWebServerMenuItem, _settings); + _runWebServer.Changed += delegate { - Rectangle newBounds = new() + if (_runWebServer.Value) + Server.StartHttpListener(); + else + Server.StopHttpListener(); + }; + + authWebServerMenuItem.Checked = _settings.GetValue("authenticationEnabled", false); + + _logSensors = new UserOption("logSensorsMenuItem", false, logSensorsMenuItem, _settings); + + _loggingInterval = new UserRadioGroup("loggingInterval", + 0, + new[] + { + log1sMenuItem, + log2sMenuItem, + log5sMenuItem, + log10sMenuItem, + log30sMenuItem, + log1minMenuItem, + log2minMenuItem, + log5minMenuItem, + log10minMenuItem, + log30minMenuItem, + log1hMenuItem, + log2hMenuItem, + log6hMenuItem + }, + _settings); + + _loggingInterval.Changed += (sender, e) => + { + switch (_loggingInterval.Value) { - X = _settings.GetValue("mainForm.Location.X", Location.X), - Y = _settings.GetValue("mainForm.Location.Y", Location.Y), - Width = _settings.GetValue("mainForm.Width", 470), - Height = _settings.GetValue("mainForm.Height", 640) - }; + case 0: + _logger.LoggingInterval = new TimeSpan(0, 0, 1); + break; + case 1: + _logger.LoggingInterval = new TimeSpan(0, 0, 2); + break; + case 2: + _logger.LoggingInterval = new TimeSpan(0, 0, 5); + break; + case 3: + _logger.LoggingInterval = new TimeSpan(0, 0, 10); + break; + case 4: + _logger.LoggingInterval = new TimeSpan(0, 0, 30); + break; + case 5: + _logger.LoggingInterval = new TimeSpan(0, 1, 0); + break; + case 6: + _logger.LoggingInterval = new TimeSpan(0, 2, 0); + break; + case 7: + _logger.LoggingInterval = new TimeSpan(0, 5, 0); + break; + case 8: + _logger.LoggingInterval = new TimeSpan(0, 10, 0); + break; + case 9: + _logger.LoggingInterval = new TimeSpan(0, 30, 0); + break; + case 10: + _logger.LoggingInterval = new TimeSpan(1, 0, 0); + break; + case 11: + _logger.LoggingInterval = new TimeSpan(2, 0, 0); + break; + case 12: + _logger.LoggingInterval = new TimeSpan(6, 0, 0); + break; + } + }; - Rectangle fullWorkingArea = new(int.MaxValue, int.MaxValue, int.MinValue, int.MinValue); + _sensorValuesTimeWindow = new UserRadioGroup("sensorValuesTimeWindow", + 10, + new[] + { + timeWindow30sMenuItem, + timeWindow1minMenuItem, + timeWindow2minMenuItem, + timeWindow5minMenuItem, + timeWindow10minMenuItem, + timeWindow30minMenuItem, + timeWindow1hMenuItem, + timeWindow2hMenuItem, + timeWindow6hMenuItem, + timeWindow12hMenuItem, + timeWindow24hMenuItem + }, + _settings); - foreach (Screen screen in Screen.AllScreens) - fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds); - - Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds); - if (intersection.Width < 20 || intersection.Height < 20 || !_settings.Contains("mainForm.Location.X")) + _sensorValuesTimeWindow.Changed += (sender, e) => + { + TimeSpan timeWindow = TimeSpan.Zero; + switch (_sensorValuesTimeWindow.Value) { - newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) - (newBounds.Width / 2); - newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) - (newBounds.Height / 2); + case 0: + timeWindow = new TimeSpan(0, 0, 30); + break; + case 1: + timeWindow = new TimeSpan(0, 1, 0); + break; + case 2: + timeWindow = new TimeSpan(0, 2, 0); + break; + case 3: + timeWindow = new TimeSpan(0, 5, 0); + break; + case 4: + timeWindow = new TimeSpan(0, 10, 0); + break; + case 5: + timeWindow = new TimeSpan(0, 30, 0); + break; + case 6: + timeWindow = new TimeSpan(1, 0, 0); + break; + case 7: + timeWindow = new TimeSpan(2, 0, 0); + break; + case 8: + timeWindow = new TimeSpan(6, 0, 0); + break; + case 9: + timeWindow = new TimeSpan(12, 0, 0); + break; + case 10: + timeWindow = new TimeSpan(24, 0, 0); + break; } - Bounds = newBounds; + _computer.Accept(new SensorVisitor(delegate(ISensor sensor) { sensor.ValuesTimeWindow = timeWindow; })); + }; - RestoreCollapsedNodeState(treeView); + InitializePlotForm(); + InitializeSplitter(); - FormClosed += MainForm_FormClosed; - } + startupMenuItem.Visible = _startupManager.IsAvailable; - private void RestoreCollapsedNodeState(TreeViewAdv treeViewAdv) + if (startMinMenuItem.Checked) { - var collapsedHwNodes = treeViewAdv.AllNodes - .Where(n => n.IsExpanded && n.Tag is IExpandPersistNode expandPersistNode && !expandPersistNode.Expanded) - .OrderByDescending(n => n.Level) - .ToList(); - - foreach (TreeNodeAdv node in collapsedHwNodes) + if (!minTrayMenuItem.Checked) { - node.IsExpanded = false; + WindowState = FormWindowState.Minimized; + Show(); } } - - private void CloseApplication() + else { - FormClosed -= MainForm_FormClosed; + Show(); + } - Visible = false; - _systemTray.IsMainIconEnabled = false; - timer.Enabled = false; + // Create a handle, otherwise calling Close() does not fire FormClosed + + // Make sure the settings are saved when the user logs off + Microsoft.Win32.SystemEvents.SessionEnded += delegate + { _computer.Close(); SaveConfiguration(); if (_runWebServer.Value) Server.Quit(); + }; - _systemTray.Dispose(); - timer.Dispose(); - backgroundUpdater.Dispose(); + Microsoft.Win32.SystemEvents.PowerModeChanged += PowerModeChanged; + } - Application.Exit(); - } + public bool AuthWebServerMenuItemChecked + { + get { return authWebServerMenuItem.Checked; } + set { authWebServerMenuItem.Checked = value; } + } - private void MainForm_FormClosed(object sender, FormClosedEventArgs e) + public HttpServer Server { get; } + + private void BackgroundUpdater_DoWork(object sender, DoWorkEventArgs e) + { + _computer.Accept(_updateVisitor); + + if (_logSensors != null && _logSensors.Value && _delayCount >= 4) + _logger.Log(); + + if (_delayCount < 4) + _delayCount++; + + _plotPanel.InvalidatePlot(); + } + + private void PowerModeChanged(object sender, Microsoft.Win32.PowerModeChangedEventArgs eventArgs) + { + if (eventArgs.Mode == Microsoft.Win32.PowerModes.Resume) { - CloseApplication(); + _computer.Reset(); } + } - private void AboutMenuItem_Click(object sender, EventArgs e) + private void InitializeSplitter() + { + splitContainer.SplitterDistance = _settings.GetValue("splitContainer.SplitterDistance", 400); + splitContainer.SplitterMoved += delegate { _settings.SetValue("splitContainer.SplitterDistance", splitContainer.SplitterDistance); }; + } + + private void InitializePlotForm() + { + _plotForm = new Form { FormBorderStyle = FormBorderStyle.SizableToolWindow, ShowInTaskbar = false, StartPosition = FormStartPosition.Manual }; + AddOwnedForm(_plotForm); + _plotForm.Bounds = new Rectangle { - _ = new AboutBox().ShowDialog(); - } + X = _settings.GetValue("plotForm.Location.X", -100000), + Y = _settings.GetValue("plotForm.Location.Y", 100), + Width = _settings.GetValue("plotForm.Width", 600), + Height = _settings.GetValue("plotForm.Height", 400) + }; - private void TreeView_Click(object sender, EventArgs e) + _showPlot = new UserOption("plotMenuItem", false, plotMenuItem, _settings); + _plotLocation = new UserRadioGroup("plotLocation", 0, new[] { plotWindowMenuItem, plotBottomMenuItem, plotRightMenuItem }, _settings); + + _showPlot.Changed += delegate { - if (!(e is MouseEventArgs m) || (m.Button != MouseButtons.Left && m.Button != MouseButtons.Right)) - return; - - NodeControlInfo info = treeView.GetNodeControlInfoAt(new Point(m.X, m.Y)); - if (m.Button == MouseButtons.Left && info.Node != null) + if (_plotLocation.Value == 0) { - if (info.Node.Tag is IExpandPersistNode expandPersistNode) - { - expandPersistNode.Expanded = info.Node.IsExpanded; - } - - return; - } - - treeView.SelectedNode = info.Node; - if (info.Node != null) - { - if (info.Node.Tag is SensorNode node && node.Sensor != null) - { - treeContextMenu.Items.Clear(); - if (node.Sensor.Parameters.Count > 0) - { - ToolStripItem item = new ToolStripMenuItem("Parameters..."); - item.Click += delegate { ShowParameterForm(node.Sensor); }; - treeContextMenu.Items.Add(item); - } - - if (nodeTextBoxText.EditEnabled) - { - ToolStripItem item = new ToolStripMenuItem("Rename"); - item.Click += delegate { nodeTextBoxText.BeginEdit(); }; - treeContextMenu.Items.Add(item); - } - - if (node.IsVisible) - { - ToolStripItem item = new ToolStripMenuItem("Hide"); - item.Click += delegate { node.IsVisible = false; }; - treeContextMenu.Items.Add(item); - } - else - { - ToolStripItem item = new ToolStripMenuItem("Unhide"); - item.Click += delegate { node.IsVisible = true; }; - treeContextMenu.Items.Add(item); - } - - treeContextMenu.Items.Add(new ToolStripSeparator()); - { - ToolStripItem item = new ToolStripMenuItem("Pen Color..."); - item.Click += delegate - { - ColorDialog dialog = new() { Color = node.PenColor.GetValueOrDefault() }; - if (dialog.ShowDialog() == DialogResult.OK) - node.PenColor = dialog.Color; - }; - - treeContextMenu.Items.Add(item); - } - - { - ToolStripItem item = new ToolStripMenuItem("Reset Pen Color"); - item.Click += delegate { node.PenColor = null; }; - treeContextMenu.Items.Add(item); - } - - treeContextMenu.Items.Add(new ToolStripSeparator()); - { - ToolStripMenuItem item = new("Show in Tray") { Checked = _systemTray.Contains(node.Sensor) }; - item.Click += delegate - { - if (item.Checked) - _systemTray.Remove(node.Sensor); - else - _systemTray.Add(node.Sensor, true); - }; - - treeContextMenu.Items.Add(item); - } - - if (_gadget != null) - { - ToolStripMenuItem item = new("Show in Gadget") { Checked = _gadget.Contains(node.Sensor) }; - item.Click += delegate - { - if (item.Checked) - { - _gadget.Remove(node.Sensor); - } - else - { - _gadget.Add(node.Sensor); - } - }; - - treeContextMenu.Items.Add(item); - } - - if (node.Sensor.Control != null) - { - treeContextMenu.Items.Add(new ToolStripSeparator()); - IControl control = node.Sensor.Control; - ToolStripMenuItem controlItem = new("Control"); - ToolStripItem defaultItem = new ToolStripMenuItem("Default") { Checked = control.ControlMode == ControlMode.Default }; - controlItem.DropDownItems.Add(defaultItem); - defaultItem.Click += delegate { control.SetDefault(); }; - ToolStripMenuItem manualItem = new("Manual"); - controlItem.DropDownItems.Add(manualItem); - manualItem.Checked = control.ControlMode == ControlMode.Software; - for (int i = 0; i <= 100; i += 5) - { - if (i <= control.MaxSoftwareValue && - i >= control.MinSoftwareValue) - { - ToolStripMenuItem item = new ToolStripRadioButtonMenuItem(i + " %"); - manualItem.DropDownItems.Add(item); - item.Checked = control.ControlMode == ControlMode.Software && Math.Round(control.SoftwareValue) == i; - int softwareValue = i; - item.Click += delegate { control.SetSoftware(softwareValue); }; - } - } - - treeContextMenu.Items.Add(controlItem); - } - - treeContextMenu.Show(treeView, new Point(m.X, m.Y)); - } - - if (info.Node.Tag is HardwareNode hardwareNode && hardwareNode.Hardware != null) - { - treeContextMenu.Items.Clear(); - - if (nodeTextBoxText.EditEnabled) - { - ToolStripItem item = new ToolStripMenuItem("Rename"); - item.Click += delegate { nodeTextBoxText.BeginEdit(); }; - treeContextMenu.Items.Add(item); - } - - treeContextMenu.Show(treeView, new Point(m.X, m.Y)); - } - } - } - - private void SaveReportMenuItem_Click(object sender, EventArgs e) - { - string report = _computer.GetReport(); - if (saveFileDialog.ShowDialog() == DialogResult.OK) - { - using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) - { - w.Write(report); - } - } - } - - private void SysTrayHideShow() - { - Visible = !Visible; - if (Visible) - Activate(); - } - - protected override void WndProc(ref Message m) - { - const int WM_SYSCOMMAND = 0x112; - const int SC_MINIMIZE = 0xF020; - const int SC_CLOSE = 0xF060; - - if (_minimizeToTray.Value && m.Msg == WM_SYSCOMMAND && m.WParam.ToInt64() == SC_MINIMIZE) - { - SysTrayHideShow(); - } - else if (_minimizeOnClose.Value && m.Msg == WM_SYSCOMMAND && m.WParam.ToInt64() == SC_CLOSE) - { - //Apparently the user wants to minimize rather than close - //Now we still need to check if we're going to the tray or not - //Note: the correct way to do this would be to send out SC_MINIMIZE, - //but since the code here is so simple, - //that would just be a waste of time. - if (_minimizeToTray.Value) - SysTrayHideShow(); + if (_showPlot.Value && Visible) + _plotForm.Show(); else - WindowState = FormWindowState.Minimized; + _plotForm.Hide(); } else { - base.WndProc(ref m); + splitContainer.Panel2Collapsed = !_showPlot.Value; + } + + treeView.Invalidate(); + }; + + _plotLocation.Changed += delegate + { + switch (_plotLocation.Value) + { + case 0: + splitContainer.Panel2.Controls.Clear(); + splitContainer.Panel2Collapsed = true; + _plotForm.Controls.Add(_plotPanel); + if (_showPlot.Value && Visible) + _plotForm.Show(); + + break; + case 1: + _plotForm.Controls.Clear(); + _plotForm.Hide(); + splitContainer.Orientation = Orientation.Horizontal; + splitContainer.Panel2.Controls.Add(_plotPanel); + splitContainer.Panel2Collapsed = !_showPlot.Value; + break; + case 2: + _plotForm.Controls.Clear(); + _plotForm.Hide(); + splitContainer.Orientation = Orientation.Vertical; + splitContainer.Panel2.Controls.Add(_plotPanel); + splitContainer.Panel2Collapsed = !_showPlot.Value; + break; + } + }; + + _plotForm.FormClosing += delegate(object sender, FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.UserClosing) + { + // just switch off the plotting when the user closes the form + if (_plotLocation.Value == 0) + { + _showPlot.Value = false; + } + + e.Cancel = true; + } + }; + + void MoveOrResizePlotForm(object sender, EventArgs e) + { + if (_plotForm.WindowState != FormWindowState.Minimized) + { + _settings.SetValue("plotForm.Location.X", _plotForm.Bounds.X); + _settings.SetValue("plotForm.Location.Y", _plotForm.Bounds.Y); + _settings.SetValue("plotForm.Width", _plotForm.Bounds.Width); + _settings.SetValue("plotForm.Height", _plotForm.Bounds.Height); } } - private void HideShowClick(object sender, EventArgs e) + _plotForm.Move += MoveOrResizePlotForm; + _plotForm.Resize += MoveOrResizePlotForm; + + _plotForm.VisibleChanged += delegate + { + Rectangle bounds = new(_plotForm.Location, _plotForm.Size); + Screen screen = Screen.FromRectangle(bounds); + Rectangle intersection = Rectangle.Intersect(screen.WorkingArea, bounds); + if (intersection.Width < Math.Min(16, bounds.Width) || + intersection.Height < Math.Min(16, bounds.Height)) + { + _plotForm.Location = new Point(screen.WorkingArea.Width / 2 - bounds.Width / 2, + screen.WorkingArea.Height / 2 - bounds.Height / 2); + } + }; + + VisibleChanged += delegate + { + if (Visible && _showPlot.Value && _plotLocation.Value == 0) + _plotForm.Show(); + else + _plotForm.Hide(); + }; + } + + private void InsertSorted(IList nodes, HardwareNode node) + { + int i = 0; + while (i < nodes.Count && nodes[i] is HardwareNode && ((HardwareNode)nodes[i]).Hardware.HardwareType <= node.Hardware.HardwareType) + i++; + + nodes.Insert(i, node); + } + + private void SubHardwareAdded(IHardware hardware, Node node) + { + HardwareNode hardwareNode = new(hardware, _settings, _unitManager); + hardwareNode.PlotSelectionChanged += PlotSelectionChanged; + InsertSorted(node.Nodes, hardwareNode); + foreach (IHardware subHardware in hardware.SubHardware) + SubHardwareAdded(subHardware, hardwareNode); + } + + private void HardwareAdded(IHardware hardware) + { + SubHardwareAdded(hardware, _root); + PlotSelectionChanged(this, null); + } + + private void HardwareRemoved(IHardware hardware) + { + List nodesToRemove = new(); + foreach (Node node in _root.Nodes) + { + if (node is HardwareNode hardwareNode && hardwareNode.Hardware == hardware) + nodesToRemove.Add(hardwareNode); + } + + foreach (HardwareNode hardwareNode in nodesToRemove) + { + _root.Nodes.Remove(hardwareNode); + hardwareNode.PlotSelectionChanged -= PlotSelectionChanged; + } + + PlotSelectionChanged(this, null); + } + + private void NodeTextBoxText_DrawText(object sender, DrawEventArgs e) + { + if (e.Node.Tag is Node node) + { + if (node.IsVisible) + { + if (plotMenuItem.Checked && node is SensorNode sensorNode && _sensorPlotColors.TryGetValue(sensorNode.Sensor, out Color color)) + e.TextColor = color; + } + else + e.TextColor = Color.DarkGray; + } + } + + private void PlotSelectionChanged(object sender, EventArgs e) + { + List selected = new(); + IDictionary colors = new Dictionary(); + int colorIndex = 0; + + foreach (TreeNodeAdv node in treeView.AllNodes) + { + if (node.Tag is SensorNode sensorNode) + { + if (sensorNode.Plot) + { + if (!sensorNode.PenColor.HasValue) + { + colors.Add(sensorNode.Sensor, + _plotColorPalette[colorIndex % _plotColorPalette.Length]); + } + + selected.Add(sensorNode.Sensor); + } + + colorIndex++; + } + } + + // if a sensor is assigned a color that's already being used by another + // sensor, try to assign it a new color. This is done only after the + // previous loop sets an unchanging default color for all sensors, so that + // colors jump around as little as possible as sensors get added/removed + // from the plot + var usedColors = new List(); + foreach (ISensor curSelectedSensor in selected) + { + if (!colors.ContainsKey(curSelectedSensor)) + continue; + + Color curColor = colors[curSelectedSensor]; + if (usedColors.Contains(curColor)) + { + foreach (Color potentialNewColor in _plotColorPalette) + { + if (!colors.Values.Contains(potentialNewColor)) + { + colors[curSelectedSensor] = potentialNewColor; + usedColors.Add(potentialNewColor); + break; + } + } + } + else + { + usedColors.Add(curColor); + } + } + + foreach (TreeNodeAdv node in treeView.AllNodes) + { + if (node.Tag is SensorNode sensorNode && sensorNode.Plot && sensorNode.PenColor.HasValue) + colors.Add(sensorNode.Sensor, sensorNode.PenColor.Value); + } + + _sensorPlotColors = colors; + _plotPanel.SetSensors(selected, colors); + } + + private void NodeTextBoxText_EditorShowing(object sender, CancelEventArgs e) + { + e.Cancel = !(treeView.CurrentNode != null && (treeView.CurrentNode.Tag is SensorNode || treeView.CurrentNode.Tag is HardwareNode)); + } + + private void NodeCheckBox_IsVisibleValueNeeded(object sender, NodeControlValueEventArgs e) + { + e.Value = e.Node.Tag is SensorNode && plotMenuItem.Checked; + } + + private void ExitClick(object sender, EventArgs e) + { + CloseApplication(); + } + + private void Timer_Tick(object sender, EventArgs e) + { + treeView.Invalidate(); + _systemTray.Redraw(); + _gadget?.Redraw(); + _wmiProvider?.Update(); + + if (!backgroundUpdater.IsBusy) + backgroundUpdater.RunWorkerAsync(); + + RestoreCollapsedNodeState(treeView); + } + + private void SaveConfiguration() + { + if (_plotPanel == null || _settings == null) + return; + + _plotPanel.SetCurrentSettings(); + + foreach (TreeColumn column in treeView.Columns) + _settings.SetValue("treeView.Columns." + column.Header + ".Width", column.Width); + + _settings.SetValue("listenerPort", Server.ListenerPort); + _settings.SetValue("authenticationEnabled", Server.AuthEnabled); + _settings.SetValue("authenticationUserName", Server.UserName); + _settings.SetValue("authenticationPassword", Server.Password); + + string fileName = Path.ChangeExtension(Application.ExecutablePath, ".config"); + + try + { + _settings.Save(fileName); + } + catch (UnauthorizedAccessException) + { + MessageBox.Show("Access to the path '" + + fileName + + "' is denied. " + + "The current settings could not be saved.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + catch (IOException) + { + MessageBox.Show("The path '" + + fileName + + "' is not writeable. " + + "The current settings could not be saved.", + "Error", + MessageBoxButtons.OK, + MessageBoxIcon.Error); + } + } + + private void MainForm_Load(object sender, EventArgs e) + { + Rectangle newBounds = new() + { + X = _settings.GetValue("mainForm.Location.X", Location.X), + Y = _settings.GetValue("mainForm.Location.Y", Location.Y), + Width = _settings.GetValue("mainForm.Width", 470), + Height = _settings.GetValue("mainForm.Height", 640) + }; + + Rectangle fullWorkingArea = new(int.MaxValue, int.MaxValue, int.MinValue, int.MinValue); + + foreach (Screen screen in Screen.AllScreens) + fullWorkingArea = Rectangle.Union(fullWorkingArea, screen.Bounds); + + Rectangle intersection = Rectangle.Intersect(fullWorkingArea, newBounds); + if (intersection.Width < 20 || intersection.Height < 20 || !_settings.Contains("mainForm.Location.X")) + { + newBounds.X = (Screen.PrimaryScreen.WorkingArea.Width / 2) - (newBounds.Width / 2); + newBounds.Y = (Screen.PrimaryScreen.WorkingArea.Height / 2) - (newBounds.Height / 2); + } + + Bounds = newBounds; + + RestoreCollapsedNodeState(treeView); + + FormClosed += MainForm_FormClosed; + } + + private void RestoreCollapsedNodeState(TreeViewAdv treeViewAdv) + { + var collapsedHwNodes = treeViewAdv.AllNodes + .Where(n => n.IsExpanded && n.Tag is IExpandPersistNode expandPersistNode && !expandPersistNode.Expanded) + .OrderByDescending(n => n.Level) + .ToList(); + + foreach (TreeNodeAdv node in collapsedHwNodes) + { + node.IsExpanded = false; + } + } + + private void CloseApplication() + { + FormClosed -= MainForm_FormClosed; + + Visible = false; + _systemTray.IsMainIconEnabled = false; + timer.Enabled = false; + _computer.Close(); + SaveConfiguration(); + if (_runWebServer.Value) + Server.Quit(); + + _systemTray.Dispose(); + timer.Dispose(); + backgroundUpdater.Dispose(); + + Application.Exit(); + } + + private void MainForm_FormClosed(object sender, FormClosedEventArgs e) + { + CloseApplication(); + } + + private void AboutMenuItem_Click(object sender, EventArgs e) + { + _ = new AboutBox().ShowDialog(); + } + + private void TreeView_Click(object sender, EventArgs e) + { + if (!(e is MouseEventArgs m) || (m.Button != MouseButtons.Left && m.Button != MouseButtons.Right)) + return; + + NodeControlInfo info = treeView.GetNodeControlInfoAt(new Point(m.X, m.Y)); + if (m.Button == MouseButtons.Left && info.Node != null) + { + if (info.Node.Tag is IExpandPersistNode expandPersistNode) + { + expandPersistNode.Expanded = info.Node.IsExpanded; + } + + return; + } + + treeView.SelectedNode = info.Node; + if (info.Node != null) + { + if (info.Node.Tag is SensorNode node && node.Sensor != null) + { + treeContextMenu.Items.Clear(); + if (node.Sensor.Parameters.Count > 0) + { + ToolStripItem item = new ToolStripMenuItem("Parameters..."); + item.Click += delegate { ShowParameterForm(node.Sensor); }; + treeContextMenu.Items.Add(item); + } + + if (nodeTextBoxText.EditEnabled) + { + ToolStripItem item = new ToolStripMenuItem("Rename"); + item.Click += delegate { nodeTextBoxText.BeginEdit(); }; + treeContextMenu.Items.Add(item); + } + + if (node.IsVisible) + { + ToolStripItem item = new ToolStripMenuItem("Hide"); + item.Click += delegate { node.IsVisible = false; }; + treeContextMenu.Items.Add(item); + } + else + { + ToolStripItem item = new ToolStripMenuItem("Unhide"); + item.Click += delegate { node.IsVisible = true; }; + treeContextMenu.Items.Add(item); + } + + treeContextMenu.Items.Add(new ToolStripSeparator()); + { + ToolStripItem item = new ToolStripMenuItem("Pen Color..."); + item.Click += delegate + { + ColorDialog dialog = new() { Color = node.PenColor.GetValueOrDefault() }; + if (dialog.ShowDialog() == DialogResult.OK) + node.PenColor = dialog.Color; + }; + + treeContextMenu.Items.Add(item); + } + + { + ToolStripItem item = new ToolStripMenuItem("Reset Pen Color"); + item.Click += delegate { node.PenColor = null; }; + treeContextMenu.Items.Add(item); + } + + treeContextMenu.Items.Add(new ToolStripSeparator()); + { + ToolStripMenuItem item = new("Show in Tray") { Checked = _systemTray.Contains(node.Sensor) }; + item.Click += delegate + { + if (item.Checked) + _systemTray.Remove(node.Sensor); + else + _systemTray.Add(node.Sensor, true); + }; + + treeContextMenu.Items.Add(item); + } + + if (_gadget != null) + { + ToolStripMenuItem item = new("Show in Gadget") { Checked = _gadget.Contains(node.Sensor) }; + item.Click += delegate + { + if (item.Checked) + { + _gadget.Remove(node.Sensor); + } + else + { + _gadget.Add(node.Sensor); + } + }; + + treeContextMenu.Items.Add(item); + } + + if (node.Sensor.Control != null) + { + treeContextMenu.Items.Add(new ToolStripSeparator()); + IControl control = node.Sensor.Control; + ToolStripMenuItem controlItem = new("Control"); + ToolStripItem defaultItem = new ToolStripMenuItem("Default") { Checked = control.ControlMode == ControlMode.Default }; + controlItem.DropDownItems.Add(defaultItem); + defaultItem.Click += delegate { control.SetDefault(); }; + ToolStripMenuItem manualItem = new("Manual"); + controlItem.DropDownItems.Add(manualItem); + manualItem.Checked = control.ControlMode == ControlMode.Software; + for (int i = 0; i <= 100; i += 5) + { + if (i <= control.MaxSoftwareValue && + i >= control.MinSoftwareValue) + { + ToolStripMenuItem item = new ToolStripRadioButtonMenuItem(i + " %"); + manualItem.DropDownItems.Add(item); + item.Checked = control.ControlMode == ControlMode.Software && Math.Round(control.SoftwareValue) == i; + int softwareValue = i; + item.Click += delegate { control.SetSoftware(softwareValue); }; + } + } + + treeContextMenu.Items.Add(controlItem); + } + + treeContextMenu.Show(treeView, new Point(m.X, m.Y)); + } + + if (info.Node.Tag is HardwareNode hardwareNode && hardwareNode.Hardware != null) + { + treeContextMenu.Items.Clear(); + + if (nodeTextBoxText.EditEnabled) + { + ToolStripItem item = new ToolStripMenuItem("Rename"); + item.Click += delegate { nodeTextBoxText.BeginEdit(); }; + treeContextMenu.Items.Add(item); + } + + treeContextMenu.Show(treeView, new Point(m.X, m.Y)); + } + } + } + + private void SaveReportMenuItem_Click(object sender, EventArgs e) + { + string report = _computer.GetReport(); + if (saveFileDialog.ShowDialog() == DialogResult.OK) + { + using (TextWriter w = new StreamWriter(saveFileDialog.FileName)) + { + w.Write(report); + } + } + } + + private void SysTrayHideShow() + { + Visible = !Visible; + if (Visible) + Activate(); + } + + protected override void WndProc(ref Message m) + { + const int WM_SYSCOMMAND = 0x112; + const int SC_MINIMIZE = 0xF020; + const int SC_CLOSE = 0xF060; + + if (_minimizeToTray.Value && m.Msg == WM_SYSCOMMAND && m.WParam.ToInt64() == SC_MINIMIZE) { SysTrayHideShow(); } - - private void ShowParameterForm(ISensor sensorForm) + else if (_minimizeOnClose.Value && m.Msg == WM_SYSCOMMAND && m.WParam.ToInt64() == SC_CLOSE) { - ParameterForm form = new() { Parameters = sensorForm.Parameters, captionLabel = { Text = sensorForm.Name } }; - form.ShowDialog(); + //Apparently the user wants to minimize rather than close + //Now we still need to check if we're going to the tray or not + //Note: the correct way to do this would be to send out SC_MINIMIZE, + //but since the code here is so simple, + //that would just be a waste of time. + if (_minimizeToTray.Value) + SysTrayHideShow(); + else + WindowState = FormWindowState.Minimized; } - - private void TreeView_NodeMouseDoubleClick(object sender, TreeNodeAdvMouseEventArgs e) + else { - if (e.Node.Tag is SensorNode node && node.Sensor != null && node.Sensor.Parameters.Count > 0) - ShowParameterForm(node.Sensor); - } - - private void CelsiusMenuItem_Click(object sender, EventArgs e) - { - celsiusMenuItem.Checked = true; - fahrenheitMenuItem.Checked = false; - _unitManager.TemperatureUnit = TemperatureUnit.Celsius; - } - - private void FahrenheitMenuItem_Click(object sender, EventArgs e) - { - celsiusMenuItem.Checked = false; - fahrenheitMenuItem.Checked = true; - _unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit; - } - - private void ResetMinMaxMenuItem_Click(object sender, EventArgs e) - { - _computer.Accept(new SensorVisitor(delegate(ISensor sensorClick) - { - sensorClick.ResetMin(); - sensorClick.ResetMax(); - })); - } - - private void MainForm_MoveOrResize(object sender, EventArgs e) - { - if (WindowState != FormWindowState.Minimized) - { - _settings.SetValue("mainForm.Location.X", Bounds.X); - _settings.SetValue("mainForm.Location.Y", Bounds.Y); - _settings.SetValue("mainForm.Width", Bounds.Width); - _settings.SetValue("mainForm.Height", Bounds.Height); - } - } - - private void ResetClick(object sender, EventArgs e) - { - // disable the fallback MainIcon during reset, otherwise icon visibility - // might be lost - _systemTray.IsMainIconEnabled = false; - _computer.Reset(); - // restore the MainIcon setting - _systemTray.IsMainIconEnabled = _minimizeToTray.Value; - } - - private void TreeView_MouseMove(object sender, MouseEventArgs e) - { - _selectionDragging &= (e.Button & (MouseButtons.Left | MouseButtons.Right)) > 0; - if (_selectionDragging) - treeView.SelectedNode = treeView.GetNodeAt(e.Location); - } - - private void TreeView_MouseDown(object sender, MouseEventArgs e) - { - _selectionDragging = true; - } - - private void TreeView_MouseUp(object sender, MouseEventArgs e) - { - _selectionDragging = false; - } - - private void ServerPortMenuItem_Click(object sender, EventArgs e) - { - new PortForm(this).ShowDialog(); - } - - private void AuthWebServerMenuItem_Click(object sender, EventArgs e) - { - new AuthForm(this).ShowDialog(); + base.WndProc(ref m); } } -} + + private void HideShowClick(object sender, EventArgs e) + { + SysTrayHideShow(); + } + + private void ShowParameterForm(ISensor sensorForm) + { + ParameterForm form = new() { Parameters = sensorForm.Parameters, captionLabel = { Text = sensorForm.Name } }; + form.ShowDialog(); + } + + private void TreeView_NodeMouseDoubleClick(object sender, TreeNodeAdvMouseEventArgs e) + { + if (e.Node.Tag is SensorNode node && node.Sensor != null && node.Sensor.Parameters.Count > 0) + ShowParameterForm(node.Sensor); + } + + private void CelsiusMenuItem_Click(object sender, EventArgs e) + { + celsiusMenuItem.Checked = true; + fahrenheitMenuItem.Checked = false; + _unitManager.TemperatureUnit = TemperatureUnit.Celsius; + } + + private void FahrenheitMenuItem_Click(object sender, EventArgs e) + { + celsiusMenuItem.Checked = false; + fahrenheitMenuItem.Checked = true; + _unitManager.TemperatureUnit = TemperatureUnit.Fahrenheit; + } + + private void ResetMinMaxMenuItem_Click(object sender, EventArgs e) + { + _computer.Accept(new SensorVisitor(delegate(ISensor sensorClick) + { + sensorClick.ResetMin(); + sensorClick.ResetMax(); + })); + } + + private void MainForm_MoveOrResize(object sender, EventArgs e) + { + if (WindowState != FormWindowState.Minimized) + { + _settings.SetValue("mainForm.Location.X", Bounds.X); + _settings.SetValue("mainForm.Location.Y", Bounds.Y); + _settings.SetValue("mainForm.Width", Bounds.Width); + _settings.SetValue("mainForm.Height", Bounds.Height); + } + } + + private void ResetClick(object sender, EventArgs e) + { + // disable the fallback MainIcon during reset, otherwise icon visibility + // might be lost + _systemTray.IsMainIconEnabled = false; + _computer.Reset(); + // restore the MainIcon setting + _systemTray.IsMainIconEnabled = _minimizeToTray.Value; + } + + private void TreeView_MouseMove(object sender, MouseEventArgs e) + { + _selectionDragging &= (e.Button & (MouseButtons.Left | MouseButtons.Right)) > 0; + if (_selectionDragging) + treeView.SelectedNode = treeView.GetNodeAt(e.Location); + } + + private void TreeView_MouseDown(object sender, MouseEventArgs e) + { + _selectionDragging = true; + } + + private void TreeView_MouseUp(object sender, MouseEventArgs e) + { + _selectionDragging = false; + } + + private void ServerPortMenuItem_Click(object sender, EventArgs e) + { + new PortForm(this).ShowDialog(); + } + + private void AuthWebServerMenuItem_Click(object sender, EventArgs e) + { + new AuthForm(this).ShowDialog(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/Node.cs b/LibreHardwareMonitor/UI/Node.cs index 1ef5131..875d720 100644 --- a/LibreHardwareMonitor/UI/Node.cs +++ b/LibreHardwareMonitor/UI/Node.cs @@ -8,162 +8,161 @@ using System; using System.Collections.ObjectModel; using System.Drawing; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class Node { - public class Node + private Node _parent; + private readonly NodeCollection _nodes; + private string _text; + private bool _visible; + + public delegate void NodeEventHandler(Node node); + public event NodeEventHandler IsVisibleChanged; + public event NodeEventHandler NodeAdded; + public event NodeEventHandler NodeRemoved; + + private TreeModel RootTreeModel() { - private Node _parent; - private readonly NodeCollection _nodes; - private string _text; - private bool _visible; - - public delegate void NodeEventHandler(Node node); - public event NodeEventHandler IsVisibleChanged; - public event NodeEventHandler NodeAdded; - public event NodeEventHandler NodeRemoved; - - private TreeModel RootTreeModel() + Node node = this; + while (node != null) { - Node node = this; - while (node != null) - { - if (node.Model != null) - return node.Model; - node = node._parent; - } - return null; + if (node.Model != null) + return node.Model; + node = node._parent; } + return null; + } - public Node() : this(string.Empty) { } + public Node() : this(string.Empty) { } - public Node(string text) + public Node(string text) + { + _text = text; + _nodes = new NodeCollection(this); + _visible = true; + } + + public TreeModel Model { get; set; } + + public Node Parent + { + get { return _parent; } + set { - _text = text; - _nodes = new NodeCollection(this); - _visible = true; - } - - public TreeModel Model { get; set; } - - public Node Parent - { - get { return _parent; } - set + if (value != _parent) { - if (value != _parent) - { - _parent?._nodes.Remove(this); - value?._nodes.Add(this); - } - } - } - - public Collection Nodes - { - get { return _nodes; } - } - - public virtual string Text - { - get { return _text; } - set - { - _text = value; - } - } - - public virtual string ToolTip { get; } - - public Image Image { get; set; } - - public virtual bool IsVisible - { - get { return _visible; } - set - { - if (value != _visible) - { - _visible = value; - TreeModel model = RootTreeModel(); - if (model != null && _parent != null) - { - int index = 0; - for (int i = 0; i < _parent._nodes.Count; i++) - { - Node node = _parent._nodes[i]; - if (node == this) - break; - if (node.IsVisible || model.ForceVisible) - index++; - } - if (model.ForceVisible) - { - model.OnNodeChanged(_parent, index, this); - } - else - { - if (value) - model.OnNodeInserted(_parent, index, this); - else - model.OnNodeRemoved(_parent, index, this); - } - } - IsVisibleChanged?.Invoke(this); - } - } - } - - private class NodeCollection : Collection - { - private readonly Node _owner; - - public NodeCollection(Node owner) - { - _owner = owner; - } - - protected override void ClearItems() - { - while (Count != 0) - RemoveAt(Count - 1); - } - - protected override void InsertItem(int index, Node item) - { - if (item == null) - throw new ArgumentNullException(nameof(item)); - - if (item._parent != _owner) - { - item._parent?._nodes.Remove(item); - item._parent = _owner; - base.InsertItem(index, item); - - TreeModel model = _owner.RootTreeModel(); - model?.OnStructureChanged(_owner); - _owner.NodeAdded?.Invoke(item); - } - } - - protected override void RemoveItem(int index) - { - Node item = this[index]; - item._parent = null; - base.RemoveItem(index); - - TreeModel model = _owner.RootTreeModel(); - model?.OnStructureChanged(_owner); - _owner.NodeRemoved?.Invoke(item); - } - - protected override void SetItem(int index, Node item) - { - if (item == null) - throw new ArgumentNullException(nameof(item)); - - RemoveAt(index); - InsertItem(index, item); + _parent?._nodes.Remove(this); + value?._nodes.Add(this); } } } -} + + public Collection Nodes + { + get { return _nodes; } + } + + public virtual string Text + { + get { return _text; } + set + { + _text = value; + } + } + + public virtual string ToolTip { get; } + + public Image Image { get; set; } + + public virtual bool IsVisible + { + get { return _visible; } + set + { + if (value != _visible) + { + _visible = value; + TreeModel model = RootTreeModel(); + if (model != null && _parent != null) + { + int index = 0; + for (int i = 0; i < _parent._nodes.Count; i++) + { + Node node = _parent._nodes[i]; + if (node == this) + break; + if (node.IsVisible || model.ForceVisible) + index++; + } + if (model.ForceVisible) + { + model.OnNodeChanged(_parent, index, this); + } + else + { + if (value) + model.OnNodeInserted(_parent, index, this); + else + model.OnNodeRemoved(_parent, index, this); + } + } + IsVisibleChanged?.Invoke(this); + } + } + } + + private class NodeCollection : Collection + { + private readonly Node _owner; + + public NodeCollection(Node owner) + { + _owner = owner; + } + + protected override void ClearItems() + { + while (Count != 0) + RemoveAt(Count - 1); + } + + protected override void InsertItem(int index, Node item) + { + if (item == null) + throw new ArgumentNullException(nameof(item)); + + if (item._parent != _owner) + { + item._parent?._nodes.Remove(item); + item._parent = _owner; + base.InsertItem(index, item); + + TreeModel model = _owner.RootTreeModel(); + model?.OnStructureChanged(_owner); + _owner.NodeAdded?.Invoke(item); + } + } + + protected override void RemoveItem(int index) + { + Node item = this[index]; + item._parent = null; + base.RemoveItem(index); + + TreeModel model = _owner.RootTreeModel(); + model?.OnStructureChanged(_owner); + _owner.NodeRemoved?.Invoke(item); + } + + protected override void SetItem(int index, Node item) + { + if (item == null) + throw new ArgumentNullException(nameof(item)); + + RemoveAt(index); + InsertItem(index, item); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/NodeToolTipProvider.cs b/LibreHardwareMonitor/UI/NodeToolTipProvider.cs index 09ce236..1c19569 100644 --- a/LibreHardwareMonitor/UI/NodeToolTipProvider.cs +++ b/LibreHardwareMonitor/UI/NodeToolTipProvider.cs @@ -6,10 +6,9 @@ using Aga.Controls.Tree; using Aga.Controls.Tree.NodeControls; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +internal class NodeToolTipProvider : IToolTipProvider { - internal class NodeToolTipProvider : IToolTipProvider - { - public string GetToolTip(TreeNodeAdv node, NodeControl nodeControl) => (node.Tag as Node)?.ToolTip; - } -} + public string GetToolTip(TreeNodeAdv node, NodeControl nodeControl) => (node.Tag as Node)?.ToolTip; +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/NotifyIconAdv.cs b/LibreHardwareMonitor/UI/NotifyIconAdv.cs index f95b9e4..7798e45 100644 --- a/LibreHardwareMonitor/UI/NotifyIconAdv.cs +++ b/LibreHardwareMonitor/UI/NotifyIconAdv.cs @@ -11,295 +11,401 @@ using System.Runtime.InteropServices; using System.Reflection; using System.Windows.Forms; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class NotifyIconAdv : IDisposable { - public class NotifyIconAdv : IDisposable + private readonly NotifyIcon _genericNotifyIcon; + private readonly NotifyIconWindowsImplementation _windowsNotifyIcon; + + public NotifyIconAdv() { - private readonly NotifyIcon _genericNotifyIcon; - private readonly NotifyIconWindowsImplementation _windowsNotifyIcon; + if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix) + _genericNotifyIcon = new NotifyIcon(); + else + _windowsNotifyIcon = new NotifyIconWindowsImplementation(); + } - public NotifyIconAdv() + public event EventHandler BalloonTipClicked + { + add { - if (Environment.OSVersion.Platform == PlatformID.MacOSX || Environment.OSVersion.Platform == PlatformID.Unix) - _genericNotifyIcon = new NotifyIcon(); + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipClicked += value; else - _windowsNotifyIcon = new NotifyIconWindowsImplementation(); + _windowsNotifyIcon.BalloonTipClicked += value; } - - public event EventHandler BalloonTipClicked + remove { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipClicked += value; - else - _windowsNotifyIcon.BalloonTipClicked += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipClicked -= value; - else - _windowsNotifyIcon.BalloonTipClicked -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipClicked -= value; + else + _windowsNotifyIcon.BalloonTipClicked -= value; } + } - public event EventHandler BalloonTipClosed + public event EventHandler BalloonTipClosed + { + add { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipClosed += value; - else - _windowsNotifyIcon.BalloonTipClosed += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipClosed -= value; - else - _windowsNotifyIcon.BalloonTipClosed -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipClosed += value; + else + _windowsNotifyIcon.BalloonTipClosed += value; } - - public event EventHandler BalloonTipShown + remove { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipShown += value; - else - _windowsNotifyIcon.BalloonTipShown += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipShown -= value; - else - _windowsNotifyIcon.BalloonTipShown -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipClosed -= value; + else + _windowsNotifyIcon.BalloonTipClosed -= value; } + } - public event EventHandler Click + public event EventHandler BalloonTipShown + { + add { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.Click += value; - else - _windowsNotifyIcon.Click += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.Click -= value; - else - _windowsNotifyIcon.Click -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipShown += value; + else + _windowsNotifyIcon.BalloonTipShown += value; } - - public event EventHandler DoubleClick + remove { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.DoubleClick += value; - else - _windowsNotifyIcon.DoubleClick += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.DoubleClick -= value; - else - _windowsNotifyIcon.DoubleClick -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipShown -= value; + else + _windowsNotifyIcon.BalloonTipShown -= value; } + } - public event MouseEventHandler MouseClick + public event EventHandler Click + { + add { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseClick += value; - else - _windowsNotifyIcon.MouseClick += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseClick -= value; - else - _windowsNotifyIcon.MouseClick -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.Click += value; + else + _windowsNotifyIcon.Click += value; } - - public event MouseEventHandler MouseDoubleClick + remove { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseDoubleClick += value; - else - _windowsNotifyIcon.MouseDoubleClick += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseDoubleClick -= value; - else - _windowsNotifyIcon.MouseDoubleClick -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.Click -= value; + else + _windowsNotifyIcon.Click -= value; } + } - public event MouseEventHandler MouseDown + public event EventHandler DoubleClick + { + add { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseDown += value; - else - _windowsNotifyIcon.MouseDown += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseDown -= value; - else - _windowsNotifyIcon.MouseDown -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.DoubleClick += value; + else + _windowsNotifyIcon.DoubleClick += value; } - - public event MouseEventHandler MouseMove + remove { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseMove += value; - else - _windowsNotifyIcon.MouseMove += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseMove -= value; - else - _windowsNotifyIcon.MouseMove -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.DoubleClick -= value; + else + _windowsNotifyIcon.DoubleClick -= value; } + } - public event MouseEventHandler MouseUp + public event MouseEventHandler MouseClick + { + add { - add - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseUp += value; - else - _windowsNotifyIcon.MouseUp += value; - } - remove - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.MouseUp -= value; - else - _windowsNotifyIcon.MouseUp -= value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseClick += value; + else + _windowsNotifyIcon.MouseClick += value; } - - public string BalloonTipText + remove { - get - { - if (_genericNotifyIcon != null) - return _genericNotifyIcon.BalloonTipText; - - - return _windowsNotifyIcon.BalloonTipText; - } - set - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipText = value; - else - _windowsNotifyIcon.BalloonTipText = value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseClick -= value; + else + _windowsNotifyIcon.MouseClick -= value; } + } - public ToolTipIcon BalloonTipIcon + public event MouseEventHandler MouseDoubleClick + { + add { - get - { - if (_genericNotifyIcon != null) - return _genericNotifyIcon.BalloonTipIcon; - - - return _windowsNotifyIcon.BalloonTipIcon; - } - set - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipIcon = value; - else - _windowsNotifyIcon.BalloonTipIcon = value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseDoubleClick += value; + else + _windowsNotifyIcon.MouseDoubleClick += value; } - - public string BalloonTipTitle + remove { - get - { - if (_genericNotifyIcon != null) - return _genericNotifyIcon.BalloonTipTitle; - - - return _windowsNotifyIcon.BalloonTipTitle; - } - set - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.BalloonTipTitle = value; - else - _windowsNotifyIcon.BalloonTipTitle = value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseDoubleClick -= value; + else + _windowsNotifyIcon.MouseDoubleClick -= value; } + } - public ContextMenuStrip ContextMenuStrip + public event MouseEventHandler MouseDown + { + add { - get - { - if (_genericNotifyIcon != null) - return _genericNotifyIcon.ContextMenuStrip; - - - return _windowsNotifyIcon.ContextMenuStrip; - } - set - { - if (_genericNotifyIcon != null) - _genericNotifyIcon.ContextMenuStrip = value; - else - _windowsNotifyIcon.ContextMenuStrip = value; - } + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseDown += value; + else + _windowsNotifyIcon.MouseDown += value; } + remove + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseDown -= value; + else + _windowsNotifyIcon.MouseDown -= value; + } + } - public object Tag { get; set; } + public event MouseEventHandler MouseMove + { + add + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseMove += value; + else + _windowsNotifyIcon.MouseMove += value; + } + remove + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseMove -= value; + else + _windowsNotifyIcon.MouseMove -= value; + } + } + + public event MouseEventHandler MouseUp + { + add + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseUp += value; + else + _windowsNotifyIcon.MouseUp += value; + } + remove + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.MouseUp -= value; + else + _windowsNotifyIcon.MouseUp -= value; + } + } + + public string BalloonTipText + { + get + { + if (_genericNotifyIcon != null) + return _genericNotifyIcon.BalloonTipText; + + + return _windowsNotifyIcon.BalloonTipText; + } + set + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipText = value; + else + _windowsNotifyIcon.BalloonTipText = value; + } + } + + public ToolTipIcon BalloonTipIcon + { + get + { + if (_genericNotifyIcon != null) + return _genericNotifyIcon.BalloonTipIcon; + + + return _windowsNotifyIcon.BalloonTipIcon; + } + set + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipIcon = value; + else + _windowsNotifyIcon.BalloonTipIcon = value; + } + } + + public string BalloonTipTitle + { + get + { + if (_genericNotifyIcon != null) + return _genericNotifyIcon.BalloonTipTitle; + + + return _windowsNotifyIcon.BalloonTipTitle; + } + set + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.BalloonTipTitle = value; + else + _windowsNotifyIcon.BalloonTipTitle = value; + } + } + + public ContextMenuStrip ContextMenuStrip + { + get + { + if (_genericNotifyIcon != null) + return _genericNotifyIcon.ContextMenuStrip; + + + return _windowsNotifyIcon.ContextMenuStrip; + } + set + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.ContextMenuStrip = value; + else + _windowsNotifyIcon.ContextMenuStrip = value; + } + } + + public object Tag { get; set; } + + public Icon Icon + { + get + { + if (_genericNotifyIcon != null) + return _genericNotifyIcon.Icon; + + + return _windowsNotifyIcon.Icon; + } + set + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.Icon = value; + else + _windowsNotifyIcon.Icon = value; + } + } + + public string Text + { + get + { + if (_genericNotifyIcon != null) + return _genericNotifyIcon.Text; + + + return _windowsNotifyIcon.Text; + } + set + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.Text = value; + else + _windowsNotifyIcon.Text = value; + } + } + + public bool Visible + { + get + { + if (_genericNotifyIcon != null) + return _genericNotifyIcon.Visible; + + + return _windowsNotifyIcon.Visible; + } + set + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.Visible = value; + else + _windowsNotifyIcon.Visible = value; + } + } + + public void Dispose() + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.Dispose(); + else + _windowsNotifyIcon.Dispose(); + } + + public void ShowBalloonTip(int timeout) + { + ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon); + } + + public void ShowBalloonTip(int timeout, string tipTitle, string tipText, + ToolTipIcon tipIcon) + { + if (_genericNotifyIcon != null) + _genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon); + else + _windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon); + } + + private class NotifyIconWindowsImplementation : Component + { + + private static int _nextId; + private readonly object _syncObj = new object(); + private Icon _icon; + private string _text = ""; + private readonly int _id; + private bool _created; + private NotifyIconNativeWindow _window; + private bool _doubleClickDown; + private bool _visible; + private readonly MethodInfo _commandDispatch; + + public event EventHandler BalloonTipClicked; + public event EventHandler BalloonTipClosed; + public event EventHandler BalloonTipShown; + public event EventHandler Click; + public event EventHandler DoubleClick; + public event MouseEventHandler MouseClick; + public event MouseEventHandler MouseDoubleClick; + public event MouseEventHandler MouseDown; + public event MouseEventHandler MouseMove; + public event MouseEventHandler MouseUp; + + public string BalloonTipText { get; set; } + public ToolTipIcon BalloonTipIcon { get; set; } + public string BalloonTipTitle { get; set; } + public ContextMenuStrip ContextMenuStrip { get; set; } public Icon Icon { get { - if (_genericNotifyIcon != null) - return _genericNotifyIcon.Icon; - - - return _windowsNotifyIcon.Icon; + return _icon; } set { - if (_genericNotifyIcon != null) - _genericNotifyIcon.Icon = value; - else - _windowsNotifyIcon.Icon = value; + if (_icon != value) + { + _icon = value; + UpdateNotifyIcon(_visible); + } } } @@ -307,18 +413,22 @@ namespace LibreHardwareMonitor.UI { get { - if (_genericNotifyIcon != null) - return _genericNotifyIcon.Text; - - - return _windowsNotifyIcon.Text; + return _text; } set { - if (_genericNotifyIcon != null) - _genericNotifyIcon.Text = value; - else - _windowsNotifyIcon.Text = value; + if (value == null) + value = ""; + + if (value.Length > 63) + throw new ArgumentOutOfRangeException(); + + if (!value.Equals(_text)) + { + _text = value; + if (_visible) + UpdateNotifyIcon(_visible); + } } } @@ -326,27 +436,56 @@ namespace LibreHardwareMonitor.UI { get { - if (_genericNotifyIcon != null) - return _genericNotifyIcon.Visible; - - - return _windowsNotifyIcon.Visible; + return _visible; } set { - if (_genericNotifyIcon != null) - _genericNotifyIcon.Visible = value; - else - _windowsNotifyIcon.Visible = value; + if (_visible != value) + { + _visible = value; + UpdateNotifyIcon(_visible); + } } } - public void Dispose() + public NotifyIconWindowsImplementation() { - if (_genericNotifyIcon != null) - _genericNotifyIcon.Dispose(); + BalloonTipText = ""; + BalloonTipTitle = ""; + + _commandDispatch = typeof(Form).Assembly. + GetType("System.Windows.Forms.Command").GetMethod("DispatchID", + BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, + null, new[] { typeof(int) }, null); + + _id = ++_nextId; + _window = new NotifyIconNativeWindow(this); + UpdateNotifyIcon(_visible); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + if (_window != null) + { + _icon = null; + _text = ""; + UpdateNotifyIcon(false); + _window.DestroyHandle(); + _window = null; + ContextMenuStrip = null; + } + } else - _windowsNotifyIcon.Dispose(); + { + if (_window != null && _window.Handle != IntPtr.Zero) + { + NativeMethods.PostMessage(new HandleRef(_window, _window.Handle), WM_CLOSE, 0, 0); + _window.ReleaseHandle(); + } + } + base.Dispose(disposing); } public void ShowBalloonTip(int timeout) @@ -354,509 +493,369 @@ namespace LibreHardwareMonitor.UI ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon); } - public void ShowBalloonTip(int timeout, string tipTitle, string tipText, - ToolTipIcon tipIcon) + public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon) { - if (_genericNotifyIcon != null) - _genericNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon); - else - _windowsNotifyIcon.ShowBalloonTip(timeout, tipTitle, tipText, tipIcon); + if (timeout < 0) + throw new ArgumentOutOfRangeException(nameof(timeout)); + + if (string.IsNullOrEmpty(tipText)) + throw new ArgumentException("tipText"); + + if (DesignMode) + return; + + if (_created) + { + NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData(); + if (_window.Handle == IntPtr.Zero) + _window.CreateHandle(new CreateParams()); + + data.Window = _window.Handle; + data.ID = _id; + data.Flags = NativeMethods.NotifyIconDataFlags.Info; + data.TimeoutOrVersion = timeout; + data.InfoTitle = tipTitle; + data.Info = tipText; + data.InfoFlags = (int)tipIcon; + + NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Modify, data); + } } - private class NotifyIconWindowsImplementation : Component + private void ShowContextMenu() { + if (ContextMenuStrip == null) + return; - private static int _nextId; - private readonly object _syncObj = new object(); - private Icon _icon; - private string _text = ""; - private readonly int _id; - private bool _created; - private NotifyIconNativeWindow _window; - private bool _doubleClickDown; - private bool _visible; - private readonly MethodInfo _commandDispatch; + NativeMethods.Point p = new NativeMethods.Point(); + NativeMethods.GetCursorPos(ref p); + NativeMethods.SetForegroundWindow(new HandleRef(_window, _window.Handle)); - public event EventHandler BalloonTipClicked; - public event EventHandler BalloonTipClosed; - public event EventHandler BalloonTipShown; - public event EventHandler Click; - public event EventHandler DoubleClick; - public event MouseEventHandler MouseClick; - public event MouseEventHandler MouseDoubleClick; - public event MouseEventHandler MouseDown; - public event MouseEventHandler MouseMove; - public event MouseEventHandler MouseUp; + ContextMenuStrip?.GetType().InvokeMember("ShowInTaskbar", + BindingFlags.NonPublic | BindingFlags.InvokeMethod | + BindingFlags.Instance, null, ContextMenuStrip, new object[] { p.X, p.Y }); + } - public string BalloonTipText { get; set; } - public ToolTipIcon BalloonTipIcon { get; set; } - public string BalloonTipTitle { get; set; } - public ContextMenuStrip ContextMenuStrip { get; set; } + private void UpdateNotifyIcon(bool showNotifyIcon) + { + if (DesignMode) + return; - public Icon Icon + lock (_syncObj) { - get + _window.LockReference(showNotifyIcon); + + NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData { CallbackMessage = WM_TRAYMOUSEMESSAGE, Flags = NativeMethods.NotifyIconDataFlags.Message }; + + if (showNotifyIcon && _window.Handle == IntPtr.Zero) + _window.CreateHandle(new CreateParams()); + + data.Window = _window.Handle; + data.ID = _id; + + if (_icon != null) { - return _icon; + data.Flags |= NativeMethods.NotifyIconDataFlags.Icon; + data.Icon = _icon.Handle; } - set + + data.Flags |= NativeMethods.NotifyIconDataFlags.Tip; + data.Tip = _text; + + if (showNotifyIcon && _icon != null) { - if (_icon != value) + if (!_created) { - _icon = value; - UpdateNotifyIcon(_visible); - } - } - } - - public string Text - { - get - { - return _text; - } - set - { - if (value == null) - value = ""; - - if (value.Length > 63) - throw new ArgumentOutOfRangeException(); - - if (!value.Equals(_text)) - { - _text = value; - if (_visible) - UpdateNotifyIcon(_visible); - } - } - } - - public bool Visible - { - get - { - return _visible; - } - set - { - if (_visible != value) - { - _visible = value; - UpdateNotifyIcon(_visible); - } - } - } - - public NotifyIconWindowsImplementation() - { - BalloonTipText = ""; - BalloonTipTitle = ""; - - _commandDispatch = typeof(Form).Assembly. - GetType("System.Windows.Forms.Command").GetMethod("DispatchID", - BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public, - null, new[] { typeof(int) }, null); - - _id = ++_nextId; - _window = new NotifyIconNativeWindow(this); - UpdateNotifyIcon(_visible); - } - - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (_window != null) - { - _icon = null; - _text = ""; - UpdateNotifyIcon(false); - _window.DestroyHandle(); - _window = null; - ContextMenuStrip = null; - } - } - else - { - if (_window != null && _window.Handle != IntPtr.Zero) - { - NativeMethods.PostMessage(new HandleRef(_window, _window.Handle), WM_CLOSE, 0, 0); - _window.ReleaseHandle(); - } - } - base.Dispose(disposing); - } - - public void ShowBalloonTip(int timeout) - { - ShowBalloonTip(timeout, BalloonTipTitle, BalloonTipText, BalloonTipIcon); - } - - public void ShowBalloonTip(int timeout, string tipTitle, string tipText, ToolTipIcon tipIcon) - { - if (timeout < 0) - throw new ArgumentOutOfRangeException(nameof(timeout)); - - if (string.IsNullOrEmpty(tipText)) - throw new ArgumentException("tipText"); - - if (DesignMode) - return; - - if (_created) - { - NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData(); - if (_window.Handle == IntPtr.Zero) - _window.CreateHandle(new CreateParams()); - - data.Window = _window.Handle; - data.ID = _id; - data.Flags = NativeMethods.NotifyIconDataFlags.Info; - data.TimeoutOrVersion = timeout; - data.InfoTitle = tipTitle; - data.Info = tipText; - data.InfoFlags = (int)tipIcon; - - NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Modify, data); - } - } - - private void ShowContextMenu() - { - if (ContextMenuStrip == null) - return; - - NativeMethods.Point p = new NativeMethods.Point(); - NativeMethods.GetCursorPos(ref p); - NativeMethods.SetForegroundWindow(new HandleRef(_window, _window.Handle)); - - ContextMenuStrip?.GetType().InvokeMember("ShowInTaskbar", - BindingFlags.NonPublic | BindingFlags.InvokeMethod | - BindingFlags.Instance, null, ContextMenuStrip, new object[] { p.X, p.Y }); - } - - private void UpdateNotifyIcon(bool showNotifyIcon) - { - if (DesignMode) - return; - - lock (_syncObj) - { - _window.LockReference(showNotifyIcon); - - NativeMethods.NotifyIconData data = new NativeMethods.NotifyIconData { CallbackMessage = WM_TRAYMOUSEMESSAGE, Flags = NativeMethods.NotifyIconDataFlags.Message }; - - if (showNotifyIcon && _window.Handle == IntPtr.Zero) - _window.CreateHandle(new CreateParams()); - - data.Window = _window.Handle; - data.ID = _id; - - if (_icon != null) - { - data.Flags |= NativeMethods.NotifyIconDataFlags.Icon; - data.Icon = _icon.Handle; - } - - data.Flags |= NativeMethods.NotifyIconDataFlags.Tip; - data.Tip = _text; - - if (showNotifyIcon && _icon != null) - { - if (!_created) + if (NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Modify, data)) { - if (NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Modify, data)) - { - _created = true; - } - else - { - int i = 0; - do - { - _created = NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Add, data); - if (!_created) - { - System.Threading.Thread.Sleep(200); - i++; - } - } while (!_created && i < 40); - } + _created = true; } else - { - NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Modify, data); - } - } - else - { - if (_created) { int i = 0; - bool deleted; do { - deleted = NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Delete, data); - if (!deleted) + _created = NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Add, data); + if (!_created) { System.Threading.Thread.Sleep(200); i++; } - } while (!deleted && i < 40); - _created = false; - } - } - } - } - - private void ProcessMouseDown(MouseButtons button, bool doubleClick) - { - if (doubleClick) - { - DoubleClick?.Invoke(this, new MouseEventArgs(button, 2, 0, 0, 0)); - MouseDoubleClick?.Invoke(this, new MouseEventArgs(button, 2, 0, 0, 0)); - - _doubleClickDown = true; - } - - MouseDown?.Invoke(this, new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0)); - } - - private void ProcessMouseUp(MouseButtons button) - { - MouseUp?.Invoke(this, new MouseEventArgs(button, 0, 0, 0, 0)); - - if (!_doubleClickDown) - { - Click?.Invoke(this, new MouseEventArgs(button, 0, 0, 0, 0)); - MouseClick?.Invoke(this, new MouseEventArgs(button, 0, 0, 0, 0)); - } - _doubleClickDown = false; - } - - private void ProcessInitMenuPopup(ref Message message) - { - _window.DefWndProc(ref message); - } - - private void WndProc(ref Message message) - { - switch (message.Msg) - { - case WM_DESTROY: - UpdateNotifyIcon(false); - return; - case WM_COMMAND: - if (message.LParam != IntPtr.Zero) - { - _window.DefWndProc(ref message); - return; - } - _commandDispatch.Invoke(null, new object[] { message.WParam.ToInt32() & 0xFFFF }); - return; - case WM_INITMENUPOPUP: - ProcessInitMenuPopup(ref message); - return; - case WM_TRAYMOUSEMESSAGE: - switch ((int)message.LParam) - { - case WM_MOUSEMOVE: - MouseMove?.Invoke(this, - new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0)); - return; - case WM_LBUTTONDOWN: - ProcessMouseDown(MouseButtons.Left, false); - return; - case WM_LBUTTONUP: - ProcessMouseUp(MouseButtons.Left); - return; - case WM_LBUTTONDBLCLK: - ProcessMouseDown(MouseButtons.Left, true); - return; - case WM_RBUTTONDOWN: - ProcessMouseDown(MouseButtons.Right, false); - return; - case WM_RBUTTONUP: - if (ContextMenuStrip != null) - ShowContextMenu(); - ProcessMouseUp(MouseButtons.Right); - return; - case WM_RBUTTONDBLCLK: - ProcessMouseDown(MouseButtons.Right, true); - return; - case WM_MBUTTONDOWN: - ProcessMouseDown(MouseButtons.Middle, false); - return; - case WM_MBUTTONUP: - ProcessMouseUp(MouseButtons.Middle); - return; - case WM_MBUTTONDBLCLK: - ProcessMouseDown(MouseButtons.Middle, true); - return; - case NIN_BALLOONSHOW: - BalloonTipShown?.Invoke(this, EventArgs.Empty); - return; - case NIN_BALLOONHIDE: - case NIN_BALLOONTIMEOUT: - BalloonTipClosed?.Invoke(this, EventArgs.Empty); - return; - case NIN_BALLOONUSERCLICK: - BalloonTipClicked?.Invoke(this, EventArgs.Empty); - return; - default: - return; - } - } - - if (message.Msg == _wmTaskBarCreated) - { - lock (_syncObj) - { - _created = false; - } - UpdateNotifyIcon(_visible); - } - - _window.DefWndProc(ref message); - } - - private class NotifyIconNativeWindow : NativeWindow - { - private readonly NotifyIconWindowsImplementation _reference; - private GCHandle _referenceHandle; - - internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) - { - _reference = component; - } - - ~NotifyIconNativeWindow() - { - if (Handle != IntPtr.Zero) - NativeMethods.PostMessage(new HandleRef(this, Handle), WM_CLOSE, 0, 0); - } - - public void LockReference(bool locked) - { - if (locked) - { - if (!_referenceHandle.IsAllocated) - { - _referenceHandle = GCHandle.Alloc(_reference, GCHandleType.Normal); + } while (!_created && i < 40); } } else { - if (_referenceHandle.IsAllocated) - _referenceHandle.Free(); + NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Modify, data); } } - - protected override void OnThreadException(Exception e) + else { - Application.OnThreadException(e); + if (_created) + { + int i = 0; + bool deleted; + do + { + deleted = NativeMethods.Shell_NotifyIcon(NativeMethods.NotifyIconMessage.Delete, data); + if (!deleted) + { + System.Threading.Thread.Sleep(200); + i++; + } + } while (!deleted && i < 40); + _created = false; + } } - - protected override void WndProc(ref Message m) - { - _reference.WndProc(ref m); - } - } - - private const int WM_NULL = 0x00; - private const int WM_DESTROY = 0x02; - private const int WM_CLOSE = 0x10; - private const int WM_COMMAND = 0x111; - private const int WM_INITMENUPOPUP = 0x117; - private const int WM_MOUSEMOVE = 0x200; - private const int WM_LBUTTONDOWN = 0x201; - private const int WM_LBUTTONUP = 0x202; - private const int WM_LBUTTONDBLCLK = 0x203; - private const int WM_RBUTTONDOWN = 0x204; - private const int WM_RBUTTONUP = 0x205; - private const int WM_RBUTTONDBLCLK = 0x206; - private const int WM_MBUTTONDOWN = 0x207; - private const int WM_MBUTTONUP = 0x208; - private const int WM_MBUTTONDBLCLK = 0x209; - private const int WM_TRAYMOUSEMESSAGE = 0x800; - - private const int NIN_BALLOONSHOW = 0x402; - private const int NIN_BALLOONHIDE = 0x403; - private const int NIN_BALLOONTIMEOUT = 0x404; - private const int NIN_BALLOONUSERCLICK = 0x405; - - private static readonly int _wmTaskBarCreated = NativeMethods.RegisterWindowMessage("TaskbarCreated"); - - private static class NativeMethods - { - private const string DllNameUser32 = "user32.dll"; - private const string DllNameShell32 = "shell32.dll"; - - [DllImport(DllNameUser32, CharSet = CharSet.Auto)] - public static extern IntPtr PostMessage(HandleRef hwnd, int msg, int wparam, int lparam); - - [DllImport(DllNameUser32, CharSet = CharSet.Auto)] - public static extern int RegisterWindowMessage(string msg); - - [Flags] - public enum NotifyIconDataFlags : int - { - Message = 0x1, - Icon = 0x2, - Tip = 0x4, - State = 0x8, - Info = 0x10 - } - - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] - public class NotifyIconData - { - private int _size = Marshal.SizeOf(typeof(NotifyIconData)); - public IntPtr Window; - public int ID; - public NotifyIconDataFlags Flags; - public int CallbackMessage; - public IntPtr Icon; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] - public string Tip; - public int State; - public int StateMask; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] - public string Info; - public int TimeoutOrVersion; - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] - public string InfoTitle; - public int InfoFlags; - } - - public enum NotifyIconMessage : int - { - Add = 0x0, - Modify = 0x1, - Delete = 0x2 - } - - [DllImport(DllNameShell32, CharSet = CharSet.Auto)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool Shell_NotifyIcon(NotifyIconMessage message, NotifyIconData pnid); - - [DllImport(DllNameUser32, CharSet = CharSet.Auto, ExactSpelling = true)] - public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags, int x, int y, HandleRef hwnd, IntPtr tpm); - - [StructLayout(LayoutKind.Sequential)] - public struct Point - { - public readonly int X; - public readonly int Y; - } - - [DllImport(DllNameUser32, CharSet = CharSet.Auto, ExactSpelling = true)] - public static extern bool GetCursorPos(ref Point point); - - [DllImport(DllNameUser32, CharSet = CharSet.Auto, ExactSpelling = true)] - public static extern bool SetForegroundWindow(HandleRef hWnd); } } + + private void ProcessMouseDown(MouseButtons button, bool doubleClick) + { + if (doubleClick) + { + DoubleClick?.Invoke(this, new MouseEventArgs(button, 2, 0, 0, 0)); + MouseDoubleClick?.Invoke(this, new MouseEventArgs(button, 2, 0, 0, 0)); + + _doubleClickDown = true; + } + + MouseDown?.Invoke(this, new MouseEventArgs(button, doubleClick ? 2 : 1, 0, 0, 0)); + } + + private void ProcessMouseUp(MouseButtons button) + { + MouseUp?.Invoke(this, new MouseEventArgs(button, 0, 0, 0, 0)); + + if (!_doubleClickDown) + { + Click?.Invoke(this, new MouseEventArgs(button, 0, 0, 0, 0)); + MouseClick?.Invoke(this, new MouseEventArgs(button, 0, 0, 0, 0)); + } + _doubleClickDown = false; + } + + private void ProcessInitMenuPopup(ref Message message) + { + _window.DefWndProc(ref message); + } + + private void WndProc(ref Message message) + { + switch (message.Msg) + { + case WM_DESTROY: + UpdateNotifyIcon(false); + return; + case WM_COMMAND: + if (message.LParam != IntPtr.Zero) + { + _window.DefWndProc(ref message); + return; + } + _commandDispatch.Invoke(null, new object[] { message.WParam.ToInt32() & 0xFFFF }); + return; + case WM_INITMENUPOPUP: + ProcessInitMenuPopup(ref message); + return; + case WM_TRAYMOUSEMESSAGE: + switch ((int)message.LParam) + { + case WM_MOUSEMOVE: + MouseMove?.Invoke(this, + new MouseEventArgs(Control.MouseButtons, 0, 0, 0, 0)); + return; + case WM_LBUTTONDOWN: + ProcessMouseDown(MouseButtons.Left, false); + return; + case WM_LBUTTONUP: + ProcessMouseUp(MouseButtons.Left); + return; + case WM_LBUTTONDBLCLK: + ProcessMouseDown(MouseButtons.Left, true); + return; + case WM_RBUTTONDOWN: + ProcessMouseDown(MouseButtons.Right, false); + return; + case WM_RBUTTONUP: + if (ContextMenuStrip != null) + ShowContextMenu(); + ProcessMouseUp(MouseButtons.Right); + return; + case WM_RBUTTONDBLCLK: + ProcessMouseDown(MouseButtons.Right, true); + return; + case WM_MBUTTONDOWN: + ProcessMouseDown(MouseButtons.Middle, false); + return; + case WM_MBUTTONUP: + ProcessMouseUp(MouseButtons.Middle); + return; + case WM_MBUTTONDBLCLK: + ProcessMouseDown(MouseButtons.Middle, true); + return; + case NIN_BALLOONSHOW: + BalloonTipShown?.Invoke(this, EventArgs.Empty); + return; + case NIN_BALLOONHIDE: + case NIN_BALLOONTIMEOUT: + BalloonTipClosed?.Invoke(this, EventArgs.Empty); + return; + case NIN_BALLOONUSERCLICK: + BalloonTipClicked?.Invoke(this, EventArgs.Empty); + return; + default: + return; + } + } + + if (message.Msg == _wmTaskBarCreated) + { + lock (_syncObj) + { + _created = false; + } + UpdateNotifyIcon(_visible); + } + + _window.DefWndProc(ref message); + } + + private class NotifyIconNativeWindow : NativeWindow + { + private readonly NotifyIconWindowsImplementation _reference; + private GCHandle _referenceHandle; + + internal NotifyIconNativeWindow(NotifyIconWindowsImplementation component) + { + _reference = component; + } + + ~NotifyIconNativeWindow() + { + if (Handle != IntPtr.Zero) + NativeMethods.PostMessage(new HandleRef(this, Handle), WM_CLOSE, 0, 0); + } + + public void LockReference(bool locked) + { + if (locked) + { + if (!_referenceHandle.IsAllocated) + { + _referenceHandle = GCHandle.Alloc(_reference, GCHandleType.Normal); + } + } + else + { + if (_referenceHandle.IsAllocated) + _referenceHandle.Free(); + } + } + + protected override void OnThreadException(Exception e) + { + Application.OnThreadException(e); + } + + protected override void WndProc(ref Message m) + { + _reference.WndProc(ref m); + } + } + + private const int WM_NULL = 0x00; + private const int WM_DESTROY = 0x02; + private const int WM_CLOSE = 0x10; + private const int WM_COMMAND = 0x111; + private const int WM_INITMENUPOPUP = 0x117; + private const int WM_MOUSEMOVE = 0x200; + private const int WM_LBUTTONDOWN = 0x201; + private const int WM_LBUTTONUP = 0x202; + private const int WM_LBUTTONDBLCLK = 0x203; + private const int WM_RBUTTONDOWN = 0x204; + private const int WM_RBUTTONUP = 0x205; + private const int WM_RBUTTONDBLCLK = 0x206; + private const int WM_MBUTTONDOWN = 0x207; + private const int WM_MBUTTONUP = 0x208; + private const int WM_MBUTTONDBLCLK = 0x209; + private const int WM_TRAYMOUSEMESSAGE = 0x800; + + private const int NIN_BALLOONSHOW = 0x402; + private const int NIN_BALLOONHIDE = 0x403; + private const int NIN_BALLOONTIMEOUT = 0x404; + private const int NIN_BALLOONUSERCLICK = 0x405; + + private static readonly int _wmTaskBarCreated = NativeMethods.RegisterWindowMessage("TaskbarCreated"); + + private static class NativeMethods + { + private const string DllNameUser32 = "user32.dll"; + private const string DllNameShell32 = "shell32.dll"; + + [DllImport(DllNameUser32, CharSet = CharSet.Auto)] + public static extern IntPtr PostMessage(HandleRef hwnd, int msg, int wparam, int lparam); + + [DllImport(DllNameUser32, CharSet = CharSet.Auto)] + public static extern int RegisterWindowMessage(string msg); + + [Flags] + public enum NotifyIconDataFlags : int + { + Message = 0x1, + Icon = 0x2, + Tip = 0x4, + State = 0x8, + Info = 0x10 + } + + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] + public class NotifyIconData + { + private int _size = Marshal.SizeOf(typeof(NotifyIconData)); + public IntPtr Window; + public int ID; + public NotifyIconDataFlags Flags; + public int CallbackMessage; + public IntPtr Icon; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)] + public string Tip; + public int State; + public int StateMask; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string Info; + public int TimeoutOrVersion; + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string InfoTitle; + public int InfoFlags; + } + + public enum NotifyIconMessage : int + { + Add = 0x0, + Modify = 0x1, + Delete = 0x2 + } + + [DllImport(DllNameShell32, CharSet = CharSet.Auto)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool Shell_NotifyIcon(NotifyIconMessage message, NotifyIconData pnid); + + [DllImport(DllNameUser32, CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern bool TrackPopupMenuEx(HandleRef hmenu, int fuFlags, int x, int y, HandleRef hwnd, IntPtr tpm); + + [StructLayout(LayoutKind.Sequential)] + public struct Point + { + public readonly int X; + public readonly int Y; + } + + [DllImport(DllNameUser32, CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern bool GetCursorPos(ref Point point); + + [DllImport(DllNameUser32, CharSet = CharSet.Auto, ExactSpelling = true)] + public static extern bool SetForegroundWindow(HandleRef hWnd); + } } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/ParameterForm.cs b/LibreHardwareMonitor/UI/ParameterForm.cs index 0a7c79b..ee8f867 100644 --- a/LibreHardwareMonitor/UI/ParameterForm.cs +++ b/LibreHardwareMonitor/UI/ParameterForm.cs @@ -10,127 +10,126 @@ using System.ComponentModel; using System.Windows.Forms; using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public partial class ParameterForm : Form { - public partial class ParameterForm : Form + private IReadOnlyList _parameters; + private BindingList _parameterRows; + + public ParameterForm() { - private IReadOnlyList _parameters; - private BindingList _parameterRows; + InitializeComponent(); + } - public ParameterForm() + public IReadOnlyList Parameters + { + get { - InitializeComponent(); + return _parameters; } - - public IReadOnlyList Parameters + set { - get + _parameters = value; + _parameterRows = new BindingList(); + + foreach (IParameter parameter in _parameters) { - return _parameters; - } - set - { - _parameters = value; - _parameterRows = new BindingList(); - - foreach (IParameter parameter in _parameters) - { - _parameterRows.Add(new ParameterRow(parameter)); - } - - bindingSource.DataSource = _parameterRows; - } - } - - private class ParameterRow : INotifyPropertyChanged - { - public readonly IParameter Parameter; - private float _value = float.NaN; - private bool _default = true; - - public event PropertyChangedEventHandler PropertyChanged; - - private void NotifyPropertyChanged(String propertyName) - { - if (PropertyChanged != null) - PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + _parameterRows.Add(new ParameterRow(parameter)); } - public ParameterRow(IParameter parameter) - { - Parameter = parameter; - Value = parameter.Value; - Default = parameter.IsDefault; - } - - public string Name - { - get { return Parameter.Name; } - } - - public float Value - { - get { return _value; } - set - { - _default = false; - _value = value; - NotifyPropertyChanged(nameof(Default)); - NotifyPropertyChanged(nameof(Value)); - } - } - - public bool Default - { - get { return _default; } - set - { - _default = value; - if (_default) - _value = Parameter.DefaultValue; - NotifyPropertyChanged(nameof(Default)); - NotifyPropertyChanged(nameof(Value)); - } - } - } - - private void DataGridView_RowEnter(object sender, DataGridViewCellEventArgs e) - { - if (e.RowIndex >= 0 && e.RowIndex < _parameters.Count) - descriptionLabel.Text = _parameters[e.RowIndex].Description; - else - descriptionLabel.Text = string.Empty; - } - - private void DataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) - { - if (e.ColumnIndex == 2 && !float.TryParse(e.FormattedValue.ToString(), out float _)) - { - dataGridView.Rows[e.RowIndex].Cells[0].ErrorText = "Invalid value"; - e.Cancel = true; - } - } - - private void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) - { - dataGridView.Rows[e.RowIndex].Cells[0].ErrorText = string.Empty; - } - - private void OkButton_Click(object sender, EventArgs e) - { - foreach (ParameterRow row in _parameterRows) - { - if (row.Default) - row.Parameter.IsDefault = true; - else - row.Parameter.Value = row.Value; - } - } - - private void DataGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e) - { - if (dataGridView.CurrentCell is DataGridViewCheckBoxCell || dataGridView.CurrentCell is DataGridViewComboBoxCell) - dataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit); + bindingSource.DataSource = _parameterRows; } } -} + + private class ParameterRow : INotifyPropertyChanged + { + public readonly IParameter Parameter; + private float _value = float.NaN; + private bool _default = true; + + public event PropertyChangedEventHandler PropertyChanged; + + private void NotifyPropertyChanged(String propertyName) + { + if (PropertyChanged != null) + PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); + } + + public ParameterRow(IParameter parameter) + { + Parameter = parameter; + Value = parameter.Value; + Default = parameter.IsDefault; + } + + public string Name + { + get { return Parameter.Name; } + } + + public float Value + { + get { return _value; } + set + { + _default = false; + _value = value; + NotifyPropertyChanged(nameof(Default)); + NotifyPropertyChanged(nameof(Value)); + } + } + + public bool Default + { + get { return _default; } + set + { + _default = value; + if (_default) + _value = Parameter.DefaultValue; + NotifyPropertyChanged(nameof(Default)); + NotifyPropertyChanged(nameof(Value)); + } + } + } + + private void DataGridView_RowEnter(object sender, DataGridViewCellEventArgs e) + { + if (e.RowIndex >= 0 && e.RowIndex < _parameters.Count) + descriptionLabel.Text = _parameters[e.RowIndex].Description; + else + descriptionLabel.Text = string.Empty; + } + + private void DataGridView_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) + { + if (e.ColumnIndex == 2 && !float.TryParse(e.FormattedValue.ToString(), out float _)) + { + dataGridView.Rows[e.RowIndex].Cells[0].ErrorText = "Invalid value"; + e.Cancel = true; + } + } + + private void DataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e) + { + dataGridView.Rows[e.RowIndex].Cells[0].ErrorText = string.Empty; + } + + private void OkButton_Click(object sender, EventArgs e) + { + foreach (ParameterRow row in _parameterRows) + { + if (row.Default) + row.Parameter.IsDefault = true; + else + row.Parameter.Value = row.Value; + } + } + + private void DataGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e) + { + if (dataGridView.CurrentCell is DataGridViewCheckBoxCell || dataGridView.CurrentCell is DataGridViewComboBoxCell) + dataGridView.CommitEdit(DataGridViewDataErrorContexts.Commit); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/PlotPanel.cs b/LibreHardwareMonitor/UI/PlotPanel.cs index 5f35386..a509df4 100644 --- a/LibreHardwareMonitor/UI/PlotPanel.cs +++ b/LibreHardwareMonitor/UI/PlotPanel.cs @@ -17,403 +17,402 @@ using OxyPlot.Axes; using OxyPlot.WindowsForms; using OxyPlot.Series; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class PlotPanel : UserControl { - public class PlotPanel : UserControl + private readonly PersistentSettings _settings; + private readonly UnitManager _unitManager; + private readonly PlotView _plot; + private readonly PlotModel _model; + private readonly TimeSpanAxis _timeAxis = new TimeSpanAxis(); + private readonly SortedDictionary _axes = new SortedDictionary(); + private readonly Dictionary _annotations = new Dictionary(); + private UserOption _stackedAxes; + private UserOption _showAxesLabels; + private UserOption _timeAxisEnableZoom; + private UserOption _yAxesEnableZoom; + private DateTime _now; + private float _dpiX; + private float _dpiY; + private double _dpiXScale = 1; + private double _dpiYScale = 1; + private Point _rightClickEnter; + private bool _cancelContextMenu = false; + + public PlotPanel(PersistentSettings settings, UnitManager unitManager) { - private readonly PersistentSettings _settings; - private readonly UnitManager _unitManager; - private readonly PlotView _plot; - private readonly PlotModel _model; - private readonly TimeSpanAxis _timeAxis = new TimeSpanAxis(); - private readonly SortedDictionary _axes = new SortedDictionary(); - private readonly Dictionary _annotations = new Dictionary(); - private UserOption _stackedAxes; - private UserOption _showAxesLabels; - private UserOption _timeAxisEnableZoom; - private UserOption _yAxesEnableZoom; - private DateTime _now; - private float _dpiX; - private float _dpiY; - private double _dpiXScale = 1; - private double _dpiYScale = 1; - private Point _rightClickEnter; - private bool _cancelContextMenu = false; + _settings = settings; + _unitManager = unitManager; - public PlotPanel(PersistentSettings settings, UnitManager unitManager) + SetDpi(); + _model = CreatePlotModel(); + + _plot = new PlotView { Dock = DockStyle.Fill, Model = _model, BackColor = Color.White, ContextMenuStrip = CreateMenu() }; + _plot.MouseDown += (sender, e) => { - _settings = settings; - _unitManager = unitManager; - - SetDpi(); - _model = CreatePlotModel(); - - _plot = new PlotView { Dock = DockStyle.Fill, Model = _model, BackColor = Color.White, ContextMenuStrip = CreateMenu() }; - _plot.MouseDown += (sender, e) => + if (e.Button == MouseButtons.Right) { - if (e.Button == MouseButtons.Right) - { - _rightClickEnter = e.Location; - } - }; - _plot.MouseMove += (sender, e) => + _rightClickEnter = e.Location; + } + }; + _plot.MouseMove += (sender, e) => + { + if (e.Button == MouseButtons.Right) { - if (e.Button == MouseButtons.Right) + if (!_cancelContextMenu && e.Location.DistanceTo(_rightClickEnter) > 10.0f) { - if (!_cancelContextMenu && e.Location.DistanceTo(_rightClickEnter) > 10.0f) - { - _cancelContextMenu = true; - } + _cancelContextMenu = true; } - }; + } + }; + UpdateAxesPosition(); + + SuspendLayout(); + Controls.Add(_plot); + ResumeLayout(true); + } + + public void SetCurrentSettings() + { + foreach (LinearAxis axis in _axes.Values) + { + _settings.SetValue("plotPanel.Min" + axis.Key, (float)axis.ActualMinimum); + _settings.SetValue("plotPanel.Max" + axis.Key, (float)axis.ActualMaximum); + } + _settings.SetValue("plotPanel.MinTimeSpan", (float)_timeAxis.ActualMinimum); + _settings.SetValue("plotPanel.MaxTimeSpan", (float)_timeAxis.ActualMaximum); + } + + private ContextMenuStrip CreateMenu() + { + ContextMenuStrip menu = new ContextMenuStrip(); + menu.Opening += (sender, e) => + { + if (_cancelContextMenu) + { + e.Cancel = true; + _cancelContextMenu = false; + } + }; + + ToolStripMenuItem stackedAxesMenuItem = new ToolStripMenuItem("Stacked Axes"); + _stackedAxes = new UserOption("stackedAxes", true, stackedAxesMenuItem, _settings); + _stackedAxes.Changed += (sender, e) => + { UpdateAxesPosition(); + InvalidatePlot(); + }; + menu.Items.Add(stackedAxesMenuItem); - SuspendLayout(); - Controls.Add(_plot); - ResumeLayout(true); - } + ToolStripMenuItem showAxesLabelsMenuItem = new ToolStripMenuItem("Show Axes Labels"); + _showAxesLabels = new UserOption("showAxesLabels", true, showAxesLabelsMenuItem, _settings); + _showAxesLabels.Changed += (sender, e) => + { + if (_showAxesLabels.Value) + _model.PlotMargins = new OxyThickness(double.NaN); + else + _model.PlotMargins = new OxyThickness(0); + }; + menu.Items.Add(showAxesLabelsMenuItem); - public void SetCurrentSettings() + ToolStripMenuItem timeAxisMenuItem = new ToolStripMenuItem("Time Axis"); + ToolStripMenuItem[] timeAxisMenuItems = + { new ToolStripMenuItem("Enable Zoom"), + new ToolStripMenuItem("Auto", null, (s, e) => { TimeAxisZoom(0, double.NaN); }), + new ToolStripMenuItem("5 min", null, (s, e) => { TimeAxisZoom(0, 5 * 60); }), + new ToolStripMenuItem("10 min", null, (s, e) => { TimeAxisZoom(0, 10 * 60); }), + new ToolStripMenuItem("20 min", null, (s, e) => { TimeAxisZoom(0, 20 * 60); }), + new ToolStripMenuItem("30 min", null, (s, e) => { TimeAxisZoom(0, 30 * 60); }), + new ToolStripMenuItem("45 min", null, (s, e) => { TimeAxisZoom(0, 45 * 60); }), + new ToolStripMenuItem("1 h", null, (s, e) => { TimeAxisZoom(0, 60 * 60); }), + new ToolStripMenuItem("1.5 h", null, (s, e) => { TimeAxisZoom(0, 1.5 * 60 * 60); }), + new ToolStripMenuItem("2 h", null, (s, e) => { TimeAxisZoom(0, 2 * 60 * 60); }), + new ToolStripMenuItem("3 h", null, (s, e) => { TimeAxisZoom(0, 3 * 60 * 60); }), + new ToolStripMenuItem("6 h", null, (s, e) => { TimeAxisZoom(0, 6 * 60 * 60); }), + new ToolStripMenuItem("12 h", null, (s, e) => { TimeAxisZoom(0, 12 * 60 * 60); }), + new ToolStripMenuItem("24 h", null, (s, e) => { TimeAxisZoom(0, 24 * 60 * 60); }) }; + + foreach (ToolStripItem mi in timeAxisMenuItems) + timeAxisMenuItem.DropDownItems.Add(mi); + menu.Items.Add(timeAxisMenuItem); + + _timeAxisEnableZoom = new UserOption("timeAxisEnableZoom", true, timeAxisMenuItems[0], _settings); + _timeAxisEnableZoom.Changed += (sender, e) => + { + _timeAxis.IsZoomEnabled = _timeAxisEnableZoom.Value; + }; + + ToolStripMenuItem yAxesMenuItem = new ToolStripMenuItem("Value Axes"); + ToolStripMenuItem[] yAxesMenuItems = + { new ToolStripMenuItem("Enable Zoom"), + new ToolStripMenuItem("Autoscale All", null, (s, e) => { AutoscaleAllYAxes(); }) }; + + foreach (ToolStripItem mi in yAxesMenuItems) + yAxesMenuItem.DropDownItems.Add(mi); + menu.Items.Add(yAxesMenuItem); + + _yAxesEnableZoom = new UserOption("yAxesEnableZoom", true, yAxesMenuItems[0], _settings); + _yAxesEnableZoom.Changed += (sender, e) => { foreach (LinearAxis axis in _axes.Values) + axis.IsZoomEnabled = _yAxesEnableZoom.Value; + }; + + return menu; + } + + private PlotModel CreatePlotModel() + { + _timeAxis.Position = AxisPosition.Bottom; + _timeAxis.MajorGridlineStyle = LineStyle.Solid; + _timeAxis.MajorGridlineThickness = 1; + _timeAxis.MajorGridlineColor = OxyColor.FromRgb(192, 192, 192); + _timeAxis.MinorGridlineStyle = LineStyle.Solid; + _timeAxis.MinorGridlineThickness = 1; + _timeAxis.MinorGridlineColor = OxyColor.FromRgb(232, 232, 232); + _timeAxis.StartPosition = 1; + _timeAxis.EndPosition = 0; + _timeAxis.MinimumPadding = 0; + _timeAxis.MaximumPadding = 0; + _timeAxis.AbsoluteMinimum = 0; + _timeAxis.Minimum = 0; + _timeAxis.AbsoluteMaximum = 24 * 60 * 60; + _timeAxis.Zoom( + _settings.GetValue("plotPanel.MinTimeSpan", 0.0f), + _settings.GetValue("plotPanel.MaxTimeSpan", 10.0f * 60)); + _timeAxis.StringFormat = "h:mm"; + + var units = new Dictionary + { + { SensorType.Voltage, "V" }, + { SensorType.Current, "A" }, + { SensorType.Clock, "MHz" }, + { SensorType.Temperature, "°C" }, + { SensorType.Load, "%" }, + { SensorType.Fan, "RPM" }, + { SensorType.Flow, "L/h" }, + { SensorType.Control, "%" }, + { SensorType.Level, "%" }, + { SensorType.Factor, "1" }, + { SensorType.Power, "W" }, + { SensorType.Data, "GB" }, + { SensorType.Frequency, "Hz" }, + { SensorType.Energy, "mWh" }, + { SensorType.Noise, "dBA" } + }; + + foreach (SensorType type in Enum.GetValues(typeof(SensorType))) + { + string typeName = type.ToString(); + var axis = new LinearAxis { - _settings.SetValue("plotPanel.Min" + axis.Key, (float)axis.ActualMinimum); - _settings.SetValue("plotPanel.Max" + axis.Key, (float)axis.ActualMaximum); - } - _settings.SetValue("plotPanel.MinTimeSpan", (float)_timeAxis.ActualMinimum); - _settings.SetValue("plotPanel.MaxTimeSpan", (float)_timeAxis.ActualMaximum); + Position = AxisPosition.Left, + MajorGridlineStyle = LineStyle.Solid, + MajorGridlineThickness = 1, + MajorGridlineColor = _timeAxis.MajorGridlineColor, + MinorGridlineStyle = LineStyle.Solid, + MinorGridlineThickness = 1, + MinorGridlineColor = _timeAxis.MinorGridlineColor, + AxislineStyle = LineStyle.Solid, + Title = typeName, + Key = typeName, + }; + + var annotation = new LineAnnotation + { + Type = LineAnnotationType.Horizontal, + ClipByXAxis = false, + ClipByYAxis = false, + LineStyle = LineStyle.Solid, + Color = OxyColors.Black, + YAxisKey = typeName, + StrokeThickness = 2, + }; + + axis.AxisChanged += (sender, args) => annotation.Y = axis.ActualMinimum; + axis.TransformChanged += (sender, args) => annotation.Y = axis.ActualMinimum; + + axis.Zoom(_settings.GetValue("plotPanel.Min" + axis.Key, float.NaN), _settings.GetValue("plotPanel.Max" + axis.Key, float.NaN)); + + if (units.ContainsKey(type)) + axis.Unit = units[type]; + + _axes.Add(type, axis); + _annotations.Add(type, annotation); } - private ContextMenuStrip CreateMenu() + var model = new ScaledPlotModel(_dpiXScale, _dpiYScale); + model.Axes.Add(_timeAxis); + foreach (LinearAxis axis in _axes.Values) + model.Axes.Add(axis); + model.IsLegendVisible = false; + + return model; + } + + private void SetDpi() + { + // https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx + const int defaultDpi = 96; + Graphics g = CreateGraphics(); + + try { - ContextMenuStrip menu = new ContextMenuStrip(); - menu.Opening += (sender, e) => - { - if (_cancelContextMenu) - { - e.Cancel = true; - _cancelContextMenu = false; - } - }; - - ToolStripMenuItem stackedAxesMenuItem = new ToolStripMenuItem("Stacked Axes"); - _stackedAxes = new UserOption("stackedAxes", true, stackedAxesMenuItem, _settings); - _stackedAxes.Changed += (sender, e) => - { - UpdateAxesPosition(); - InvalidatePlot(); - }; - menu.Items.Add(stackedAxesMenuItem); - - ToolStripMenuItem showAxesLabelsMenuItem = new ToolStripMenuItem("Show Axes Labels"); - _showAxesLabels = new UserOption("showAxesLabels", true, showAxesLabelsMenuItem, _settings); - _showAxesLabels.Changed += (sender, e) => - { - if (_showAxesLabels.Value) - _model.PlotMargins = new OxyThickness(double.NaN); - else - _model.PlotMargins = new OxyThickness(0); - }; - menu.Items.Add(showAxesLabelsMenuItem); - - ToolStripMenuItem timeAxisMenuItem = new ToolStripMenuItem("Time Axis"); - ToolStripMenuItem[] timeAxisMenuItems = - { new ToolStripMenuItem("Enable Zoom"), - new ToolStripMenuItem("Auto", null, (s, e) => { TimeAxisZoom(0, double.NaN); }), - new ToolStripMenuItem("5 min", null, (s, e) => { TimeAxisZoom(0, 5 * 60); }), - new ToolStripMenuItem("10 min", null, (s, e) => { TimeAxisZoom(0, 10 * 60); }), - new ToolStripMenuItem("20 min", null, (s, e) => { TimeAxisZoom(0, 20 * 60); }), - new ToolStripMenuItem("30 min", null, (s, e) => { TimeAxisZoom(0, 30 * 60); }), - new ToolStripMenuItem("45 min", null, (s, e) => { TimeAxisZoom(0, 45 * 60); }), - new ToolStripMenuItem("1 h", null, (s, e) => { TimeAxisZoom(0, 60 * 60); }), - new ToolStripMenuItem("1.5 h", null, (s, e) => { TimeAxisZoom(0, 1.5 * 60 * 60); }), - new ToolStripMenuItem("2 h", null, (s, e) => { TimeAxisZoom(0, 2 * 60 * 60); }), - new ToolStripMenuItem("3 h", null, (s, e) => { TimeAxisZoom(0, 3 * 60 * 60); }), - new ToolStripMenuItem("6 h", null, (s, e) => { TimeAxisZoom(0, 6 * 60 * 60); }), - new ToolStripMenuItem("12 h", null, (s, e) => { TimeAxisZoom(0, 12 * 60 * 60); }), - new ToolStripMenuItem("24 h", null, (s, e) => { TimeAxisZoom(0, 24 * 60 * 60); }) }; - - foreach (ToolStripItem mi in timeAxisMenuItems) - timeAxisMenuItem.DropDownItems.Add(mi); - menu.Items.Add(timeAxisMenuItem); - - _timeAxisEnableZoom = new UserOption("timeAxisEnableZoom", true, timeAxisMenuItems[0], _settings); - _timeAxisEnableZoom.Changed += (sender, e) => - { - _timeAxis.IsZoomEnabled = _timeAxisEnableZoom.Value; - }; - - ToolStripMenuItem yAxesMenuItem = new ToolStripMenuItem("Value Axes"); - ToolStripMenuItem[] yAxesMenuItems = - { new ToolStripMenuItem("Enable Zoom"), - new ToolStripMenuItem("Autoscale All", null, (s, e) => { AutoscaleAllYAxes(); }) }; - - foreach (ToolStripItem mi in yAxesMenuItems) - yAxesMenuItem.DropDownItems.Add(mi); - menu.Items.Add(yAxesMenuItem); - - _yAxesEnableZoom = new UserOption("yAxesEnableZoom", true, yAxesMenuItems[0], _settings); - _yAxesEnableZoom.Changed += (sender, e) => - { - foreach (LinearAxis axis in _axes.Values) - axis.IsZoomEnabled = _yAxesEnableZoom.Value; - }; - - return menu; + _dpiX = g.DpiX; + _dpiY = g.DpiY; + } + finally + { + g.Dispose(); } - private PlotModel CreatePlotModel() - { - _timeAxis.Position = AxisPosition.Bottom; - _timeAxis.MajorGridlineStyle = LineStyle.Solid; - _timeAxis.MajorGridlineThickness = 1; - _timeAxis.MajorGridlineColor = OxyColor.FromRgb(192, 192, 192); - _timeAxis.MinorGridlineStyle = LineStyle.Solid; - _timeAxis.MinorGridlineThickness = 1; - _timeAxis.MinorGridlineColor = OxyColor.FromRgb(232, 232, 232); - _timeAxis.StartPosition = 1; - _timeAxis.EndPosition = 0; - _timeAxis.MinimumPadding = 0; - _timeAxis.MaximumPadding = 0; - _timeAxis.AbsoluteMinimum = 0; - _timeAxis.Minimum = 0; - _timeAxis.AbsoluteMaximum = 24 * 60 * 60; - _timeAxis.Zoom( - _settings.GetValue("plotPanel.MinTimeSpan", 0.0f), - _settings.GetValue("plotPanel.MaxTimeSpan", 10.0f * 60)); - _timeAxis.StringFormat = "h:mm"; + if (_dpiX > 0) + _dpiXScale = _dpiX / defaultDpi; + if (_dpiY > 0) + _dpiYScale = _dpiY / defaultDpi; + } - var units = new Dictionary + public void SetSensors(List sensors, IDictionary colors) + { + _model.Series.Clear(); + var types = new HashSet(); + + + DataPoint CreateDataPoint(SensorType type, SensorValue value) + { + float displayedValue; + + if (type == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) { - { SensorType.Voltage, "V" }, - { SensorType.Current, "A" }, - { SensorType.Clock, "MHz" }, - { SensorType.Temperature, "°C" }, - { SensorType.Load, "%" }, - { SensorType.Fan, "RPM" }, - { SensorType.Flow, "L/h" }, - { SensorType.Control, "%" }, - { SensorType.Level, "%" }, - { SensorType.Factor, "1" }, - { SensorType.Power, "W" }, - { SensorType.Data, "GB" }, - { SensorType.Frequency, "Hz" }, - { SensorType.Energy, "mWh" }, - { SensorType.Noise, "dBA" } + displayedValue = UnitManager.CelsiusToFahrenheit(value.Value).Value; + } + else + { + displayedValue = value.Value; + } + + return new DataPoint((_now - value.Time).TotalSeconds, displayedValue); + } + + + foreach (ISensor sensor in sensors) + { + var series = new LineSeries + { + ItemsSource = sensor.Values.Select(value => CreateDataPoint(sensor.SensorType, value)), + Color = colors[sensor].ToOxyColor(), + StrokeThickness = 1, + YAxisKey = _axes[sensor.SensorType].Key, + Title = sensor.Hardware.Name + " " + sensor.Name }; - foreach (SensorType type in Enum.GetValues(typeof(SensorType))) - { - string typeName = type.ToString(); - var axis = new LinearAxis - { - Position = AxisPosition.Left, - MajorGridlineStyle = LineStyle.Solid, - MajorGridlineThickness = 1, - MajorGridlineColor = _timeAxis.MajorGridlineColor, - MinorGridlineStyle = LineStyle.Solid, - MinorGridlineThickness = 1, - MinorGridlineColor = _timeAxis.MinorGridlineColor, - AxislineStyle = LineStyle.Solid, - Title = typeName, - Key = typeName, - }; + _model.Series.Add(series); - var annotation = new LineAnnotation - { - Type = LineAnnotationType.Horizontal, - ClipByXAxis = false, - ClipByYAxis = false, - LineStyle = LineStyle.Solid, - Color = OxyColors.Black, - YAxisKey = typeName, - StrokeThickness = 2, - }; - - axis.AxisChanged += (sender, args) => annotation.Y = axis.ActualMinimum; - axis.TransformChanged += (sender, args) => annotation.Y = axis.ActualMinimum; - - axis.Zoom(_settings.GetValue("plotPanel.Min" + axis.Key, float.NaN), _settings.GetValue("plotPanel.Max" + axis.Key, float.NaN)); - - if (units.ContainsKey(type)) - axis.Unit = units[type]; - - _axes.Add(type, axis); - _annotations.Add(type, annotation); - } - - var model = new ScaledPlotModel(_dpiXScale, _dpiYScale); - model.Axes.Add(_timeAxis); - foreach (LinearAxis axis in _axes.Values) - model.Axes.Add(axis); - model.IsLegendVisible = false; - - return model; + types.Add(sensor.SensorType); } - private void SetDpi() + foreach (KeyValuePair pair in _axes.Reverse()) { - // https://msdn.microsoft.com/en-us/library/windows/desktop/dn469266(v=vs.85).aspx - const int defaultDpi = 96; - Graphics g = CreateGraphics(); - - try - { - _dpiX = g.DpiX; - _dpiY = g.DpiY; - } - finally - { - g.Dispose(); - } - - if (_dpiX > 0) - _dpiXScale = _dpiX / defaultDpi; - if (_dpiY > 0) - _dpiYScale = _dpiY / defaultDpi; + LinearAxis axis = pair.Value; + SensorType type = pair.Key; + axis.IsAxisVisible = types.Contains(type); } - public void SetSensors(List sensors, IDictionary colors) + UpdateAxesPosition(); + InvalidatePlot(); + } + + private void UpdateAxesPosition() + { + if (_stackedAxes.Value) { - _model.Series.Clear(); - var types = new HashSet(); - - - DataPoint CreateDataPoint(SensorType type, SensorValue value) + int count = _axes.Values.Count(axis => axis.IsAxisVisible); + double start = 0.0; + foreach (KeyValuePair pair in _axes.Reverse()) { - float displayedValue; - - if (type == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) - { - displayedValue = UnitManager.CelsiusToFahrenheit(value.Value).Value; - } - else - { - displayedValue = value.Value; - } - - return new DataPoint((_now - value.Time).TotalSeconds, displayedValue); - } - - - foreach (ISensor sensor in sensors) - { - var series = new LineSeries - { - ItemsSource = sensor.Values.Select(value => CreateDataPoint(sensor.SensorType, value)), - Color = colors[sensor].ToOxyColor(), - StrokeThickness = 1, - YAxisKey = _axes[sensor.SensorType].Key, - Title = sensor.Hardware.Name + " " + sensor.Name - }; - - _model.Series.Add(series); - - types.Add(sensor.SensorType); + LinearAxis axis = pair.Value; + axis.StartPosition = start; + double delta = axis.IsAxisVisible ? 1.0 / count : 0; + start += delta; + axis.EndPosition = start; + axis.PositionTier = 0; + axis.MajorGridlineStyle = LineStyle.Solid; + axis.MinorGridlineStyle = LineStyle.Solid; + LineAnnotation annotation = _annotations[pair.Key]; + annotation.Y = axis.ActualMinimum; + if (!_model.Annotations.Contains(annotation)) + _model.Annotations.Add(annotation); } + } + else + { + int tier = 0; foreach (KeyValuePair pair in _axes.Reverse()) { LinearAxis axis = pair.Value; - SensorType type = pair.Key; - axis.IsAxisVisible = types.Contains(type); - } - UpdateAxesPosition(); - InvalidatePlot(); - } - - private void UpdateAxesPosition() - { - if (_stackedAxes.Value) - { - int count = _axes.Values.Count(axis => axis.IsAxisVisible); - double start = 0.0; - foreach (KeyValuePair pair in _axes.Reverse()) + if (axis.IsAxisVisible) { - LinearAxis axis = pair.Value; - axis.StartPosition = start; - double delta = axis.IsAxisVisible ? 1.0 / count : 0; - start += delta; - axis.EndPosition = start; + axis.StartPosition = 0; + axis.EndPosition = 1; + axis.PositionTier = tier; + tier++; + } + else + { + axis.StartPosition = 0; + axis.EndPosition = 0; axis.PositionTier = 0; - axis.MajorGridlineStyle = LineStyle.Solid; - axis.MinorGridlineStyle = LineStyle.Solid; - LineAnnotation annotation = _annotations[pair.Key]; - annotation.Y = axis.ActualMinimum; - if (!_model.Annotations.Contains(annotation)) - _model.Annotations.Add(annotation); } + axis.MajorGridlineStyle = LineStyle.None; + axis.MinorGridlineStyle = LineStyle.None; + LineAnnotation annotation = _annotations[pair.Key]; + if (_model.Annotations.Contains(annotation)) + _model.Annotations.Remove(_annotations[pair.Key]); } - else - { - int tier = 0; - - foreach (KeyValuePair pair in _axes.Reverse()) - { - LinearAxis axis = pair.Value; - - if (axis.IsAxisVisible) - { - axis.StartPosition = 0; - axis.EndPosition = 1; - axis.PositionTier = tier; - tier++; - } - else - { - axis.StartPosition = 0; - axis.EndPosition = 0; - axis.PositionTier = 0; - } - axis.MajorGridlineStyle = LineStyle.None; - axis.MinorGridlineStyle = LineStyle.None; - LineAnnotation annotation = _annotations[pair.Key]; - if (_model.Annotations.Contains(annotation)) - _model.Annotations.Remove(_annotations[pair.Key]); - } - } - } - - public void InvalidatePlot() - { - _now = DateTime.UtcNow; - - if (_axes != null) - { - foreach (KeyValuePair pair in _axes) - { - LinearAxis axis = pair.Value; - SensorType type = pair.Key; - if (type == SensorType.Temperature) - axis.Unit = _unitManager.TemperatureUnit == TemperatureUnit.Celsius ? "°C" : "°F"; - - if (!_stackedAxes.Value) - continue; - - var annotation = _annotations[pair.Key]; - annotation.Y = axis.ActualMaximum; - } - } - - _plot?.InvalidatePlot(true); - } - - public void TimeAxisZoom(double min, double max) - { - bool timeAxisIsZoomEnabled = _timeAxis.IsZoomEnabled; - - _timeAxis.IsZoomEnabled = true; - _timeAxis.Zoom(min, max); - InvalidatePlot(); - _timeAxis.IsZoomEnabled = timeAxisIsZoomEnabled; - } - - public void AutoscaleAllYAxes() - { - foreach (LinearAxis axis in _axes.Values) - axis.Zoom(double.NaN, double.NaN); } } -} + + public void InvalidatePlot() + { + _now = DateTime.UtcNow; + + if (_axes != null) + { + foreach (KeyValuePair pair in _axes) + { + LinearAxis axis = pair.Value; + SensorType type = pair.Key; + if (type == SensorType.Temperature) + axis.Unit = _unitManager.TemperatureUnit == TemperatureUnit.Celsius ? "°C" : "°F"; + + if (!_stackedAxes.Value) + continue; + + var annotation = _annotations[pair.Key]; + annotation.Y = axis.ActualMaximum; + } + } + + _plot?.InvalidatePlot(true); + } + + public void TimeAxisZoom(double min, double max) + { + bool timeAxisIsZoomEnabled = _timeAxis.IsZoomEnabled; + + _timeAxis.IsZoomEnabled = true; + _timeAxis.Zoom(min, max); + InvalidatePlot(); + _timeAxis.IsZoomEnabled = timeAxisIsZoomEnabled; + } + + public void AutoscaleAllYAxes() + { + foreach (LinearAxis axis in _axes.Values) + axis.Zoom(double.NaN, double.NaN); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/PortForm.cs b/LibreHardwareMonitor/UI/PortForm.cs index 22d9c4e..e30d57b 100644 --- a/LibreHardwareMonitor/UI/PortForm.cs +++ b/LibreHardwareMonitor/UI/PortForm.cs @@ -10,74 +10,73 @@ using System.Net; using System.Net.Sockets; using System.Diagnostics; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public partial class PortForm : Form { - public partial class PortForm : Form + private readonly MainForm _parent; + private readonly string _localIP; + public PortForm(MainForm m) { - private readonly MainForm _parent; - private readonly string _localIP; - public PortForm(MainForm m) - { - InitializeComponent(); - _parent = m; - _localIP = GetLocalIP(); - } - - private void PortTextBox_TextChanged(object sender, EventArgs e) - { - - } - - private string GetLocalIP() - { - IPHostEntry host; - string localIP = "?"; - host = Dns.GetHostEntry(Dns.GetHostName()); - foreach (IPAddress ip in host.AddressList) - { - if (ip.AddressFamily == AddressFamily.InterNetwork) - localIP = ip.ToString(); - } - return localIP; - } - - private void PortNumericUpDn_ValueChanged(object sender, EventArgs e) - { - string url = "http://" + _localIP + ":" + portNumericUpDn.Value + "/"; - webServerLinkLabel.Text = url; - webServerLinkLabel.Links.Remove(webServerLinkLabel.Links[0]); - webServerLinkLabel.Links.Add(0, webServerLinkLabel.Text.Length, url); - } - - private void PortOKButton_Click(object sender, EventArgs e) - { - _parent.Server.ListenerPort = (int)portNumericUpDn.Value; - Close(); - } - - private void PortCancelButton_Click(object sender, EventArgs e) - { - Close(); - } - - private void PortForm_Load(object sender, EventArgs e) - { - portNumericUpDn.Value = _parent.Server.ListenerPort; - PortNumericUpDn_ValueChanged(null, null); - } - - private void WebServerLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) - { - try - { - Process.Start(new ProcessStartInfo(e.Link.LinkData.ToString())); - } - catch { } - } - - private void PortNumericUpDn_KeyUp(object sender, KeyEventArgs e) - { - PortNumericUpDn_ValueChanged(null, null); - } + InitializeComponent(); + _parent = m; + _localIP = GetLocalIP(); } -} + + private void PortTextBox_TextChanged(object sender, EventArgs e) + { + + } + + private string GetLocalIP() + { + IPHostEntry host; + string localIP = "?"; + host = Dns.GetHostEntry(Dns.GetHostName()); + foreach (IPAddress ip in host.AddressList) + { + if (ip.AddressFamily == AddressFamily.InterNetwork) + localIP = ip.ToString(); + } + return localIP; + } + + private void PortNumericUpDn_ValueChanged(object sender, EventArgs e) + { + string url = "http://" + _localIP + ":" + portNumericUpDn.Value + "/"; + webServerLinkLabel.Text = url; + webServerLinkLabel.Links.Remove(webServerLinkLabel.Links[0]); + webServerLinkLabel.Links.Add(0, webServerLinkLabel.Text.Length, url); + } + + private void PortOKButton_Click(object sender, EventArgs e) + { + _parent.Server.ListenerPort = (int)portNumericUpDn.Value; + Close(); + } + + private void PortCancelButton_Click(object sender, EventArgs e) + { + Close(); + } + + private void PortForm_Load(object sender, EventArgs e) + { + portNumericUpDn.Value = _parent.Server.ListenerPort; + PortNumericUpDn_ValueChanged(null, null); + } + + private void WebServerLinkLabel_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e) + { + try + { + Process.Start(new ProcessStartInfo(e.Link.LinkData.ToString())); + } + catch { } + } + + private void PortNumericUpDn_KeyUp(object sender, KeyEventArgs e) + { + PortNumericUpDn_ValueChanged(null, null); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/ScaledPlotModel.cs b/LibreHardwareMonitor/UI/ScaledPlotModel.cs index 39352be..eb02187 100644 --- a/LibreHardwareMonitor/UI/ScaledPlotModel.cs +++ b/LibreHardwareMonitor/UI/ScaledPlotModel.cs @@ -1,34 +1,33 @@ using OxyPlot; using OxyPlot.Legends; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +class ScaledPlotModel : PlotModel { - class ScaledPlotModel : PlotModel + public ScaledPlotModel(double dpiXscale, double dpiYscale) { - public ScaledPlotModel(double dpiXscale, double dpiYscale) - { - PlotMargins = new OxyThickness(PlotMargins.Left * dpiXscale, - PlotMargins.Top * dpiYscale, - PlotMargins.Right * dpiXscale, - PlotMargins.Bottom * dpiYscale); + PlotMargins = new OxyThickness(PlotMargins.Left * dpiXscale, + PlotMargins.Top * dpiYscale, + PlotMargins.Right * dpiXscale, + PlotMargins.Bottom * dpiYscale); - Padding = new OxyThickness(Padding.Left * dpiXscale, - Padding.Top * dpiYscale, - Padding.Right * dpiXscale, - Padding.Bottom * dpiYscale); + Padding = new OxyThickness(Padding.Left * dpiXscale, + Padding.Top * dpiYscale, + Padding.Right * dpiXscale, + Padding.Bottom * dpiYscale); - TitlePadding *= dpiXscale; + TitlePadding *= dpiXscale; - Legend legend = new(); + Legend legend = new(); - legend.LegendSymbolLength *= dpiXscale; - legend.LegendSymbolMargin *= dpiXscale; - legend.LegendPadding *= dpiXscale; - legend.LegendColumnSpacing *= dpiXscale; - legend.LegendItemSpacing *= dpiXscale; - legend.LegendMargin *= dpiXscale; + legend.LegendSymbolLength *= dpiXscale; + legend.LegendSymbolMargin *= dpiXscale; + legend.LegendPadding *= dpiXscale; + legend.LegendColumnSpacing *= dpiXscale; + legend.LegendItemSpacing *= dpiXscale; + legend.LegendMargin *= dpiXscale; - Legends.Add(legend); - } + Legends.Add(legend); } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/SensorGadget.cs b/LibreHardwareMonitor/UI/SensorGadget.cs index 07f0872..7c3b055 100644 --- a/LibreHardwareMonitor/UI/SensorGadget.cs +++ b/LibreHardwareMonitor/UI/SensorGadget.cs @@ -14,743 +14,741 @@ using System.Linq; using LibreHardwareMonitor.Hardware; using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class SensorGadget : Gadget { - public class SensorGadget : Gadget + private const int TopBorder = 6; + private const int BottomBorder = 7; + private const int LeftBorder = 6; + private const int RightBorder = 7; + + private readonly UnitManager _unitManager; + private Image _back = Utilities.EmbeddedResources.GetImage("gadget.png"); + private Image _image; + private Image _fore; + private Image _barBack = Utilities.EmbeddedResources.GetImage("barback.png"); + private Image _barFore = Utilities.EmbeddedResources.GetImage("barblue.png"); + private Image _background = new Bitmap(1, 1); + private readonly float _scale; + private float _fontSize; + private int _iconSize; + private int _hardwareLineHeight; + private int _sensorLineHeight; + private int _rightMargin; + private int _leftMargin; + private int _topMargin; + private int _bottomMargin; + private int _progressWidth; + + private readonly IDictionary> _sensors = new SortedDictionary>(new HardwareComparer()); + private readonly PersistentSettings _settings; + private readonly UserOption _hardwareNames; + + private Font _largeFont; + private Font _smallFont; + private Brush _textBrush; + private StringFormat _stringFormat; + private StringFormat _trimStringFormat; + private StringFormat _alignRightStringFormat; + + public SensorGadget(IComputer computer, PersistentSettings settings, UnitManager unitManager) { - private const int TopBorder = 6; - private const int BottomBorder = 7; - private const int LeftBorder = 6; - private const int RightBorder = 7; + _unitManager = unitManager; + _settings = settings; + computer.HardwareAdded += HardwareAdded; + computer.HardwareRemoved += HardwareRemoved; - private readonly UnitManager _unitManager; - private Image _back = Utilities.EmbeddedResources.GetImage("gadget.png"); - private Image _image; - private Image _fore; - private Image _barBack = Utilities.EmbeddedResources.GetImage("barback.png"); - private Image _barFore = Utilities.EmbeddedResources.GetImage("barblue.png"); - private Image _background = new Bitmap(1, 1); - private readonly float _scale; - private float _fontSize; - private int _iconSize; - private int _hardwareLineHeight; - private int _sensorLineHeight; - private int _rightMargin; - private int _leftMargin; - private int _topMargin; - private int _bottomMargin; - private int _progressWidth; + _stringFormat = new StringFormat { FormatFlags = StringFormatFlags.NoWrap }; + _trimStringFormat = new StringFormat { Trimming = StringTrimming.EllipsisCharacter, FormatFlags = StringFormatFlags.NoWrap }; + _alignRightStringFormat = new StringFormat { Alignment = StringAlignment.Far, FormatFlags = StringFormatFlags.NoWrap }; - private readonly IDictionary> _sensors = new SortedDictionary>(new HardwareComparer()); - private readonly PersistentSettings _settings; - private readonly UserOption _hardwareNames; - - private Font _largeFont; - private Font _smallFont; - private Brush _textBrush; - private StringFormat _stringFormat; - private StringFormat _trimStringFormat; - private StringFormat _alignRightStringFormat; - - public SensorGadget(IComputer computer, PersistentSettings settings, UnitManager unitManager) - { - _unitManager = unitManager; - _settings = settings; - computer.HardwareAdded += HardwareAdded; - computer.HardwareRemoved += HardwareRemoved; - - _stringFormat = new StringFormat { FormatFlags = StringFormatFlags.NoWrap }; - _trimStringFormat = new StringFormat { Trimming = StringTrimming.EllipsisCharacter, FormatFlags = StringFormatFlags.NoWrap }; - _alignRightStringFormat = new StringFormat { Alignment = StringAlignment.Far, FormatFlags = StringFormatFlags.NoWrap }; - - if (File.Exists("gadget_background.png")) - { - try - { - Image newBack = new Bitmap("gadget_background.png"); - _back.Dispose(); - _back = newBack; - } - catch { } - } - - if (File.Exists("gadget_image.png")) - { - try - { - _image = new Bitmap("gadget_image.png"); - } - catch { } - } - - if (File.Exists("gadget_foreground.png")) - { - try - { - _fore = new Bitmap("gadget_foreground.png"); - } - catch { } - } - - if (File.Exists("gadget_bar_background.png")) - { - try - { - Image newBarBack = new Bitmap("gadget_bar_background.png"); - _barBack.Dispose(); - _barBack = newBarBack; - } - catch { } - } - - if (File.Exists("gadget_bar_foreground.png")) - { - try - { - Image newBarColor = new Bitmap("gadget_bar_foreground.png"); - _barFore.Dispose(); - _barFore = newBarColor; - } - catch { } - } - - Location = new Point(settings.GetValue("sensorGadget.Location.X", 100), settings.GetValue("sensorGadget.Location.Y", 100)); - LocationChanged += delegate - { - settings.SetValue("sensorGadget.Location.X", Location.X); - settings.SetValue("sensorGadget.Location.Y", Location.Y); - }; - - // get the custom to default dpi ratio - using (Bitmap b = new Bitmap(1, 1)) - { - _scale = b.HorizontalResolution / 96.0f; - } - - SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f)); - Resize(settings.GetValue("sensorGadget.Width", Size.Width)); - - ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); - ToolStripMenuItem hardwareNamesItem = new ToolStripMenuItem("Hardware Names"); - contextMenuStrip.Items.Add(hardwareNamesItem); - ToolStripMenuItem fontSizeMenu = new ToolStripMenuItem("Font Size"); - for (int i = 0; i < 4; i++) - { - float size; - string name; - switch (i) - { - case 0: size = 6.5f; name = "Small"; break; - case 1: size = 7.5f; name = "Medium"; break; - case 2: size = 9f; name = "Large"; break; - case 3: size = 11f; name = "Very Large"; break; - default: throw new NotImplementedException(); - } - - ToolStripItem item = new ToolStripMenuItem(name) { Checked = _fontSize == size }; - item.Click += delegate - { - SetFontSize(size); - settings.SetValue("sensorGadget.FontSize", size); - foreach (ToolStripMenuItem mi in fontSizeMenu.DropDownItems) - mi.Checked = mi == item; - }; - fontSizeMenu.DropDownItems.Add(item); - } - contextMenuStrip.Items.Add(fontSizeMenu); - - Color fontColor = settings.GetValue("sensorGadget.FontColor", Color.White); - int fontColorArgb = fontColor.ToArgb(); - - SetFontColor(fontColor); - - IEnumerable providedColors = Enum.GetValues(typeof(KnownColor)) - .Cast() - .Select(x => Color.FromKnownColor(x)) - .Where(x => !x.IsSystemColor && x.Name.Length < 7); - - ToolStripMenuItem fontColorMenu = new ToolStripMenuItem("Font Color"); - foreach (Color color in providedColors) - { - ToolStripItem item = new ToolStripMenuItem(color.Name) { Checked = fontColorArgb == color.ToArgb() }; - item.Click += delegate - { - SetFontColor(color); - settings.SetValue("sensorGadget.FontColor", color); - foreach (ToolStripMenuItem mi in fontColorMenu.DropDownItems) - mi.Checked = mi == item; - }; - fontColorMenu.DropDownItems.Add(item); - } - contextMenuStrip.Items.Add(fontColorMenu); - contextMenuStrip.Items.Add(new ToolStripSeparator()); - ToolStripMenuItem lockItem = new ToolStripMenuItem("Lock Position and Size"); - contextMenuStrip.Items.Add(lockItem); - contextMenuStrip.Items.Add(new ToolStripSeparator()); - ToolStripMenuItem alwaysOnTopItem = new ToolStripMenuItem("Always on Top"); - contextMenuStrip.Items.Add(alwaysOnTopItem); - ToolStripMenuItem opacityMenu = new ToolStripMenuItem("Opacity"); - contextMenuStrip.Items.Add(opacityMenu); - Opacity = (byte)settings.GetValue("sensorGadget.Opacity", 255); - - for (int i = 0; i < 5; i++) - { - ToolStripMenuItem item = new ToolStripMenuItem((20 * (i + 1)).ToString() + " %"); - byte o = (byte)(51 * (i + 1)); - item.Checked = Opacity == o; - item.Click += delegate - { - Opacity = o; - settings.SetValue("sensorGadget.Opacity", Opacity); - foreach (ToolStripMenuItem mi in opacityMenu.DropDownItems) - mi.Checked = mi == item; - }; - opacityMenu.DropDownItems.Add(item); - } - ContextMenuStrip = contextMenuStrip; - - _hardwareNames = new UserOption("sensorGadget.Hardwarenames", true, hardwareNamesItem, settings); - _hardwareNames.Changed += delegate - { - Resize(); - }; - - UserOption alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false, alwaysOnTopItem, settings); - alwaysOnTop.Changed += delegate - { - AlwaysOnTop = alwaysOnTop.Value; - }; - UserOption lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize", false, lockItem, settings); - lockPositionAndSize.Changed += delegate - { - LockPositionAndSize = lockPositionAndSize.Value; - }; - - HitTest += delegate (object sender, HitTestEventArgs e) - { - if (lockPositionAndSize.Value) - return; - - if (e.Location.X < LeftBorder) - { - e.HitResult = HitResult.Left; - return; - } - if (e.Location.X > Size.Width - 1 - RightBorder) - { - e.HitResult = HitResult.Right; - } - }; - - SizeChanged += delegate - { - settings.SetValue("sensorGadget.Width", Size.Width); - Redraw(); - }; - - VisibleChanged += delegate - { - Rectangle bounds = new Rectangle(Location, Size); - Screen screen = Screen.FromRectangle(bounds); - Rectangle intersection = Rectangle.Intersect(screen.WorkingArea, bounds); - if (intersection.Width < Math.Min(16, bounds.Width) || intersection.Height < Math.Min(16, bounds.Height)) - { - Location = new Point(screen.WorkingArea.Width / 2 - bounds.Width / 2, screen.WorkingArea.Height / 2 - bounds.Height / 2); - } - }; - - MouseDoubleClick += delegate - { - SendHideShowCommand(); - }; - } - - public override void Dispose() - { - - _largeFont.Dispose(); - _largeFont = null; - - _smallFont.Dispose(); - _smallFont = null; - - _textBrush.Dispose(); - _textBrush = null; - - _stringFormat.Dispose(); - _stringFormat = null; - - _trimStringFormat.Dispose(); - _trimStringFormat = null; - - _alignRightStringFormat.Dispose(); - _alignRightStringFormat = null; - - _back.Dispose(); - _back = null; - - _barFore.Dispose(); - _barFore = null; - - _barBack.Dispose(); - _barBack = null; - - _background.Dispose(); - _background = null; - - if (_image != null) - { - _image.Dispose(); - _image = null; - } - - if (_fore != null) - { - _fore.Dispose(); - _fore = null; - } - - base.Dispose(); - } - - private void HardwareRemoved(IHardware hardware) - { - hardware.SensorAdded -= SensorAdded; - hardware.SensorRemoved -= SensorRemoved; - - foreach (ISensor sensor in hardware.Sensors) - SensorRemoved(sensor); - - foreach (IHardware subHardware in hardware.SubHardware) - HardwareRemoved(subHardware); - } - - private void HardwareAdded(IHardware hardware) - { - foreach (ISensor sensor in hardware.Sensors) - SensorAdded(sensor); - - hardware.SensorAdded += SensorAdded; - hardware.SensorRemoved += SensorRemoved; - - foreach (IHardware subHardware in hardware.SubHardware) - HardwareAdded(subHardware); - } - - private void SensorAdded(ISensor sensor) - { - if (_settings.GetValue(new Identifier(sensor.Identifier, "gadget").ToString(), false)) - Add(sensor); - } - - private void SensorRemoved(ISensor sensor) - { - if (Contains(sensor)) - Remove(sensor, false); - } - - public bool Contains(ISensor sensor) - { - return _sensors.Values.Any(list => list.Contains(sensor)); - } - - public void Add(ISensor sensor) - { - if (Contains(sensor)) - return; - - - // get the right hardware - IHardware hardware = sensor.Hardware; - while (hardware.Parent != null) - hardware = hardware.Parent; - - // get the sensor list associated with the hardware - if (!_sensors.TryGetValue(hardware, out IList list)) - { - list = new List(); - _sensors.Add(hardware, list); - } - - // insert the sensor at the right position - int i = 0; - while (i < list.Count && (list[i].SensorType < sensor.SensorType || (list[i].SensorType == sensor.SensorType && list[i].Index < sensor.Index))) - i++; - - list.Insert(i, sensor); - - _settings.SetValue(new Identifier(sensor.Identifier, "gadget").ToString(), true); - Resize(); - } - - public void Remove(ISensor sensor) - { - Remove(sensor, true); - } - - private void Remove(ISensor sensor, bool deleteConfig) - { - if (deleteConfig) - _settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString()); - - foreach (KeyValuePair> keyValue in _sensors) - { - if (keyValue.Value.Contains(sensor)) - { - keyValue.Value.Remove(sensor); - if (keyValue.Value.Count == 0) - { - _sensors.Remove(keyValue.Key); - break; - } - } - } - Resize(); - } - - public event EventHandler HideShowCommand; - - public void SendHideShowCommand() - { - HideShowCommand?.Invoke(this, null); - } - - private Font CreateFont(float size, FontStyle style) + if (File.Exists("gadget_background.png")) { try { - return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style); + Image newBack = new Bitmap("gadget_background.png"); + _back.Dispose(); + _back = newBack; } - catch (ArgumentException) + catch { } + } + + if (File.Exists("gadget_image.png")) + { + try { - // if the style is not supported, fall back to the original one - return new Font(SystemFonts.MessageBoxFont.FontFamily, size, - SystemFonts.MessageBoxFont.Style); + _image = new Bitmap("gadget_image.png"); } + catch { } } - private void SetFontSize(float size) + if (File.Exists("gadget_foreground.png")) { - _fontSize = size; - _largeFont = CreateFont(_fontSize, FontStyle.Bold); - _smallFont = CreateFont(_fontSize, FontStyle.Regular); - - double scaledFontSize = _fontSize * _scale; - _iconSize = (int)Math.Round(1.5 * scaledFontSize); - _hardwareLineHeight = (int)Math.Round(1.66 * scaledFontSize); - _sensorLineHeight = (int)Math.Round(1.33 * scaledFontSize); - _leftMargin = LeftBorder + (int)Math.Round(0.3 * scaledFontSize); - _rightMargin = RightBorder + (int)Math.Round(0.3 * scaledFontSize); - _topMargin = TopBorder; - _bottomMargin = BottomBorder + (int)Math.Round(0.3 * scaledFontSize); - _progressWidth = (int)Math.Round(5.3 * scaledFontSize); - - Resize((int)Math.Round(17.3 * scaledFontSize)); - } - - private void SetFontColor(Color color) - { - _textBrush?.Dispose(); - _textBrush = new SolidBrush(color); - } - - private void Resize() - { - Resize(Size.Width); - } - - private void Resize(int width) - { - int y = _topMargin; - - foreach (KeyValuePair> pair in _sensors) + try { - if (_hardwareNames.Value) + _fore = new Bitmap("gadget_foreground.png"); + } + catch { } + } + + if (File.Exists("gadget_bar_background.png")) + { + try + { + Image newBarBack = new Bitmap("gadget_bar_background.png"); + _barBack.Dispose(); + _barBack = newBarBack; + } + catch { } + } + + if (File.Exists("gadget_bar_foreground.png")) + { + try + { + Image newBarColor = new Bitmap("gadget_bar_foreground.png"); + _barFore.Dispose(); + _barFore = newBarColor; + } + catch { } + } + + Location = new Point(settings.GetValue("sensorGadget.Location.X", 100), settings.GetValue("sensorGadget.Location.Y", 100)); + LocationChanged += delegate + { + settings.SetValue("sensorGadget.Location.X", Location.X); + settings.SetValue("sensorGadget.Location.Y", Location.Y); + }; + + // get the custom to default dpi ratio + using (Bitmap b = new Bitmap(1, 1)) + { + _scale = b.HorizontalResolution / 96.0f; + } + + SetFontSize(settings.GetValue("sensorGadget.FontSize", 7.5f)); + Resize(settings.GetValue("sensorGadget.Width", Size.Width)); + + ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); + ToolStripMenuItem hardwareNamesItem = new ToolStripMenuItem("Hardware Names"); + contextMenuStrip.Items.Add(hardwareNamesItem); + ToolStripMenuItem fontSizeMenu = new ToolStripMenuItem("Font Size"); + for (int i = 0; i < 4; i++) + { + float size; + string name; + switch (i) + { + case 0: size = 6.5f; name = "Small"; break; + case 1: size = 7.5f; name = "Medium"; break; + case 2: size = 9f; name = "Large"; break; + case 3: size = 11f; name = "Very Large"; break; + default: throw new NotImplementedException(); + } + + ToolStripItem item = new ToolStripMenuItem(name) { Checked = _fontSize == size }; + item.Click += delegate + { + SetFontSize(size); + settings.SetValue("sensorGadget.FontSize", size); + foreach (ToolStripMenuItem mi in fontSizeMenu.DropDownItems) + mi.Checked = mi == item; + }; + fontSizeMenu.DropDownItems.Add(item); + } + contextMenuStrip.Items.Add(fontSizeMenu); + + Color fontColor = settings.GetValue("sensorGadget.FontColor", Color.White); + int fontColorArgb = fontColor.ToArgb(); + + SetFontColor(fontColor); + + IEnumerable providedColors = Enum.GetValues(typeof(KnownColor)) + .Cast() + .Select(x => Color.FromKnownColor(x)) + .Where(x => !x.IsSystemColor && x.Name.Length < 7); + + ToolStripMenuItem fontColorMenu = new ToolStripMenuItem("Font Color"); + foreach (Color color in providedColors) + { + ToolStripItem item = new ToolStripMenuItem(color.Name) { Checked = fontColorArgb == color.ToArgb() }; + item.Click += delegate + { + SetFontColor(color); + settings.SetValue("sensorGadget.FontColor", color); + foreach (ToolStripMenuItem mi in fontColorMenu.DropDownItems) + mi.Checked = mi == item; + }; + fontColorMenu.DropDownItems.Add(item); + } + contextMenuStrip.Items.Add(fontColorMenu); + contextMenuStrip.Items.Add(new ToolStripSeparator()); + ToolStripMenuItem lockItem = new ToolStripMenuItem("Lock Position and Size"); + contextMenuStrip.Items.Add(lockItem); + contextMenuStrip.Items.Add(new ToolStripSeparator()); + ToolStripMenuItem alwaysOnTopItem = new ToolStripMenuItem("Always on Top"); + contextMenuStrip.Items.Add(alwaysOnTopItem); + ToolStripMenuItem opacityMenu = new ToolStripMenuItem("Opacity"); + contextMenuStrip.Items.Add(opacityMenu); + Opacity = (byte)settings.GetValue("sensorGadget.Opacity", 255); + + for (int i = 0; i < 5; i++) + { + ToolStripMenuItem item = new ToolStripMenuItem((20 * (i + 1)).ToString() + " %"); + byte o = (byte)(51 * (i + 1)); + item.Checked = Opacity == o; + item.Click += delegate + { + Opacity = o; + settings.SetValue("sensorGadget.Opacity", Opacity); + foreach (ToolStripMenuItem mi in opacityMenu.DropDownItems) + mi.Checked = mi == item; + }; + opacityMenu.DropDownItems.Add(item); + } + ContextMenuStrip = contextMenuStrip; + + _hardwareNames = new UserOption("sensorGadget.Hardwarenames", true, hardwareNamesItem, settings); + _hardwareNames.Changed += delegate + { + Resize(); + }; + + UserOption alwaysOnTop = new UserOption("sensorGadget.AlwaysOnTop", false, alwaysOnTopItem, settings); + alwaysOnTop.Changed += delegate + { + AlwaysOnTop = alwaysOnTop.Value; + }; + UserOption lockPositionAndSize = new UserOption("sensorGadget.LockPositionAndSize", false, lockItem, settings); + lockPositionAndSize.Changed += delegate + { + LockPositionAndSize = lockPositionAndSize.Value; + }; + + HitTest += delegate (object sender, HitTestEventArgs e) + { + if (lockPositionAndSize.Value) + return; + + if (e.Location.X < LeftBorder) + { + e.HitResult = HitResult.Left; + return; + } + if (e.Location.X > Size.Width - 1 - RightBorder) + { + e.HitResult = HitResult.Right; + } + }; + + SizeChanged += delegate + { + settings.SetValue("sensorGadget.Width", Size.Width); + Redraw(); + }; + + VisibleChanged += delegate + { + Rectangle bounds = new Rectangle(Location, Size); + Screen screen = Screen.FromRectangle(bounds); + Rectangle intersection = Rectangle.Intersect(screen.WorkingArea, bounds); + if (intersection.Width < Math.Min(16, bounds.Width) || intersection.Height < Math.Min(16, bounds.Height)) + { + Location = new Point(screen.WorkingArea.Width / 2 - bounds.Width / 2, screen.WorkingArea.Height / 2 - bounds.Height / 2); + } + }; + + MouseDoubleClick += delegate + { + SendHideShowCommand(); + }; + } + + public override void Dispose() + { + + _largeFont.Dispose(); + _largeFont = null; + + _smallFont.Dispose(); + _smallFont = null; + + _textBrush.Dispose(); + _textBrush = null; + + _stringFormat.Dispose(); + _stringFormat = null; + + _trimStringFormat.Dispose(); + _trimStringFormat = null; + + _alignRightStringFormat.Dispose(); + _alignRightStringFormat = null; + + _back.Dispose(); + _back = null; + + _barFore.Dispose(); + _barFore = null; + + _barBack.Dispose(); + _barBack = null; + + _background.Dispose(); + _background = null; + + if (_image != null) + { + _image.Dispose(); + _image = null; + } + + if (_fore != null) + { + _fore.Dispose(); + _fore = null; + } + + base.Dispose(); + } + + private void HardwareRemoved(IHardware hardware) + { + hardware.SensorAdded -= SensorAdded; + hardware.SensorRemoved -= SensorRemoved; + + foreach (ISensor sensor in hardware.Sensors) + SensorRemoved(sensor); + + foreach (IHardware subHardware in hardware.SubHardware) + HardwareRemoved(subHardware); + } + + private void HardwareAdded(IHardware hardware) + { + foreach (ISensor sensor in hardware.Sensors) + SensorAdded(sensor); + + hardware.SensorAdded += SensorAdded; + hardware.SensorRemoved += SensorRemoved; + + foreach (IHardware subHardware in hardware.SubHardware) + HardwareAdded(subHardware); + } + + private void SensorAdded(ISensor sensor) + { + if (_settings.GetValue(new Identifier(sensor.Identifier, "gadget").ToString(), false)) + Add(sensor); + } + + private void SensorRemoved(ISensor sensor) + { + if (Contains(sensor)) + Remove(sensor, false); + } + + public bool Contains(ISensor sensor) + { + return _sensors.Values.Any(list => list.Contains(sensor)); + } + + public void Add(ISensor sensor) + { + if (Contains(sensor)) + return; + + + // get the right hardware + IHardware hardware = sensor.Hardware; + while (hardware.Parent != null) + hardware = hardware.Parent; + + // get the sensor list associated with the hardware + if (!_sensors.TryGetValue(hardware, out IList list)) + { + list = new List(); + _sensors.Add(hardware, list); + } + + // insert the sensor at the right position + int i = 0; + while (i < list.Count && (list[i].SensorType < sensor.SensorType || (list[i].SensorType == sensor.SensorType && list[i].Index < sensor.Index))) + i++; + + list.Insert(i, sensor); + + _settings.SetValue(new Identifier(sensor.Identifier, "gadget").ToString(), true); + Resize(); + } + + public void Remove(ISensor sensor) + { + Remove(sensor, true); + } + + private void Remove(ISensor sensor, bool deleteConfig) + { + if (deleteConfig) + _settings.Remove(new Identifier(sensor.Identifier, "gadget").ToString()); + + foreach (KeyValuePair> keyValue in _sensors) + { + if (keyValue.Value.Contains(sensor)) + { + keyValue.Value.Remove(sensor); + if (keyValue.Value.Count == 0) { - if (y > _topMargin) - y += _hardwareLineHeight - _sensorLineHeight; - y += _hardwareLineHeight; + _sensors.Remove(keyValue.Key); + break; } - y += pair.Value.Count * _sensorLineHeight; } - - if (_sensors.Count == 0) - y += 4 * _sensorLineHeight + _hardwareLineHeight; - - y += _bottomMargin; - Size = new Size(width, y); } + Resize(); + } - private void DrawImageWidthBorder(Graphics g, int width, int height, Image back, int t, int b, int l, int r) + public event EventHandler HideShowCommand; + + public void SendHideShowCommand() + { + HideShowCommand?.Invoke(this, null); + } + + private Font CreateFont(float size, FontStyle style) + { + try { - GraphicsUnit u = GraphicsUnit.Pixel; - - g.DrawImage(back, new Rectangle(0, 0, l, t), new Rectangle(0, 0, l, t), u); - g.DrawImage(back, new Rectangle(l, 0, width - l - r, t), new Rectangle(l, 0, back.Width - l - r, t), u); - g.DrawImage(back, new Rectangle(width - r, 0, r, t), new Rectangle(back.Width - r, 0, r, t), u); - - g.DrawImage(back, new Rectangle(0, t, l, height - t - b), new Rectangle(0, t, l, back.Height - t - b), u); - g.DrawImage(back, new Rectangle(l, t, width - l - r, height - t - b), new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u); - g.DrawImage(back, new Rectangle(width - r, t, r, height - t - b), new Rectangle(back.Width - r, t, r, back.Height - t - b), u); - - g.DrawImage(back, new Rectangle(0, height - b, l, b), new Rectangle(0, back.Height - b, l, b), u); - g.DrawImage(back, new Rectangle(l, height - b, width - l - r, b), new Rectangle(l, back.Height - b, back.Width - l - r, b), u); - g.DrawImage(back, new Rectangle(width - r, height - b, r, b), new Rectangle(back.Width - r, back.Height - b, r, b), u); + return new Font(SystemFonts.MessageBoxFont.FontFamily, size, style); } - - private void DrawBackground(Graphics g) + catch (ArgumentException) { - int w = Size.Width; - int h = Size.Height; + // if the style is not supported, fall back to the original one + return new Font(SystemFonts.MessageBoxFont.FontFamily, size, + SystemFonts.MessageBoxFont.Style); + } + } - if (w != _background.Width || h != _background.Height) + private void SetFontSize(float size) + { + _fontSize = size; + _largeFont = CreateFont(_fontSize, FontStyle.Bold); + _smallFont = CreateFont(_fontSize, FontStyle.Regular); + + double scaledFontSize = _fontSize * _scale; + _iconSize = (int)Math.Round(1.5 * scaledFontSize); + _hardwareLineHeight = (int)Math.Round(1.66 * scaledFontSize); + _sensorLineHeight = (int)Math.Round(1.33 * scaledFontSize); + _leftMargin = LeftBorder + (int)Math.Round(0.3 * scaledFontSize); + _rightMargin = RightBorder + (int)Math.Round(0.3 * scaledFontSize); + _topMargin = TopBorder; + _bottomMargin = BottomBorder + (int)Math.Round(0.3 * scaledFontSize); + _progressWidth = (int)Math.Round(5.3 * scaledFontSize); + + Resize((int)Math.Round(17.3 * scaledFontSize)); + } + + private void SetFontColor(Color color) + { + _textBrush?.Dispose(); + _textBrush = new SolidBrush(color); + } + + private void Resize() + { + Resize(Size.Width); + } + + private void Resize(int width) + { + int y = _topMargin; + + foreach (KeyValuePair> pair in _sensors) + { + if (_hardwareNames.Value) { - _background.Dispose(); - _background = new Bitmap(w, h, PixelFormat.Format32bppPArgb); + if (y > _topMargin) + y += _hardwareLineHeight - _sensorLineHeight; + y += _hardwareLineHeight; + } + y += pair.Value.Count * _sensorLineHeight; + } - using (Graphics graphics = Graphics.FromImage(_background)) + if (_sensors.Count == 0) + y += 4 * _sensorLineHeight + _hardwareLineHeight; + + y += _bottomMargin; + Size = new Size(width, y); + } + + private void DrawImageWidthBorder(Graphics g, int width, int height, Image back, int t, int b, int l, int r) + { + GraphicsUnit u = GraphicsUnit.Pixel; + + g.DrawImage(back, new Rectangle(0, 0, l, t), new Rectangle(0, 0, l, t), u); + g.DrawImage(back, new Rectangle(l, 0, width - l - r, t), new Rectangle(l, 0, back.Width - l - r, t), u); + g.DrawImage(back, new Rectangle(width - r, 0, r, t), new Rectangle(back.Width - r, 0, r, t), u); + + g.DrawImage(back, new Rectangle(0, t, l, height - t - b), new Rectangle(0, t, l, back.Height - t - b), u); + g.DrawImage(back, new Rectangle(l, t, width - l - r, height - t - b), new Rectangle(l, t, back.Width - l - r, back.Height - t - b), u); + g.DrawImage(back, new Rectangle(width - r, t, r, height - t - b), new Rectangle(back.Width - r, t, r, back.Height - t - b), u); + + g.DrawImage(back, new Rectangle(0, height - b, l, b), new Rectangle(0, back.Height - b, l, b), u); + g.DrawImage(back, new Rectangle(l, height - b, width - l - r, b), new Rectangle(l, back.Height - b, back.Width - l - r, b), u); + g.DrawImage(back, new Rectangle(width - r, height - b, r, b), new Rectangle(back.Width - r, back.Height - b, r, b), u); + } + + private void DrawBackground(Graphics g) + { + int w = Size.Width; + int h = Size.Height; + + if (w != _background.Width || h != _background.Height) + { + _background.Dispose(); + _background = new Bitmap(w, h, PixelFormat.Format32bppPArgb); + + using (Graphics graphics = Graphics.FromImage(_background)) + { + DrawImageWidthBorder(graphics, w, h, _back, TopBorder, BottomBorder,LeftBorder, RightBorder); + + if (_fore != null) + DrawImageWidthBorder(graphics, w, h, _fore, TopBorder, BottomBorder, LeftBorder, RightBorder); + + if (_image != null) { - DrawImageWidthBorder(graphics, w, h, _back, TopBorder, BottomBorder,LeftBorder, RightBorder); + int width = w - LeftBorder - RightBorder; + int height = h - TopBorder - BottomBorder; + float xRatio = width / (float)_image.Width; + float yRatio = height / (float)_image.Height; + float destWidth, destHeight; + float xOffset, yOffset; - if (_fore != null) - DrawImageWidthBorder(graphics, w, h, _fore, TopBorder, BottomBorder, LeftBorder, RightBorder); - - if (_image != null) + if (xRatio < yRatio) { - int width = w - LeftBorder - RightBorder; - int height = h - TopBorder - BottomBorder; - float xRatio = width / (float)_image.Width; - float yRatio = height / (float)_image.Height; - float destWidth, destHeight; - float xOffset, yOffset; - - if (xRatio < yRatio) - { - destWidth = width; - destHeight = _image.Height * xRatio; - xOffset = 0; - yOffset = 0.5f * (height - destHeight); - } - else - { - destWidth = _image.Width * yRatio; - destHeight = height; - xOffset = 0.5f * (width - destWidth); - yOffset = 0; - } - - graphics.DrawImage(_image, new RectangleF(LeftBorder + xOffset, TopBorder + yOffset, destWidth, destHeight)); - } - } - } - - g.DrawImageUnscaled(_background, 0, 0); - } - - private void DrawProgress(Graphics g, float x, float y, float width, float height, float progress) - { - g.DrawImage(_barBack, - new RectangleF(x + width * progress, y, width * (1 - progress), height), - new RectangleF(_barBack.Width * progress, 0, (1 - progress) * _barBack.Width, _barBack.Height), - GraphicsUnit.Pixel); - g.DrawImage(_barFore, - new RectangleF(x, y, width * progress, height), - new RectangleF(0, 0, progress * _barFore.Width, _barFore.Height), GraphicsUnit.Pixel); - } - - protected override void OnPaint(PaintEventArgs e) - { - Graphics g = e.Graphics; - int w = Size.Width; - - g.Clear(Color.Transparent); - DrawBackground(g); - - int x; - int y = _topMargin; - - if (_sensors.Count == 0) - { - x = LeftBorder + 1; - g.DrawString("Right-click on a sensor in the main window and select " + - "\"Show in Gadget\" to show the sensor here.", - _smallFont, _textBrush, - new Rectangle(x, y - 1, w - RightBorder - x, 0)); - } - - foreach (KeyValuePair> pair in _sensors) - { - if (_hardwareNames.Value) - { - if (y > _topMargin) - y += _hardwareLineHeight - _sensorLineHeight; - x = LeftBorder + 1; - g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType), new Rectangle(x, y + 1, _iconSize, _iconSize)); - x += _iconSize + 1; - g.DrawString(pair.Key.Name, _largeFont, _textBrush, new Rectangle(x, y - 1, w - RightBorder - x, 0), _stringFormat); - y += _hardwareLineHeight; - } - - foreach (ISensor sensor in pair.Value) - { - int remainingWidth; - - - if ((sensor.SensorType != SensorType.Load && - sensor.SensorType != SensorType.Control && - sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) - { - string formatted; - - if (sensor.Value.HasValue) - { - string format = ""; - switch (sensor.SensorType) - { - case SensorType.Voltage: - format = "{0:F3} V"; - break; - case SensorType.Current: - format = "{0:F3} A"; - break; - case SensorType.Clock: - format = "{0:F0} MHz"; - break; - case SensorType.Frequency: - format = "{0:F0} Hz"; - break; - case SensorType.Temperature: - format = "{0:F1} °C"; - break; - case SensorType.Fan: - format = "{0:F0} RPM"; - break; - case SensorType.Flow: - format = "{0:F0} L/h"; - break; - case SensorType.Power: - format = "{0:F1} W"; - break; - case SensorType.Data: - format = "{0:F1} GB"; - break; - case SensorType.SmallData: - format = "{0:F0} MB"; - break; - case SensorType.Factor: - format = "{0:F3}"; - break; - case SensorType.TimeSpan: - format = "{0:g}"; - break; - case SensorType.Energy: - format = "{0:F0} mWh"; - break; - case SensorType.Noise: - format = "{0:F0} dBA"; - break; - } - - if (sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) - { - formatted = $"{UnitManager.CelsiusToFahrenheit(sensor.Value):F1} °F"; - } - else if (sensor.SensorType == SensorType.Throughput) - { - string result; - switch (sensor.Name) - { - case "Connection Speed": - { - switch (sensor.Value) - { - case 100000000: - result = "100Mbps"; - break; - case 1000000000: - result = "1Gbps"; - break; - default: - { - if (sensor.Value < 1024) - result = $"{sensor.Value:F0} bps"; - else if (sensor.Value < 1048576) - result = $"{sensor.Value / 1024:F1} Kbps"; - else if (sensor.Value < 1073741824) - result = $"{sensor.Value / 1048576:F1} Mbps"; - else - result = $"{sensor.Value / 1073741824:F1} Gbps"; - } - break; - } - } - break; - default: - { - if (sensor.Value < 1048576) - result = $"{sensor.Value / 1024:F1} KB/s"; - else - result = $"{sensor.Value / 1048576:F1} MB/s"; - } - break; - } - formatted = result; - } - else if (sensor.SensorType == SensorType.TimeSpan) - { - formatted = string.Format(format, TimeSpan.FromSeconds(sensor.Value.Value)); - } - else - { - formatted = string.Format(format, sensor.Value); - } - } - else - { - formatted = "-"; - } - - g.DrawString(formatted, _smallFont, _textBrush, new RectangleF(-1, y - 1, w - _rightMargin + 3, 0), _alignRightStringFormat); - - remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted, _smallFont, w, StringFormat.GenericTypographic).Width) - _rightMargin; + destWidth = width; + destHeight = _image.Height * xRatio; + xOffset = 0; + yOffset = 0.5f * (height - destHeight); } else { - DrawProgress(g, w - _progressWidth - _rightMargin, y + 0.35f * _sensorLineHeight, _progressWidth, 0.6f * _sensorLineHeight, 0.01f * sensor.Value.Value); - remainingWidth = w - _progressWidth - _rightMargin; + destWidth = _image.Width * yRatio; + destHeight = height; + xOffset = 0.5f * (width - destWidth); + yOffset = 0; } - remainingWidth -= _leftMargin + 2; - if (remainingWidth > 0) - { - g.DrawString(sensor.Name, _smallFont, _textBrush, new RectangleF(_leftMargin - 1, y - 1, remainingWidth, 0), _trimStringFormat); - } - y += _sensorLineHeight; + graphics.DrawImage(_image, new RectangleF(LeftBorder + xOffset, TopBorder + yOffset, destWidth, destHeight)); } } } - private class HardwareComparer : IComparer + g.DrawImageUnscaled(_background, 0, 0); + } + + private void DrawProgress(Graphics g, float x, float y, float width, float height, float progress) + { + g.DrawImage(_barBack, + new RectangleF(x + width * progress, y, width * (1 - progress), height), + new RectangleF(_barBack.Width * progress, 0, (1 - progress) * _barBack.Width, _barBack.Height), + GraphicsUnit.Pixel); + g.DrawImage(_barFore, + new RectangleF(x, y, width * progress, height), + new RectangleF(0, 0, progress * _barFore.Width, _barFore.Height), GraphicsUnit.Pixel); + } + + protected override void OnPaint(PaintEventArgs e) + { + Graphics g = e.Graphics; + int w = Size.Width; + + g.Clear(Color.Transparent); + DrawBackground(g); + + int x; + int y = _topMargin; + + if (_sensors.Count == 0) { - public int Compare(IHardware x, IHardware y) + x = LeftBorder + 1; + g.DrawString("Right-click on a sensor in the main window and select " + + "\"Show in Gadget\" to show the sensor here.", + _smallFont, _textBrush, + new Rectangle(x, y - 1, w - RightBorder - x, 0)); + } + + foreach (KeyValuePair> pair in _sensors) + { + if (_hardwareNames.Value) { - switch (x) + if (y > _topMargin) + y += _hardwareLineHeight - _sensorLineHeight; + x = LeftBorder + 1; + g.DrawImage(HardwareTypeImage.Instance.GetImage(pair.Key.HardwareType), new Rectangle(x, y + 1, _iconSize, _iconSize)); + x += _iconSize + 1; + g.DrawString(pair.Key.Name, _largeFont, _textBrush, new Rectangle(x, y - 1, w - RightBorder - x, 0), _stringFormat); + y += _hardwareLineHeight; + } + + foreach (ISensor sensor in pair.Value) + { + int remainingWidth; + + + if ((sensor.SensorType != SensorType.Load && + sensor.SensorType != SensorType.Control && + sensor.SensorType != SensorType.Level) || !sensor.Value.HasValue) { - case null when y == null: - return 0; - case null: - return -1; + string formatted; + + if (sensor.Value.HasValue) + { + string format = ""; + switch (sensor.SensorType) + { + case SensorType.Voltage: + format = "{0:F3} V"; + break; + case SensorType.Current: + format = "{0:F3} A"; + break; + case SensorType.Clock: + format = "{0:F0} MHz"; + break; + case SensorType.Frequency: + format = "{0:F0} Hz"; + break; + case SensorType.Temperature: + format = "{0:F1} °C"; + break; + case SensorType.Fan: + format = "{0:F0} RPM"; + break; + case SensorType.Flow: + format = "{0:F0} L/h"; + break; + case SensorType.Power: + format = "{0:F1} W"; + break; + case SensorType.Data: + format = "{0:F1} GB"; + break; + case SensorType.SmallData: + format = "{0:F0} MB"; + break; + case SensorType.Factor: + format = "{0:F3}"; + break; + case SensorType.TimeSpan: + format = "{0:g}"; + break; + case SensorType.Energy: + format = "{0:F0} mWh"; + break; + case SensorType.Noise: + format = "{0:F0} dBA"; + break; + } + + if (sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) + { + formatted = $"{UnitManager.CelsiusToFahrenheit(sensor.Value):F1} °F"; + } + else if (sensor.SensorType == SensorType.Throughput) + { + string result; + switch (sensor.Name) + { + case "Connection Speed": + { + switch (sensor.Value) + { + case 100000000: + result = "100Mbps"; + break; + case 1000000000: + result = "1Gbps"; + break; + default: + { + if (sensor.Value < 1024) + result = $"{sensor.Value:F0} bps"; + else if (sensor.Value < 1048576) + result = $"{sensor.Value / 1024:F1} Kbps"; + else if (sensor.Value < 1073741824) + result = $"{sensor.Value / 1048576:F1} Mbps"; + else + result = $"{sensor.Value / 1073741824:F1} Gbps"; + } + break; + } + } + break; + default: + { + if (sensor.Value < 1048576) + result = $"{sensor.Value / 1024:F1} KB/s"; + else + result = $"{sensor.Value / 1048576:F1} MB/s"; + } + break; + } + formatted = result; + } + else if (sensor.SensorType == SensorType.TimeSpan) + { + formatted = string.Format(format, TimeSpan.FromSeconds(sensor.Value.Value)); + } + else + { + formatted = string.Format(format, sensor.Value); + } + } + else + { + formatted = "-"; + } + + g.DrawString(formatted, _smallFont, _textBrush, new RectangleF(-1, y - 1, w - _rightMargin + 3, 0), _alignRightStringFormat); + + remainingWidth = w - (int)Math.Floor(g.MeasureString(formatted, _smallFont, w, StringFormat.GenericTypographic).Width) - _rightMargin; + } + else + { + DrawProgress(g, w - _progressWidth - _rightMargin, y + 0.35f * _sensorLineHeight, _progressWidth, 0.6f * _sensorLineHeight, 0.01f * sensor.Value.Value); + remainingWidth = w - _progressWidth - _rightMargin; } - if (y == null) - return 1; - - if (x.HardwareType != y.HardwareType) - return x.HardwareType.CompareTo(y.HardwareType); - - return x.Identifier.CompareTo(y.Identifier); + remainingWidth -= _leftMargin + 2; + if (remainingWidth > 0) + { + g.DrawString(sensor.Name, _smallFont, _textBrush, new RectangleF(_leftMargin - 1, y - 1, remainingWidth, 0), _trimStringFormat); + } + y += _sensorLineHeight; } } } -} + private class HardwareComparer : IComparer + { + public int Compare(IHardware x, IHardware y) + { + switch (x) + { + case null when y == null: + return 0; + case null: + return -1; + } + + if (y == null) + return 1; + + if (x.HardwareType != y.HardwareType) + return x.HardwareType.CompareTo(y.HardwareType); + + return x.Identifier.CompareTo(y.Identifier); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/SensorNode.cs b/LibreHardwareMonitor/UI/SensorNode.cs index 918002b..d1335fd 100644 --- a/LibreHardwareMonitor/UI/SensorNode.cs +++ b/LibreHardwareMonitor/UI/SensorNode.cs @@ -11,270 +11,269 @@ using System.Text; using LibreHardwareMonitor.Hardware; using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class SensorNode : Node { - public class SensorNode : Node + private readonly PersistentSettings _settings; + private readonly UnitManager _unitManager; + private Color? _penColor; + private bool _plot; + + public SensorNode(ISensor sensor, PersistentSettings settings, UnitManager unitManager) { - private readonly PersistentSettings _settings; - private readonly UnitManager _unitManager; - private Color? _penColor; - private bool _plot; + Sensor = sensor; + _settings = settings; + _unitManager = unitManager; - public SensorNode(ISensor sensor, PersistentSettings settings, UnitManager unitManager) + switch (sensor.SensorType) { - Sensor = sensor; - _settings = settings; - _unitManager = unitManager; - - switch (sensor.SensorType) - { - case SensorType.Voltage: - Format = "{0:F3} V"; - break; - case SensorType.Current: - Format = "{0:F3} A"; - break; - case SensorType.Clock: - Format = "{0:F1} MHz"; - break; - case SensorType.Load: - Format = "{0:F1} %"; - break; - case SensorType.Temperature: - Format = "{0:F1} °C"; - break; - case SensorType.Fan: - Format = "{0:F0} RPM"; - break; - case SensorType.Flow: - Format = "{0:F1} L/h"; - break; - case SensorType.Control: - Format = "{0:F1} %"; - break; - case SensorType.Level: - Format = "{0:F1} %"; - break; - case SensorType.Power: - Format = "{0:F1} W"; - break; - case SensorType.Data: - Format = "{0:F1} GB"; - break; - case SensorType.SmallData: - Format = "{0:F1} MB"; - break; - case SensorType.Factor: - Format = "{0:F3}"; - break; - case SensorType.Frequency: - Format = "{0:F1} Hz"; - break; - case SensorType.Throughput: - Format = "{0:F1} B/s"; - break; - case SensorType.TimeSpan: - Format = "{0:g}"; - break; - case SensorType.Energy: - Format = "{0:F0} mWh"; - break; - case SensorType.Noise: - Format = "{0:F0} dBA"; - break; - } - - bool hidden = settings.GetValue(new Identifier(sensor.Identifier, "hidden").ToString(), sensor.IsDefaultHidden); - base.IsVisible = !hidden; - Plot = settings.GetValue(new Identifier(sensor.Identifier, "plot").ToString(), false); - string id = new Identifier(sensor.Identifier, "penColor").ToString(); - - if (settings.Contains(id)) - PenColor = settings.GetValue(id, Color.Black); + case SensorType.Voltage: + Format = "{0:F3} V"; + break; + case SensorType.Current: + Format = "{0:F3} A"; + break; + case SensorType.Clock: + Format = "{0:F1} MHz"; + break; + case SensorType.Load: + Format = "{0:F1} %"; + break; + case SensorType.Temperature: + Format = "{0:F1} °C"; + break; + case SensorType.Fan: + Format = "{0:F0} RPM"; + break; + case SensorType.Flow: + Format = "{0:F1} L/h"; + break; + case SensorType.Control: + Format = "{0:F1} %"; + break; + case SensorType.Level: + Format = "{0:F1} %"; + break; + case SensorType.Power: + Format = "{0:F1} W"; + break; + case SensorType.Data: + Format = "{0:F1} GB"; + break; + case SensorType.SmallData: + Format = "{0:F1} MB"; + break; + case SensorType.Factor: + Format = "{0:F3}"; + break; + case SensorType.Frequency: + Format = "{0:F1} Hz"; + break; + case SensorType.Throughput: + Format = "{0:F1} B/s"; + break; + case SensorType.TimeSpan: + Format = "{0:g}"; + break; + case SensorType.Energy: + Format = "{0:F0} mWh"; + break; + case SensorType.Noise: + Format = "{0:F0} dBA"; + break; } - public event EventHandler PlotSelectionChanged; + bool hidden = settings.GetValue(new Identifier(sensor.Identifier, "hidden").ToString(), sensor.IsDefaultHidden); + base.IsVisible = !hidden; + Plot = settings.GetValue(new Identifier(sensor.Identifier, "plot").ToString(), false); + string id = new Identifier(sensor.Identifier, "penColor").ToString(); - public string Format { get; set; } = ""; + if (settings.Contains(id)) + PenColor = settings.GetValue(id, Color.Black); + } - public override bool IsVisible + public event EventHandler PlotSelectionChanged; + + public string Format { get; set; } = ""; + + public override bool IsVisible + { + get { return base.IsVisible; } + set { - get { return base.IsVisible; } - set - { - base.IsVisible = value; - _settings.SetValue(new Identifier(Sensor.Identifier, "hidden").ToString(), !value); - } + base.IsVisible = value; + _settings.SetValue(new Identifier(Sensor.Identifier, "hidden").ToString(), !value); } + } - public string Max + public string Max + { + get { return ValueToString(Sensor.Max); } + } + + public string Min + { + get { return ValueToString(Sensor.Min); } + } + + public Color? PenColor + { + get { return _penColor; } + set { - get { return ValueToString(Sensor.Max); } - } + _penColor = value; - public string Min - { - get { return ValueToString(Sensor.Min); } - } - - public Color? PenColor - { - get { return _penColor; } - set - { - _penColor = value; - - string id = new Identifier(Sensor.Identifier, "penColor").ToString(); - if (value.HasValue) - _settings.SetValue(id, value.Value); - else - _settings.Remove(id); - - PlotSelectionChanged?.Invoke(this, null); - } - } - - public bool Plot - { - get { return _plot; } - set - { - _plot = value; - _settings.SetValue(new Identifier(Sensor.Identifier, "plot").ToString(), value); - PlotSelectionChanged?.Invoke(this, null); - } - } - - public ISensor Sensor { get; } - - public override string Text - { - get { return Sensor.Name; } - set { Sensor.Name = value; } - } - - public override string ToolTip - { - get - { - StringBuilder stringBuilder = new(); - - if (Sensor is ICriticalSensorLimits criticalSensorLimits) - OptionallyAppendCriticalRange(stringBuilder, criticalSensorLimits.CriticalLowLimit, criticalSensorLimits.CriticalHighLimit, "critical"); - - if (Sensor is ISensorLimits sensorLimits) - OptionallyAppendCriticalRange(stringBuilder, sensorLimits.LowLimit, sensorLimits.HighLimit, "normal"); - - return stringBuilder.ToString(); - } - } - - public string Value - { - get { return ValueToString(Sensor.Value); } - } - - public string ValueToString(float? value) - { + string id = new Identifier(Sensor.Identifier, "penColor").ToString(); if (value.HasValue) + _settings.SetValue(id, value.Value); + else + _settings.Remove(id); + + PlotSelectionChanged?.Invoke(this, null); + } + } + + public bool Plot + { + get { return _plot; } + set + { + _plot = value; + _settings.SetValue(new Identifier(Sensor.Identifier, "plot").ToString(), value); + PlotSelectionChanged?.Invoke(this, null); + } + } + + public ISensor Sensor { get; } + + public override string Text + { + get { return Sensor.Name; } + set { Sensor.Name = value; } + } + + public override string ToolTip + { + get + { + StringBuilder stringBuilder = new(); + + if (Sensor is ICriticalSensorLimits criticalSensorLimits) + OptionallyAppendCriticalRange(stringBuilder, criticalSensorLimits.CriticalLowLimit, criticalSensorLimits.CriticalHighLimit, "critical"); + + if (Sensor is ISensorLimits sensorLimits) + OptionallyAppendCriticalRange(stringBuilder, sensorLimits.LowLimit, sensorLimits.HighLimit, "normal"); + + return stringBuilder.ToString(); + } + } + + public string Value + { + get { return ValueToString(Sensor.Value); } + } + + public string ValueToString(float? value) + { + if (value.HasValue) + { + switch (Sensor.SensorType) { - switch (Sensor.SensorType) - { - case SensorType.Temperature when _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit: + case SensorType.Temperature when _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit: { return $"{value * 1.8 + 32:F1} °F"; } - case SensorType.Throughput: + case SensorType.Throughput: { string result; switch (Sensor.Name) { case "Connection Speed": - { - switch (value) { - case 100000000: + switch (value) { - result = "100Mbps"; - break; - } - case 1000000000: - { - result = "1Gbps"; - break; - } - default: - { - if (value < 1024) - result = $"{value:F0} bps"; - else if (value < 1048576) - result = $"{value / 1024:F1} Kbps"; - else if (value < 1073741824) - result = $"{value / 1048576:F1} Mbps"; - else - result = $"{value / 1073741824:F1} Gbps"; + case 100000000: + { + result = "100Mbps"; + break; + } + case 1000000000: + { + result = "1Gbps"; + break; + } + default: + { + if (value < 1024) + result = $"{value:F0} bps"; + else if (value < 1048576) + result = $"{value / 1024:F1} Kbps"; + else if (value < 1073741824) + result = $"{value / 1048576:F1} Mbps"; + else + result = $"{value / 1073741824:F1} Gbps"; + } + + break; } break; } - - break; - } default: - { - const int _1MB = 1048576; + { + const int _1MB = 1048576; - result = value < _1MB ? $"{value / 1024:F1} KB/s" : $"{value / _1MB:F1} MB/s"; + result = value < _1MB ? $"{value / 1024:F1} KB/s" : $"{value / _1MB:F1} MB/s"; - break; - } + break; + } } return result; } - case SensorType.TimeSpan: + case SensorType.TimeSpan: { return value.HasValue ? string.Format(Format, TimeSpan.FromSeconds(value.Value)) : "-"; } - default: + default: { return string.Format(Format, value); } - } - } - - return "-"; - } - - private void OptionallyAppendCriticalRange(StringBuilder str, float? min, float? max, string kind) - { - if (min.HasValue) - { - str.AppendLine(max.HasValue - ? $"{CultureInfo.CurrentUICulture.TextInfo.ToTitleCase(kind)} range: {ValueToString(min)} to {ValueToString(max)}." - : $"Minimal {kind} value: {ValueToString(min)}."); - } - else if (max.HasValue) - { - str.AppendLine($"Maximal {kind} value: {ValueToString(max)}."); } } - public override bool Equals(object obj) + return "-"; + } + + private void OptionallyAppendCriticalRange(StringBuilder str, float? min, float? max, string kind) + { + if (min.HasValue) { - if (obj == null) - return false; - - if (!(obj is SensorNode s)) - return false; - - - return (Sensor == s.Sensor); + str.AppendLine(max.HasValue + ? $"{CultureInfo.CurrentUICulture.TextInfo.ToTitleCase(kind)} range: {ValueToString(min)} to {ValueToString(max)}." + : $"Minimal {kind} value: {ValueToString(min)}."); } - - public override int GetHashCode() + else if (max.HasValue) { - return Sensor.GetHashCode(); + str.AppendLine($"Maximal {kind} value: {ValueToString(max)}."); } } -} + + public override bool Equals(object obj) + { + if (obj == null) + return false; + + if (!(obj is SensorNode s)) + return false; + + + return (Sensor == s.Sensor); + } + + public override int GetHashCode() + { + return Sensor.GetHashCode(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/SensorNotifyIcon.cs b/LibreHardwareMonitor/UI/SensorNotifyIcon.cs index ec4fdf2..d622a76 100644 --- a/LibreHardwareMonitor/UI/SensorNotifyIcon.cs +++ b/LibreHardwareMonitor/UI/SensorNotifyIcon.cs @@ -14,268 +14,267 @@ using System.Windows.Forms; using LibreHardwareMonitor.Hardware; using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class SensorNotifyIcon : IDisposable { - public class SensorNotifyIcon : IDisposable + private readonly UnitManager _unitManager; + private readonly NotifyIconAdv _notifyIcon; + private readonly Bitmap _bitmap; + private readonly Graphics _graphics; + private Color _color; + private Color _darkColor; + private Brush _brush; + private Brush _darkBrush; + private readonly Pen _pen; + private readonly Font _font; + private readonly Font _smallFont; + + public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor, PersistentSettings settings, UnitManager unitManager) { - private readonly UnitManager _unitManager; - private readonly NotifyIconAdv _notifyIcon; - private readonly Bitmap _bitmap; - private readonly Graphics _graphics; - private Color _color; - private Color _darkColor; - private Brush _brush; - private Brush _darkBrush; - private readonly Pen _pen; - private readonly Font _font; - private readonly Font _smallFont; + _unitManager = unitManager; + Sensor = sensor; + _notifyIcon = new NotifyIconAdv(); - public SensorNotifyIcon(SystemTray sensorSystemTray, ISensor sensor, PersistentSettings settings, UnitManager unitManager) + Color defaultColor = Color.White; + if (sensor.SensorType == SensorType.Load || sensor.SensorType == SensorType.Control || sensor.SensorType == SensorType.Level) + defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1); + + Color = settings.GetValue(new Identifier(sensor.Identifier, "traycolor").ToString(), defaultColor); + + _pen = new Pen(Color.FromArgb(96, Color.Black)); + ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); + ToolStripItem hideShowItem = new ToolStripMenuItem("Hide/Show"); + hideShowItem.Click += delegate { - _unitManager = unitManager; - Sensor = sensor; - _notifyIcon = new NotifyIconAdv(); - - Color defaultColor = Color.White; - if (sensor.SensorType == SensorType.Load || sensor.SensorType == SensorType.Control || sensor.SensorType == SensorType.Level) - defaultColor = Color.FromArgb(0xff, 0x70, 0x8c, 0xf1); - - Color = settings.GetValue(new Identifier(sensor.Identifier, "traycolor").ToString(), defaultColor); - - _pen = new Pen(Color.FromArgb(96, Color.Black)); - ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); - ToolStripItem hideShowItem = new ToolStripMenuItem("Hide/Show"); - hideShowItem.Click += delegate + sensorSystemTray.SendHideShowCommand(); + }; + contextMenuStrip.Items.Add(hideShowItem); + contextMenuStrip.Items.Add(new ToolStripSeparator()); + ToolStripItem removeItem = new ToolStripMenuItem("Remove Sensor"); + removeItem.Click += delegate + { + sensorSystemTray.Remove(Sensor); + }; + contextMenuStrip.Items.Add(removeItem); + ToolStripItem colorItem = new ToolStripMenuItem("Change Color..."); + colorItem.Click += delegate + { + ColorDialog dialog = new ColorDialog { Color = Color }; + if (dialog.ShowDialog() == DialogResult.OK) { - sensorSystemTray.SendHideShowCommand(); - }; - contextMenuStrip.Items.Add(hideShowItem); - contextMenuStrip.Items.Add(new ToolStripSeparator()); - ToolStripItem removeItem = new ToolStripMenuItem("Remove Sensor"); - removeItem.Click += delegate - { - sensorSystemTray.Remove(Sensor); - }; - contextMenuStrip.Items.Add(removeItem); - ToolStripItem colorItem = new ToolStripMenuItem("Change Color..."); - colorItem.Click += delegate - { - ColorDialog dialog = new ColorDialog { Color = Color }; - if (dialog.ShowDialog() == DialogResult.OK) - { - Color = dialog.Color; - settings.SetValue(new Identifier(sensor.Identifier, - "traycolor").ToString(), Color); - } - }; - contextMenuStrip.Items.Add(colorItem); - contextMenuStrip.Items.Add(new ToolStripSeparator()); - ToolStripItem exitItem = new ToolStripMenuItem("Exit"); - exitItem.Click += delegate - { - sensorSystemTray.SendExitCommand(); - }; - contextMenuStrip.Items.Add(exitItem); - _notifyIcon.ContextMenuStrip = contextMenuStrip; - _notifyIcon.DoubleClick += delegate - { - sensorSystemTray.SendHideShowCommand(); - }; - - // get the default dpi to create an icon with the correct size - float dpiX, dpiY; - using (Bitmap b = new Bitmap(1, 1, PixelFormat.Format32bppArgb)) - { - dpiX = b.HorizontalResolution; - dpiY = b.VerticalResolution; + Color = dialog.Color; + settings.SetValue(new Identifier(sensor.Identifier, + "traycolor").ToString(), Color); } + }; + contextMenuStrip.Items.Add(colorItem); + contextMenuStrip.Items.Add(new ToolStripSeparator()); + ToolStripItem exitItem = new ToolStripMenuItem("Exit"); + exitItem.Click += delegate + { + sensorSystemTray.SendExitCommand(); + }; + contextMenuStrip.Items.Add(exitItem); + _notifyIcon.ContextMenuStrip = contextMenuStrip; + _notifyIcon.DoubleClick += delegate + { + sensorSystemTray.SendHideShowCommand(); + }; - // adjust the size of the icon to current dpi (default is 16x16 at 96 dpi) - int width = (int)Math.Round(16 * dpiX / 96); - int height = (int)Math.Round(16 * dpiY / 96); - - // make sure it does never get smaller than 16x16 - width = width < 16 ? 16 : width; - height = height < 16 ? 16 : height; - - // adjust the font size to the icon size - FontFamily family = SystemFonts.MessageBoxFont.FontFamily; - float baseSize; - switch (family.Name) - { - case "Segoe UI": baseSize = 12; break; - case "Tahoma": baseSize = 11; break; - default: baseSize = 12; break; - } - - _font = new Font(family, baseSize * width / 16.0f, GraphicsUnit.Pixel); - _smallFont = new Font(family, 0.75f * baseSize * width / 16.0f, GraphicsUnit.Pixel); - - _bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); - _graphics = Graphics.FromImage(_bitmap); - if (Environment.OSVersion.Version.Major > 5) - { - _graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; - _graphics.SmoothingMode = SmoothingMode.HighQuality; - } + // get the default dpi to create an icon with the correct size + float dpiX, dpiY; + using (Bitmap b = new Bitmap(1, 1, PixelFormat.Format32bppArgb)) + { + dpiX = b.HorizontalResolution; + dpiY = b.VerticalResolution; } - public ISensor Sensor { get; } + // adjust the size of the icon to current dpi (default is 16x16 at 96 dpi) + int width = (int)Math.Round(16 * dpiX / 96); + int height = (int)Math.Round(16 * dpiY / 96); - public Color Color + // make sure it does never get smaller than 16x16 + width = width < 16 ? 16 : width; + height = height < 16 ? 16 : height; + + // adjust the font size to the icon size + FontFamily family = SystemFonts.MessageBoxFont.FontFamily; + float baseSize; + switch (family.Name) { - get { return _color; } - set - { - _color = value; - _darkColor = Color.FromArgb(255, _color.R / 3, _color.G / 3, _color.B / 3); - Brush brush = _brush; - _brush = new SolidBrush(_color); - brush?.Dispose(); - Brush darkBrush = _darkBrush; - _darkBrush = new SolidBrush(_darkColor); - darkBrush?.Dispose(); - } + case "Segoe UI": baseSize = 12; break; + case "Tahoma": baseSize = 11; break; + default: baseSize = 12; break; } - public void Dispose() + _font = new Font(family, baseSize * width / 16.0f, GraphicsUnit.Pixel); + _smallFont = new Font(family, 0.75f * baseSize * width / 16.0f, GraphicsUnit.Pixel); + + _bitmap = new Bitmap(width, height, PixelFormat.Format32bppArgb); + _graphics = Graphics.FromImage(_bitmap); + if (Environment.OSVersion.Version.Major > 5) { - Icon icon = _notifyIcon.Icon; - _notifyIcon.Icon = null; - icon?.Destroy(); - _notifyIcon.Dispose(); - - _brush?.Dispose(); - _darkBrush?.Dispose(); - _pen.Dispose(); - _graphics.Dispose(); - _bitmap.Dispose(); - _font.Dispose(); - _smallFont.Dispose(); - } - - private string GetString() - { - if (!Sensor.Value.HasValue) - return "-"; - - switch (Sensor.SensorType) - { - case SensorType.Temperature: - return _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit ? $"{UnitManager.CelsiusToFahrenheit(Sensor.Value):F0}" : $"{Sensor.Value:F0}"; - case SensorType.TimeSpan: - return $"{TimeSpan.FromSeconds(Sensor.Value.Value):g}"; - case SensorType.Clock: - case SensorType.Fan: - case SensorType.Flow: - return $"{1e-3f * Sensor.Value:F1}"; - case SensorType.Voltage: - case SensorType.Current: - case SensorType.SmallData: - case SensorType.Factor: - case SensorType.Throughput: - return $"{Sensor.Value:F1}"; - case SensorType.Control: - case SensorType.Frequency: - case SensorType.Level: - case SensorType.Power: - case SensorType.Data: - case SensorType.Load: - case SensorType.Energy: - case SensorType.Noise: - return $"{Sensor.Value:F0}"; - default: - return "-"; - } - } - - private Icon CreateTransparentIcon() - { - string text = GetString(); - int count = 0; - for (int i = 0; i < text.Length; i++) - if ((text[i] >= '0' && text[i] <= '9') || text[i] == '-') - count++; - bool small = count > 2; - - _graphics.Clear(Color.Transparent); - Rectangle bounds = new Rectangle(Point.Empty, _bitmap.Size); - TextRenderer.DrawText(_graphics, text, small ? _smallFont : _font, bounds, _color, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); - - return IconFactory.Create(_bitmap); - } - - private Icon CreatePercentageIcon() - { - try - { - _graphics.Clear(Color.Transparent); - } - catch (ArgumentException) - { - _graphics.Clear(Color.Black); - } - _graphics.FillRectangle(_darkBrush, 0.5f, -0.5f, _bitmap.Width - 2, _bitmap.Height); - float value = Sensor.Value.GetValueOrDefault(); - float y = (float)(_bitmap.Height * 0.01f) * (100 - value); - _graphics.FillRectangle(_brush, 0.5f, -0.5f + y, _bitmap.Width - 2, _bitmap.Height - y); - _graphics.DrawRectangle(_pen, 1, 0, _bitmap.Width - 3, _bitmap.Height - 1); - - return IconFactory.Create(_bitmap); - } - - public void Update() - { - Icon icon = _notifyIcon.Icon; - - switch (Sensor.SensorType) - { - case SensorType.Load: - case SensorType.Control: - case SensorType.Level: - _notifyIcon.Icon = CreatePercentageIcon(); - break; - default: - _notifyIcon.Icon = CreateTransparentIcon(); - break; - } - - icon?.Destroy(); - - string format = ""; - switch (Sensor.SensorType) - { - case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break; - case SensorType.Current: format = "\n{0}: {1:F2} A"; break; - case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break; - case SensorType.Load: format = "\n{0}: {1:F1} %"; break; - case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break; - case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break; - case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break; - case SensorType.Control: format = "\n{0}: {1:F1} %"; break; - case SensorType.Level: format = "\n{0}: {1:F1} %"; break; - case SensorType.Power: format = "\n{0}: {1:F0} W"; break; - case SensorType.Data: format = "\n{0}: {1:F0} GB"; break; - case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break; - case SensorType.Energy: format = "\n{0}: {0:F0} mWh"; break; - case SensorType.Noise: format = "\n{0}: {0:F0} dBA"; break; - } - string formattedValue = string.Format(format, Sensor.Name, Sensor.Value); - - if (Sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) - { - format = "\n{0}: {1:F1} °F"; - formattedValue = string.Format(format, Sensor.Name, UnitManager.CelsiusToFahrenheit(Sensor.Value)); - } - - string hardwareName = Sensor.Hardware.Name; - hardwareName = hardwareName.Substring(0, Math.Min(63 - formattedValue.Length, hardwareName.Length)); - string text = hardwareName + formattedValue; - if (text.Length > 63) - text = null; - - _notifyIcon.Text = text; - _notifyIcon.Visible = true; + _graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit; + _graphics.SmoothingMode = SmoothingMode.HighQuality; } } -} + + public ISensor Sensor { get; } + + public Color Color + { + get { return _color; } + set + { + _color = value; + _darkColor = Color.FromArgb(255, _color.R / 3, _color.G / 3, _color.B / 3); + Brush brush = _brush; + _brush = new SolidBrush(_color); + brush?.Dispose(); + Brush darkBrush = _darkBrush; + _darkBrush = new SolidBrush(_darkColor); + darkBrush?.Dispose(); + } + } + + public void Dispose() + { + Icon icon = _notifyIcon.Icon; + _notifyIcon.Icon = null; + icon?.Destroy(); + _notifyIcon.Dispose(); + + _brush?.Dispose(); + _darkBrush?.Dispose(); + _pen.Dispose(); + _graphics.Dispose(); + _bitmap.Dispose(); + _font.Dispose(); + _smallFont.Dispose(); + } + + private string GetString() + { + if (!Sensor.Value.HasValue) + return "-"; + + switch (Sensor.SensorType) + { + case SensorType.Temperature: + return _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit ? $"{UnitManager.CelsiusToFahrenheit(Sensor.Value):F0}" : $"{Sensor.Value:F0}"; + case SensorType.TimeSpan: + return $"{TimeSpan.FromSeconds(Sensor.Value.Value):g}"; + case SensorType.Clock: + case SensorType.Fan: + case SensorType.Flow: + return $"{1e-3f * Sensor.Value:F1}"; + case SensorType.Voltage: + case SensorType.Current: + case SensorType.SmallData: + case SensorType.Factor: + case SensorType.Throughput: + return $"{Sensor.Value:F1}"; + case SensorType.Control: + case SensorType.Frequency: + case SensorType.Level: + case SensorType.Power: + case SensorType.Data: + case SensorType.Load: + case SensorType.Energy: + case SensorType.Noise: + return $"{Sensor.Value:F0}"; + default: + return "-"; + } + } + + private Icon CreateTransparentIcon() + { + string text = GetString(); + int count = 0; + for (int i = 0; i < text.Length; i++) + if ((text[i] >= '0' && text[i] <= '9') || text[i] == '-') + count++; + bool small = count > 2; + + _graphics.Clear(Color.Transparent); + Rectangle bounds = new Rectangle(Point.Empty, _bitmap.Size); + TextRenderer.DrawText(_graphics, text, small ? _smallFont : _font, bounds, _color, Color.Transparent, TextFormatFlags.HorizontalCenter | TextFormatFlags.VerticalCenter); + + return IconFactory.Create(_bitmap); + } + + private Icon CreatePercentageIcon() + { + try + { + _graphics.Clear(Color.Transparent); + } + catch (ArgumentException) + { + _graphics.Clear(Color.Black); + } + _graphics.FillRectangle(_darkBrush, 0.5f, -0.5f, _bitmap.Width - 2, _bitmap.Height); + float value = Sensor.Value.GetValueOrDefault(); + float y = (float)(_bitmap.Height * 0.01f) * (100 - value); + _graphics.FillRectangle(_brush, 0.5f, -0.5f + y, _bitmap.Width - 2, _bitmap.Height - y); + _graphics.DrawRectangle(_pen, 1, 0, _bitmap.Width - 3, _bitmap.Height - 1); + + return IconFactory.Create(_bitmap); + } + + public void Update() + { + Icon icon = _notifyIcon.Icon; + + switch (Sensor.SensorType) + { + case SensorType.Load: + case SensorType.Control: + case SensorType.Level: + _notifyIcon.Icon = CreatePercentageIcon(); + break; + default: + _notifyIcon.Icon = CreateTransparentIcon(); + break; + } + + icon?.Destroy(); + + string format = ""; + switch (Sensor.SensorType) + { + case SensorType.Voltage: format = "\n{0}: {1:F2} V"; break; + case SensorType.Current: format = "\n{0}: {1:F2} A"; break; + case SensorType.Clock: format = "\n{0}: {1:F0} MHz"; break; + case SensorType.Load: format = "\n{0}: {1:F1} %"; break; + case SensorType.Temperature: format = "\n{0}: {1:F1} °C"; break; + case SensorType.Fan: format = "\n{0}: {1:F0} RPM"; break; + case SensorType.Flow: format = "\n{0}: {1:F0} L/h"; break; + case SensorType.Control: format = "\n{0}: {1:F1} %"; break; + case SensorType.Level: format = "\n{0}: {1:F1} %"; break; + case SensorType.Power: format = "\n{0}: {1:F0} W"; break; + case SensorType.Data: format = "\n{0}: {1:F0} GB"; break; + case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break; + case SensorType.Energy: format = "\n{0}: {0:F0} mWh"; break; + case SensorType.Noise: format = "\n{0}: {0:F0} dBA"; break; + } + string formattedValue = string.Format(format, Sensor.Name, Sensor.Value); + + if (Sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit) + { + format = "\n{0}: {1:F1} °F"; + formattedValue = string.Format(format, Sensor.Name, UnitManager.CelsiusToFahrenheit(Sensor.Value)); + } + + string hardwareName = Sensor.Hardware.Name; + hardwareName = hardwareName.Substring(0, Math.Min(63 - formattedValue.Length, hardwareName.Length)); + string text = hardwareName + formattedValue; + if (text.Length > 63) + text = null; + + _notifyIcon.Text = text; + _notifyIcon.Visible = true; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/ShowDesktop.cs b/LibreHardwareMonitor/UI/ShowDesktop.cs index 8ee34c0..97d1dbf 100644 --- a/LibreHardwareMonitor/UI/ShowDesktop.cs +++ b/LibreHardwareMonitor/UI/ShowDesktop.cs @@ -8,151 +8,150 @@ using System; using System.Runtime.InteropServices; using System.Windows.Forms; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class ShowDesktop : IDisposable { - public class ShowDesktop : IDisposable + private readonly NativeWindow _referenceWindow; + private readonly string _referenceWindowCaption = "LibreHardwareMonitorShowDesktopReferenceWindow"; + private readonly System.Threading.Timer _timer; + private bool _showDesktop; + + /// + /// Prevents a default instance of the class from being created. + /// + private ShowDesktop() { - private readonly NativeWindow _referenceWindow; - private readonly string _referenceWindowCaption = "LibreHardwareMonitorShowDesktopReferenceWindow"; - private readonly System.Threading.Timer _timer; - private bool _showDesktop; + // Create a reference window to detect show desktop + _referenceWindow = new NativeWindow(); - /// - /// Prevents a default instance of the class from being created. - /// - private ShowDesktop() + CreateParams cp = new CreateParams { ExStyle = GadgetWindow.WS_EX_TOOLWINDOW, Caption = _referenceWindowCaption }; + _referenceWindow.CreateHandle(cp); + NativeMethods.SetWindowPos(_referenceWindow.Handle, + GadgetWindow.HWND_BOTTOM, + 0, + 0, + 0, + 0, + GadgetWindow.SWP_NOMOVE | + GadgetWindow.SWP_NOSIZE | + GadgetWindow.SWP_NOACTIVATE | + GadgetWindow.SWP_NOSENDCHANGING); + + // start a repeated timer to detect "Show Desktop" events + _timer = new System.Threading.Timer(OnTimer, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); + } + + public delegate void ShowDesktopChangedEventHandler(bool showDesktop); + + private event ShowDesktopChangedEventHandler ShowDesktopChangedEvent; + + // notify when the "show desktop" mode is changed + public event ShowDesktopChangedEventHandler ShowDesktopChanged + { + add { - // Create a reference window to detect show desktop - _referenceWindow = new NativeWindow(); + // start the monitor timer when someone is listening + if (ShowDesktopChangedEvent == null) + StartTimer(); - CreateParams cp = new CreateParams { ExStyle = GadgetWindow.WS_EX_TOOLWINDOW, Caption = _referenceWindowCaption }; - _referenceWindow.CreateHandle(cp); - NativeMethods.SetWindowPos(_referenceWindow.Handle, - GadgetWindow.HWND_BOTTOM, - 0, - 0, - 0, - 0, - GadgetWindow.SWP_NOMOVE | - GadgetWindow.SWP_NOSIZE | - GadgetWindow.SWP_NOACTIVATE | - GadgetWindow.SWP_NOSENDCHANGING); - - // start a repeated timer to detect "Show Desktop" events - _timer = new System.Threading.Timer(OnTimer, null, System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); + ShowDesktopChangedEvent += value; } - - public delegate void ShowDesktopChangedEventHandler(bool showDesktop); - - private event ShowDesktopChangedEventHandler ShowDesktopChangedEvent; - - // notify when the "show desktop" mode is changed - public event ShowDesktopChangedEventHandler ShowDesktopChanged + remove { - add - { - // start the monitor timer when someone is listening - if (ShowDesktopChangedEvent == null) - StartTimer(); - - ShowDesktopChangedEvent += value; - } - remove - { - ShowDesktopChangedEvent -= value; - // stop the monitor timer if nobody is interested - if (ShowDesktopChangedEvent == null) - StopTimer(); - } - } - - public static ShowDesktop Instance { get; } = new ShowDesktop(); - - /// - public void Dispose() - { - _timer?.Dispose(); - _referenceWindow.ReleaseHandle(); - } - - private void StartTimer() - { - _timer.Change(0, 200); - } - - private void StopTimer() - { - _timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); - } - - // the desktop worker window (if available) can hide the reference window - private IntPtr GetDesktopWorkerWindow() - { - IntPtr shellWindow = NativeMethods.GetShellWindow(); - if (shellWindow == IntPtr.Zero) - return IntPtr.Zero; - - - NativeMethods.GetWindowThreadProcessId(shellWindow, out int shellId); - - IntPtr workerWindow = IntPtr.Zero; - while ((workerWindow = NativeMethods.FindWindowEx(IntPtr.Zero, workerWindow, "WorkerW", null)) != IntPtr.Zero) - { - NativeMethods.GetWindowThreadProcessId(workerWindow, out int workerId); - if (workerId == shellId) - { - IntPtr window = NativeMethods.FindWindowEx(workerWindow, IntPtr.Zero, "SHELLDLL_DefView", null); - if (window != IntPtr.Zero) - { - IntPtr desktopWindow = NativeMethods.FindWindowEx(window, IntPtr.Zero, "SysListView32", null); - if (desktopWindow != IntPtr.Zero) - return workerWindow; - } - } - } - - return IntPtr.Zero; - } - - private void OnTimer(object state) - { - bool showDesktopDetected; - - IntPtr workerWindow = GetDesktopWorkerWindow(); - if (workerWindow != IntPtr.Zero) - { - // search if the reference window is behind the worker window - IntPtr reference = NativeMethods.FindWindowEx(IntPtr.Zero, workerWindow, null, _referenceWindowCaption); - showDesktopDetected = reference != IntPtr.Zero; - } - else - { - // if there is no worker window, then nothing can hide the reference - showDesktopDetected = false; - } - - if (_showDesktop != showDesktopDetected) - { - _showDesktop = showDesktopDetected; - ShowDesktopChangedEvent?.Invoke(_showDesktop); - } - } - - private static class NativeMethods - { - private const string USER = "user32.dll"; - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern IntPtr GetShellWindow(); - - [DllImport(USER, CallingConvention = CallingConvention.Winapi)] - public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); + ShowDesktopChangedEvent -= value; + // stop the monitor timer if nobody is interested + if (ShowDesktopChangedEvent == null) + StopTimer(); } } -} + + public static ShowDesktop Instance { get; } = new ShowDesktop(); + + /// + public void Dispose() + { + _timer?.Dispose(); + _referenceWindow.ReleaseHandle(); + } + + private void StartTimer() + { + _timer.Change(0, 200); + } + + private void StopTimer() + { + _timer.Change(System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite); + } + + // the desktop worker window (if available) can hide the reference window + private IntPtr GetDesktopWorkerWindow() + { + IntPtr shellWindow = NativeMethods.GetShellWindow(); + if (shellWindow == IntPtr.Zero) + return IntPtr.Zero; + + + NativeMethods.GetWindowThreadProcessId(shellWindow, out int shellId); + + IntPtr workerWindow = IntPtr.Zero; + while ((workerWindow = NativeMethods.FindWindowEx(IntPtr.Zero, workerWindow, "WorkerW", null)) != IntPtr.Zero) + { + NativeMethods.GetWindowThreadProcessId(workerWindow, out int workerId); + if (workerId == shellId) + { + IntPtr window = NativeMethods.FindWindowEx(workerWindow, IntPtr.Zero, "SHELLDLL_DefView", null); + if (window != IntPtr.Zero) + { + IntPtr desktopWindow = NativeMethods.FindWindowEx(window, IntPtr.Zero, "SysListView32", null); + if (desktopWindow != IntPtr.Zero) + return workerWindow; + } + } + } + + return IntPtr.Zero; + } + + private void OnTimer(object state) + { + bool showDesktopDetected; + + IntPtr workerWindow = GetDesktopWorkerWindow(); + if (workerWindow != IntPtr.Zero) + { + // search if the reference window is behind the worker window + IntPtr reference = NativeMethods.FindWindowEx(IntPtr.Zero, workerWindow, null, _referenceWindowCaption); + showDesktopDetected = reference != IntPtr.Zero; + } + else + { + // if there is no worker window, then nothing can hide the reference + showDesktopDetected = false; + } + + if (_showDesktop != showDesktopDetected) + { + _showDesktop = showDesktopDetected; + ShowDesktopChangedEvent?.Invoke(_showDesktop); + } + } + + private static class NativeMethods + { + private const string USER = "user32.dll"; + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern IntPtr GetShellWindow(); + + [DllImport(USER, CallingConvention = CallingConvention.Winapi)] + public static extern int GetWindowThreadProcessId(IntPtr hWnd, out int processId); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/SplitContainerAdv.cs b/LibreHardwareMonitor/UI/SplitContainerAdv.cs index d6c592d..4d92e28 100644 --- a/LibreHardwareMonitor/UI/SplitContainerAdv.cs +++ b/LibreHardwareMonitor/UI/SplitContainerAdv.cs @@ -8,132 +8,131 @@ using System; using System.Drawing; using System.Windows.Forms; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class SplitContainerAdv : SplitContainer { - public class SplitContainerAdv : SplitContainer + private int _delta; + private Border3DStyle _border3DStyle = Border3DStyle.Raised; + private Color _bgColor = SystemColors.Control; + + public SplitContainerAdv() { - private int _delta; - private Border3DStyle _border3DStyle = Border3DStyle.Raised; - private Color _bgColor = SystemColors.Control; + SetStyle(ControlStyles.ResizeRedraw, true); + SetStyle(ControlStyles.AllPaintingInWmPaint, true); + SetStyle(ControlStyles.UserPaint, true); + SetStyle(ControlStyles.OptimizedDoubleBuffer, true); + SetStyle(ControlStyles.ContainerControl, true); + UpdateStyles(); + } - public SplitContainerAdv() + protected override void OnPaint(PaintEventArgs e) + { + base.OnPaint(e); + Graphics g = e.Graphics; + Rectangle r = SplitterRectangle; + + using (SolidBrush brush = new SolidBrush(_bgColor)) + g.FillRectangle(brush, r); + + ControlPaint.DrawBorder3D(g, r, _border3DStyle); + } + + protected override void OnKeyDown(KeyEventArgs e) + { + if (!IsSplitterFixed) { - SetStyle(ControlStyles.ResizeRedraw, true); - SetStyle(ControlStyles.AllPaintingInWmPaint, true); - SetStyle(ControlStyles.UserPaint, true); - SetStyle(ControlStyles.OptimizedDoubleBuffer, true); - SetStyle(ControlStyles.ContainerControl, true); - UpdateStyles(); - } - - protected override void OnPaint(PaintEventArgs e) - { - base.OnPaint(e); - Graphics g = e.Graphics; - Rectangle r = SplitterRectangle; - - using (SolidBrush brush = new SolidBrush(_bgColor)) - g.FillRectangle(brush, r); - - ControlPaint.DrawBorder3D(g, r, _border3DStyle); - } - - protected override void OnKeyDown(KeyEventArgs e) - { - if (!IsSplitterFixed) + switch (e.KeyData) { - switch (e.KeyData) + case Keys.Right: + case Keys.Down: + SplitterDistance += SplitterIncrement; + break; + case Keys.Left: + case Keys.Up: + SplitterDistance -= SplitterIncrement; + break; + } + + Invalidate(); + } + } + + protected override void OnMouseDown(MouseEventArgs e) + { + if (Orientation == Orientation.Vertical) + { + _delta = SplitterDistance - e.X; + Cursor.Current = Cursors.VSplit; + } + else + { + _delta = SplitterDistance - e.Y; + Cursor.Current = Cursors.HSplit; + } + IsSplitterFixed = true; + } + + protected override void OnMouseMove(MouseEventArgs e) + { + if (IsSplitterFixed) + { + if (e.Button == MouseButtons.Left) + { + if (Orientation == Orientation.Vertical) { - case Keys.Right: - case Keys.Down: - SplitterDistance += SplitterIncrement; - break; - case Keys.Left: - case Keys.Up: - SplitterDistance -= SplitterIncrement; - break; - } - - Invalidate(); - } - } - - protected override void OnMouseDown(MouseEventArgs e) - { - if (Orientation == Orientation.Vertical) - { - _delta = SplitterDistance - e.X; - Cursor.Current = Cursors.VSplit; - } - else - { - _delta = SplitterDistance - e.Y; - Cursor.Current = Cursors.HSplit; - } - IsSplitterFixed = true; - } - - protected override void OnMouseMove(MouseEventArgs e) - { - if (IsSplitterFixed) - { - if (e.Button == MouseButtons.Left) - { - if (Orientation == Orientation.Vertical) - { - if (e.X > 0 && e.X < Width) - SplitterDistance = e.X + _delta < 0 ? 0 : e.X + _delta; - } - else - { - if (e.Y > 0 && e.Y < Height) - SplitterDistance = e.Y + _delta < 0 ? 0 : e.Y + _delta; - } + if (e.X > 0 && e.X < Width) + SplitterDistance = e.X + _delta < 0 ? 0 : e.X + _delta; } else { - IsSplitterFixed = false; + if (e.Y > 0 && e.Y < Height) + SplitterDistance = e.Y + _delta < 0 ? 0 : e.Y + _delta; } - Invalidate(); } else { - if (SplitterRectangle.Contains(e.Location)) - Cursor = Orientation == Orientation.Vertical ? Cursors.VSplit : Cursors.HSplit; + IsSplitterFixed = false; } + Invalidate(); } - - protected override void OnMouseLeave(EventArgs e) + else { - base.OnMouseLeave(e); - Cursor = Cursors.Default; - } - - protected override void OnMouseUp(MouseEventArgs e) - { - _delta = 0; - IsSplitterFixed = false; - Cursor.Current = Cursors.Default; - } - - public Border3DStyle Border3DStyle - { - get { return _border3DStyle; } - set - { - _border3DStyle = value; - Invalidate(false); - } - } - - public Color Color - { - get { return _bgColor; } - set - { - _bgColor = value; - Invalidate(false); - } + if (SplitterRectangle.Contains(e.Location)) + Cursor = Orientation == Orientation.Vertical ? Cursors.VSplit : Cursors.HSplit; } } -} + + protected override void OnMouseLeave(EventArgs e) + { + base.OnMouseLeave(e); + Cursor = Cursors.Default; + } + + protected override void OnMouseUp(MouseEventArgs e) + { + _delta = 0; + IsSplitterFixed = false; + Cursor.Current = Cursors.Default; + } + + public Border3DStyle Border3DStyle + { + get { return _border3DStyle; } + set + { + _border3DStyle = value; + Invalidate(false); + } + } + + public Color Color + { + get { return _bgColor; } + set + { + _bgColor = value; + Invalidate(false); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/StartupManager.cs b/LibreHardwareMonitor/UI/StartupManager.cs index bf5e4fa..10a8a1d 100644 --- a/LibreHardwareMonitor/UI/StartupManager.cs +++ b/LibreHardwareMonitor/UI/StartupManager.cs @@ -14,168 +14,167 @@ using Microsoft.Win32; using Microsoft.Win32.TaskScheduler; using Action = Microsoft.Win32.TaskScheduler.Action; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class StartupManager { - public class StartupManager + private const string RegistryPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; + private bool _startup; + + public StartupManager() { - private const string RegistryPath = @"Software\Microsoft\Windows\CurrentVersion\Run"; - private bool _startup; - - public StartupManager() + if (Environment.OSVersion.Platform >= PlatformID.Unix) { - if (Environment.OSVersion.Platform >= PlatformID.Unix) - { - IsAvailable = false; - return; - } + IsAvailable = false; + return; + } - if (IsAdministrator() && TaskService.Instance.Connected) - { - IsAvailable = true; + if (IsAdministrator() && TaskService.Instance.Connected) + { + IsAvailable = true; - Task task = GetTask(); - if (task != null) + Task task = GetTask(); + if (task != null) + { + foreach (Action action in task.Definition.Actions) { - foreach (Action action in task.Definition.Actions) + if (action.ActionType == TaskActionType.Execute && action is ExecAction execAction) { - if (action.ActionType == TaskActionType.Execute && action is ExecAction execAction) - { - if (execAction.Path.Equals(Application.ExecutablePath, StringComparison.OrdinalIgnoreCase)) - _startup = true; - } + if (execAction.Path.Equals(Application.ExecutablePath, StringComparison.OrdinalIgnoreCase)) + _startup = true; } } } - else - { - try - { - using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(RegistryPath)) - { - string value = (string)registryKey?.GetValue(nameof(LibreHardwareMonitor)); - - if (value != null) - _startup = value == Application.ExecutablePath; - } - - IsAvailable = true; - } - catch (SecurityException) - { - IsAvailable = false; - } - } } - - public bool IsAvailable { get; } - - public bool Startup + else { - get { return _startup; } - set + try { - if (_startup != value) + using (RegistryKey registryKey = Registry.CurrentUser.OpenSubKey(RegistryPath)) { - if (IsAvailable) + string value = (string)registryKey?.GetValue(nameof(LibreHardwareMonitor)); + + if (value != null) + _startup = value == Application.ExecutablePath; + } + + IsAvailable = true; + } + catch (SecurityException) + { + IsAvailable = false; + } + } + } + + public bool IsAvailable { get; } + + public bool Startup + { + get { return _startup; } + set + { + if (_startup != value) + { + if (IsAvailable) + { + if (TaskService.Instance.Connected) { - if (TaskService.Instance.Connected) - { - if (value) - CreateTask(); - else - DeleteTask(); - - _startup = value; - } + if (value) + CreateTask(); else - { - try - { - if (value) - CreateRegistryKey(); - else - DeleteRegistryKey(); + DeleteTask(); - _startup = value; - } - catch (UnauthorizedAccessException) - { - throw new InvalidOperationException(); - } - } + _startup = value; } else { - throw new InvalidOperationException(); + try + { + if (value) + CreateRegistryKey(); + else + DeleteRegistryKey(); + + _startup = value; + } + catch (UnauthorizedAccessException) + { + throw new InvalidOperationException(); + } } } + else + { + throw new InvalidOperationException(); + } } } + } - private static bool IsAdministrator() + private static bool IsAdministrator() + { + try { - try - { - WindowsIdentity identity = WindowsIdentity.GetCurrent(); - WindowsPrincipal principal = new WindowsPrincipal(identity); + WindowsIdentity identity = WindowsIdentity.GetCurrent(); + WindowsPrincipal principal = new WindowsPrincipal(identity); - return principal.IsInRole(WindowsBuiltInRole.Administrator); - } - catch - { - return false; - } + return principal.IsInRole(WindowsBuiltInRole.Administrator); } - - private static Task GetTask() + catch { - try - { - return TaskService.Instance.AllTasks.FirstOrDefault(x => x.Name.Equals(nameof(LibreHardwareMonitor), StringComparison.OrdinalIgnoreCase)); - } - catch - { - return null; - } - } - - private void CreateTask() - { - TaskDefinition taskDefinition = TaskService.Instance.NewTask(); - taskDefinition.RegistrationInfo.Description = "Starts LibreHardwareMonitor on Windows startup."; - - taskDefinition.Triggers.Add(new LogonTrigger()); - - taskDefinition.Settings.StartWhenAvailable = true; - taskDefinition.Settings.DisallowStartIfOnBatteries = false; - taskDefinition.Settings.StopIfGoingOnBatteries = false; - taskDefinition.Settings.ExecutionTimeLimit = TimeSpan.Zero; - taskDefinition.Settings.AllowHardTerminate = false; - - taskDefinition.Principal.RunLevel = TaskRunLevel.Highest; - taskDefinition.Principal.LogonType = TaskLogonType.InteractiveToken; - - taskDefinition.Actions.Add(new ExecAction(Application.ExecutablePath, "", Path.GetDirectoryName(Application.ExecutablePath))); - - TaskService.Instance.RootFolder.RegisterTaskDefinition(nameof(LibreHardwareMonitor), taskDefinition); - } - - private static void DeleteTask() - { - Task task = GetTask(); - task?.Folder.DeleteTask(task.Name, false); - } - - private static void CreateRegistryKey() - { - RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(RegistryPath); - registryKey?.SetValue(nameof(LibreHardwareMonitor), Application.ExecutablePath); - } - - private static void DeleteRegistryKey() - { - RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(RegistryPath); - registryKey?.DeleteValue(nameof(LibreHardwareMonitor)); + return false; } } -} + + private static Task GetTask() + { + try + { + return TaskService.Instance.AllTasks.FirstOrDefault(x => x.Name.Equals(nameof(LibreHardwareMonitor), StringComparison.OrdinalIgnoreCase)); + } + catch + { + return null; + } + } + + private void CreateTask() + { + TaskDefinition taskDefinition = TaskService.Instance.NewTask(); + taskDefinition.RegistrationInfo.Description = "Starts LibreHardwareMonitor on Windows startup."; + + taskDefinition.Triggers.Add(new LogonTrigger()); + + taskDefinition.Settings.StartWhenAvailable = true; + taskDefinition.Settings.DisallowStartIfOnBatteries = false; + taskDefinition.Settings.StopIfGoingOnBatteries = false; + taskDefinition.Settings.ExecutionTimeLimit = TimeSpan.Zero; + taskDefinition.Settings.AllowHardTerminate = false; + + taskDefinition.Principal.RunLevel = TaskRunLevel.Highest; + taskDefinition.Principal.LogonType = TaskLogonType.InteractiveToken; + + taskDefinition.Actions.Add(new ExecAction(Application.ExecutablePath, "", Path.GetDirectoryName(Application.ExecutablePath))); + + TaskService.Instance.RootFolder.RegisterTaskDefinition(nameof(LibreHardwareMonitor), taskDefinition); + } + + private static void DeleteTask() + { + Task task = GetTask(); + task?.Folder.DeleteTask(task.Name, false); + } + + private static void CreateRegistryKey() + { + RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(RegistryPath); + registryKey?.SetValue(nameof(LibreHardwareMonitor), Application.ExecutablePath); + } + + private static void DeleteRegistryKey() + { + RegistryKey registryKey = Registry.CurrentUser.CreateSubKey(RegistryPath); + registryKey?.DeleteValue(nameof(LibreHardwareMonitor)); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/SystemTray.cs b/LibreHardwareMonitor/UI/SystemTray.cs index 75fb0ff..048d2df 100644 --- a/LibreHardwareMonitor/UI/SystemTray.cs +++ b/LibreHardwareMonitor/UI/SystemTray.cs @@ -10,177 +10,176 @@ using System.Windows.Forms; using LibreHardwareMonitor.Hardware; using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class SystemTray : IDisposable { - public class SystemTray : IDisposable + private IComputer _computer; + private readonly PersistentSettings _settings; + private readonly UnitManager _unitManager; + private readonly List _sensorList = new List(); + private bool _mainIconEnabled; + private readonly NotifyIconAdv _mainIcon; + + public SystemTray(IComputer computer, PersistentSettings settings, UnitManager unitManager) { - private IComputer _computer; - private readonly PersistentSettings _settings; - private readonly UnitManager _unitManager; - private readonly List _sensorList = new List(); - private bool _mainIconEnabled; - private readonly NotifyIconAdv _mainIcon; + _computer = computer; + _settings = settings; + _unitManager = unitManager; + computer.HardwareAdded += HardwareAdded; + computer.HardwareRemoved += HardwareRemoved; - public SystemTray(IComputer computer, PersistentSettings settings, UnitManager unitManager) + _mainIcon = new NotifyIconAdv(); + + ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); + ToolStripItem hideShowItem = new ToolStripMenuItem("Hide/Show"); + hideShowItem.Click += delegate { - _computer = computer; - _settings = settings; - _unitManager = unitManager; - computer.HardwareAdded += HardwareAdded; - computer.HardwareRemoved += HardwareRemoved; + SendHideShowCommand(); + }; + contextMenuStrip.Items.Add(hideShowItem); + contextMenuStrip.Items.Add(new ToolStripSeparator()); + ToolStripItem exitItem = new ToolStripMenuItem("Exit"); + exitItem.Click += delegate + { + SendExitCommand(); + }; + contextMenuStrip.Items.Add(exitItem); + _mainIcon.ContextMenuStrip = contextMenuStrip; + _mainIcon.DoubleClick += delegate + { + SendHideShowCommand(); + }; + _mainIcon.Icon = EmbeddedResources.GetIcon("smallicon.ico"); + _mainIcon.Text = "Libre Hardware Monitor"; + } - _mainIcon = new NotifyIconAdv(); + private void HardwareRemoved(IHardware hardware) + { + hardware.SensorAdded -= SensorAdded; + hardware.SensorRemoved -= SensorRemoved; - ContextMenuStrip contextMenuStrip = new ContextMenuStrip(); - ToolStripItem hideShowItem = new ToolStripMenuItem("Hide/Show"); - hideShowItem.Click += delegate - { - SendHideShowCommand(); - }; - contextMenuStrip.Items.Add(hideShowItem); - contextMenuStrip.Items.Add(new ToolStripSeparator()); - ToolStripItem exitItem = new ToolStripMenuItem("Exit"); - exitItem.Click += delegate - { - SendExitCommand(); - }; - contextMenuStrip.Items.Add(exitItem); - _mainIcon.ContextMenuStrip = contextMenuStrip; - _mainIcon.DoubleClick += delegate - { - SendHideShowCommand(); - }; - _mainIcon.Icon = EmbeddedResources.GetIcon("smallicon.ico"); - _mainIcon.Text = "Libre Hardware Monitor"; + foreach (ISensor sensor in hardware.Sensors) + SensorRemoved(sensor); + + foreach (IHardware subHardware in hardware.SubHardware) + HardwareRemoved(subHardware); + } + + private void HardwareAdded(IHardware hardware) + { + foreach (ISensor sensor in hardware.Sensors) + SensorAdded(sensor); + + hardware.SensorAdded += SensorAdded; + hardware.SensorRemoved += SensorRemoved; + + foreach (IHardware subHardware in hardware.SubHardware) + HardwareAdded(subHardware); + } + + private void SensorAdded(ISensor sensor) + { + if (_settings.GetValue(new Identifier(sensor.Identifier, "tray").ToString(), false)) + Add(sensor, false); + } + + private void SensorRemoved(ISensor sensor) + { + if (Contains(sensor)) + Remove(sensor, false); + } + + public void Dispose() + { + foreach (SensorNotifyIcon icon in _sensorList) + icon.Dispose(); + _mainIcon.Dispose(); + } + + public void Redraw() + { + foreach (SensorNotifyIcon icon in _sensorList) + icon.Update(); + } + + public bool Contains(ISensor sensor) + { + foreach (SensorNotifyIcon icon in _sensorList) + if (icon.Sensor == sensor) + return true; + return false; + } + + public void Add(ISensor sensor, bool balloonTip) + { + if (Contains(sensor)) + return; + + + _sensorList.Add(new SensorNotifyIcon(this, sensor, _settings, _unitManager)); + UpdateMainIconVisibility(); + _settings.SetValue(new Identifier(sensor.Identifier, "tray").ToString(), true); + } + + public void Remove(ISensor sensor) + { + Remove(sensor, true); + } + + private void Remove(ISensor sensor, bool deleteConfig) + { + if (deleteConfig) + { + _settings.Remove(new Identifier(sensor.Identifier, "tray").ToString()); + _settings.Remove(new Identifier(sensor.Identifier, "traycolor").ToString()); } - - private void HardwareRemoved(IHardware hardware) + SensorNotifyIcon instance = null; + foreach (SensorNotifyIcon icon in _sensorList) { - hardware.SensorAdded -= SensorAdded; - hardware.SensorRemoved -= SensorRemoved; - - foreach (ISensor sensor in hardware.Sensors) - SensorRemoved(sensor); - - foreach (IHardware subHardware in hardware.SubHardware) - HardwareRemoved(subHardware); + if (icon.Sensor == sensor) + instance = icon; } - - private void HardwareAdded(IHardware hardware) + if (instance != null) { - foreach (ISensor sensor in hardware.Sensors) - SensorAdded(sensor); - - hardware.SensorAdded += SensorAdded; - hardware.SensorRemoved += SensorRemoved; - - foreach (IHardware subHardware in hardware.SubHardware) - HardwareAdded(subHardware); - } - - private void SensorAdded(ISensor sensor) - { - if (_settings.GetValue(new Identifier(sensor.Identifier, "tray").ToString(), false)) - Add(sensor, false); - } - - private void SensorRemoved(ISensor sensor) - { - if (Contains(sensor)) - Remove(sensor, false); - } - - public void Dispose() - { - foreach (SensorNotifyIcon icon in _sensorList) - icon.Dispose(); - _mainIcon.Dispose(); - } - - public void Redraw() - { - foreach (SensorNotifyIcon icon in _sensorList) - icon.Update(); - } - - public bool Contains(ISensor sensor) - { - foreach (SensorNotifyIcon icon in _sensorList) - if (icon.Sensor == sensor) - return true; - return false; - } - - public void Add(ISensor sensor, bool balloonTip) - { - if (Contains(sensor)) - return; - - - _sensorList.Add(new SensorNotifyIcon(this, sensor, _settings, _unitManager)); + _sensorList.Remove(instance); UpdateMainIconVisibility(); - _settings.SetValue(new Identifier(sensor.Identifier, "tray").ToString(), true); + instance.Dispose(); } + } - public void Remove(ISensor sensor) - { - Remove(sensor, true); - } + public event EventHandler HideShowCommand; - private void Remove(ISensor sensor, bool deleteConfig) + public void SendHideShowCommand() + { + HideShowCommand?.Invoke(this, null); + } + + public event EventHandler ExitCommand; + + public void SendExitCommand() + { + ExitCommand?.Invoke(this, null); + } + + private void UpdateMainIconVisibility() + { + if (_mainIconEnabled) + _mainIcon.Visible = _sensorList.Count == 0; + else + _mainIcon.Visible = false; + } + + public bool IsMainIconEnabled + { + get { return _mainIconEnabled; } + set { - if (deleteConfig) + if (_mainIconEnabled != value) { - _settings.Remove(new Identifier(sensor.Identifier, "tray").ToString()); - _settings.Remove(new Identifier(sensor.Identifier, "traycolor").ToString()); - } - SensorNotifyIcon instance = null; - foreach (SensorNotifyIcon icon in _sensorList) - { - if (icon.Sensor == sensor) - instance = icon; - } - if (instance != null) - { - _sensorList.Remove(instance); + _mainIconEnabled = value; UpdateMainIconVisibility(); - instance.Dispose(); - } - } - - public event EventHandler HideShowCommand; - - public void SendHideShowCommand() - { - HideShowCommand?.Invoke(this, null); - } - - public event EventHandler ExitCommand; - - public void SendExitCommand() - { - ExitCommand?.Invoke(this, null); - } - - private void UpdateMainIconVisibility() - { - if (_mainIconEnabled) - _mainIcon.Visible = _sensorList.Count == 0; - else - _mainIcon.Visible = false; - } - - public bool IsMainIconEnabled - { - get { return _mainIconEnabled; } - set - { - if (_mainIconEnabled != value) - { - _mainIconEnabled = value; - UpdateMainIconVisibility(); - } } } } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/ToolStripRadioButtonMenuItem.cs b/LibreHardwareMonitor/UI/ToolStripRadioButtonMenuItem.cs index 29df43d..c1dacb9 100644 --- a/LibreHardwareMonitor/UI/ToolStripRadioButtonMenuItem.cs +++ b/LibreHardwareMonitor/UI/ToolStripRadioButtonMenuItem.cs @@ -3,253 +3,252 @@ using System.Drawing; using System.Windows.Forms; using System.Windows.Forms.VisualStyles; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +/// +/// https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-display-option-buttons-in-a-menustrip-windows-forms +/// +public class ToolStripRadioButtonMenuItem : ToolStripMenuItem { - /// - /// https://docs.microsoft.com/en-us/dotnet/desktop/winforms/controls/how-to-display-option-buttons-in-a-menustrip-windows-forms - /// - public class ToolStripRadioButtonMenuItem : ToolStripMenuItem + public ToolStripRadioButtonMenuItem() + : base() { - public ToolStripRadioButtonMenuItem() - : base() + Initialize(); + } + + public ToolStripRadioButtonMenuItem(string text) + : base(text, null, (EventHandler)null) + { + Initialize(); + } + + public ToolStripRadioButtonMenuItem(Image image) + : base(null, image, (EventHandler)null) + { + Initialize(); + } + + public ToolStripRadioButtonMenuItem(string text, Image image) + : base(text, image, (EventHandler)null) + { + Initialize(); + } + + public ToolStripRadioButtonMenuItem(string text, Image image, + EventHandler onClick) + : base(text, image, onClick) + { + Initialize(); + } + + public ToolStripRadioButtonMenuItem(string text, Image image, + EventHandler onClick, string name) + : base(text, image, onClick, name) + { + Initialize(); + } + + public ToolStripRadioButtonMenuItem(string text, Image image, + params ToolStripItem[] dropDownItems) + : base(text, image, dropDownItems) + { + Initialize(); + } + + public ToolStripRadioButtonMenuItem(string text, Image image, + EventHandler onClick, Keys shortcutKeys) + : base(text, image, onClick) + { + Initialize(); + ShortcutKeys = shortcutKeys; + } + + // Called by all constructors to initialize CheckOnClick. + private void Initialize() + { + CheckOnClick = true; + } + + protected override void OnCheckedChanged(EventArgs e) + { + base.OnCheckedChanged(e); + + // If this item is no longer in the checked state or if its + // parent has not yet been initialized, do nothing. + if (!Checked || Parent == null) return; + + // Clear the checked state for all siblings. + foreach (ToolStripItem item in Parent.Items) { - Initialize(); - } - - public ToolStripRadioButtonMenuItem(string text) - : base(text, null, (EventHandler)null) - { - Initialize(); - } - - public ToolStripRadioButtonMenuItem(Image image) - : base(null, image, (EventHandler)null) - { - Initialize(); - } - - public ToolStripRadioButtonMenuItem(string text, Image image) - : base(text, image, (EventHandler)null) - { - Initialize(); - } - - public ToolStripRadioButtonMenuItem(string text, Image image, - EventHandler onClick) - : base(text, image, onClick) - { - Initialize(); - } - - public ToolStripRadioButtonMenuItem(string text, Image image, - EventHandler onClick, string name) - : base(text, image, onClick, name) - { - Initialize(); - } - - public ToolStripRadioButtonMenuItem(string text, Image image, - params ToolStripItem[] dropDownItems) - : base(text, image, dropDownItems) - { - Initialize(); - } - - public ToolStripRadioButtonMenuItem(string text, Image image, - EventHandler onClick, Keys shortcutKeys) - : base(text, image, onClick) - { - Initialize(); - ShortcutKeys = shortcutKeys; - } - - // Called by all constructors to initialize CheckOnClick. - private void Initialize() - { - CheckOnClick = true; - } - - protected override void OnCheckedChanged(EventArgs e) - { - base.OnCheckedChanged(e); - - // If this item is no longer in the checked state or if its - // parent has not yet been initialized, do nothing. - if (!Checked || Parent == null) return; - - // Clear the checked state for all siblings. - foreach (ToolStripItem item in Parent.Items) + if (item is ToolStripRadioButtonMenuItem radioItem + && radioItem != this + && radioItem.Checked) { - if (item is ToolStripRadioButtonMenuItem radioItem - && radioItem != this - && radioItem.Checked) - { - radioItem.Checked = false; + radioItem.Checked = false; - // Only one item can be selected at a time, - // so there is no need to continue. - return; - } - } - } - - protected override void OnClick(EventArgs e) - { - // If the item is already in the checked state, do not call - // the base method, which would toggle the value. - if (Checked) return; - - base.OnClick(e); - } - - // Let the item paint itself, and then paint the RadioButton - // where the check mark is normally displayed. - protected override void OnPaint(PaintEventArgs e) - { - if (Image != null) - { - // If the client sets the Image property, the selection behavior - // remains unchanged, but the RadioButton is not displayed and the - // selection is indicated only by the selection rectangle. - base.OnPaint(e); + // Only one item can be selected at a time, + // so there is no need to continue. return; } - else - { - // If the Image property is not set, call the base OnPaint method - // with the CheckState property temporarily cleared to prevent - // the check mark from being painted. - CheckState currentState = CheckState; - CheckState = CheckState.Unchecked; - base.OnPaint(e); - CheckState = currentState; - } + } + } - // Determine the correct state of the RadioButton. - RadioButtonState buttonState = RadioButtonState.UncheckedNormal; - if (Enabled) + protected override void OnClick(EventArgs e) + { + // If the item is already in the checked state, do not call + // the base method, which would toggle the value. + if (Checked) return; + + base.OnClick(e); + } + + // Let the item paint itself, and then paint the RadioButton + // where the check mark is normally displayed. + protected override void OnPaint(PaintEventArgs e) + { + if (Image != null) + { + // If the client sets the Image property, the selection behavior + // remains unchanged, but the RadioButton is not displayed and the + // selection is indicated only by the selection rectangle. + base.OnPaint(e); + return; + } + else + { + // If the Image property is not set, call the base OnPaint method + // with the CheckState property temporarily cleared to prevent + // the check mark from being painted. + CheckState currentState = CheckState; + CheckState = CheckState.Unchecked; + base.OnPaint(e); + CheckState = currentState; + } + + // Determine the correct state of the RadioButton. + RadioButtonState buttonState = RadioButtonState.UncheckedNormal; + if (Enabled) + { + if (mouseDownState) { - if (mouseDownState) - { - if (Checked) - buttonState = RadioButtonState.CheckedPressed; - else - buttonState = RadioButtonState.UncheckedPressed; - } - else if (mouseHoverState) - { - if (Checked) - buttonState = RadioButtonState.CheckedHot; - else - buttonState = RadioButtonState.UncheckedHot; - } + if (Checked) + buttonState = RadioButtonState.CheckedPressed; else - { - if (Checked) - buttonState = RadioButtonState.CheckedNormal; - } + buttonState = RadioButtonState.UncheckedPressed; + } + else if (mouseHoverState) + { + if (Checked) + buttonState = RadioButtonState.CheckedHot; + else + buttonState = RadioButtonState.UncheckedHot; } else { if (Checked) - buttonState = RadioButtonState.CheckedDisabled; - else - buttonState = RadioButtonState.UncheckedDisabled; + buttonState = RadioButtonState.CheckedNormal; } - - // Calculate the position at which to display the RadioButton. - int offset = (ContentRectangle.Height - - RadioButtonRenderer.GetGlyphSize( - e.Graphics, buttonState).Height) / 2; - - Point imageLocation = new Point( - ContentRectangle.Location.X + 4, - ContentRectangle.Location.Y + offset); - - // Paint the RadioButton. - RadioButtonRenderer.DrawRadioButton(e.Graphics, imageLocation, buttonState); + } + else + { + if (Checked) + buttonState = RadioButtonState.CheckedDisabled; + else + buttonState = RadioButtonState.UncheckedDisabled; } - private bool mouseHoverState; + // Calculate the position at which to display the RadioButton. + int offset = (ContentRectangle.Height - + RadioButtonRenderer.GetGlyphSize( + e.Graphics, buttonState).Height) / 2; - protected override void OnMouseEnter(EventArgs e) + Point imageLocation = new Point( + ContentRectangle.Location.X + 4, + ContentRectangle.Location.Y + offset); + + // Paint the RadioButton. + RadioButtonRenderer.DrawRadioButton(e.Graphics, imageLocation, buttonState); + } + + private bool mouseHoverState; + + protected override void OnMouseEnter(EventArgs e) + { + mouseHoverState = true; + + // Force the item to repaint with the new RadioButton state. + Invalidate(); + + base.OnMouseEnter(e); + } + + protected override void OnMouseLeave(EventArgs e) + { + mouseHoverState = false; + base.OnMouseLeave(e); + } + + private bool mouseDownState; + + protected override void OnMouseDown(MouseEventArgs e) + { + mouseDownState = true; + + // Force the item to repaint with the new RadioButton state. + Invalidate(); + + base.OnMouseDown(e); + } + + protected override void OnMouseUp(MouseEventArgs e) + { + mouseDownState = false; + base.OnMouseUp(e); + } + + // Enable the item only if its parent item is in the checked state + // and its Enabled property has not been explicitly set to false. + public override bool Enabled + { + get { - mouseHoverState = true; - - // Force the item to repaint with the new RadioButton state. - Invalidate(); - - base.OnMouseEnter(e); - } - - protected override void OnMouseLeave(EventArgs e) - { - mouseHoverState = false; - base.OnMouseLeave(e); - } - - private bool mouseDownState; - - protected override void OnMouseDown(MouseEventArgs e) - { - mouseDownState = true; - - // Force the item to repaint with the new RadioButton state. - Invalidate(); - - base.OnMouseDown(e); - } - - protected override void OnMouseUp(MouseEventArgs e) - { - mouseDownState = false; - base.OnMouseUp(e); - } - - // Enable the item only if its parent item is in the checked state - // and its Enabled property has not been explicitly set to false. - public override bool Enabled - { - get + // Use the base value in design mode to prevent the designer + // from setting the base value to the calculated value. + if (!DesignMode + && OwnerItem is ToolStripMenuItem ownerMenuItem + && ownerMenuItem.CheckOnClick) { - // Use the base value in design mode to prevent the designer - // from setting the base value to the calculated value. - if (!DesignMode - && OwnerItem is ToolStripMenuItem ownerMenuItem - && ownerMenuItem.CheckOnClick) - { - return base.Enabled && ownerMenuItem.Checked; - } - else - { - return base.Enabled; - } + return base.Enabled && ownerMenuItem.Checked; } - set + else { - base.Enabled = value; + return base.Enabled; } } - - // When OwnerItem becomes available, if it is a ToolStripMenuItem - // with a CheckOnClick property value of true, subscribe to its - // CheckedChanged event. - protected override void OnOwnerChanged(EventArgs e) + set { - if (OwnerItem is ToolStripMenuItem ownerMenuItem - && ownerMenuItem.CheckOnClick) - { - ownerMenuItem.CheckedChanged += - new EventHandler(OwnerMenuItem_CheckedChanged); - } - base.OnOwnerChanged(e); - } - - // When the checked state of the parent item changes, - // repaint the item so that the new Enabled state is displayed. - private void OwnerMenuItem_CheckedChanged(object sender, EventArgs e) - { - Invalidate(); + base.Enabled = value; } } -} + + // When OwnerItem becomes available, if it is a ToolStripMenuItem + // with a CheckOnClick property value of true, subscribe to its + // CheckedChanged event. + protected override void OnOwnerChanged(EventArgs e) + { + if (OwnerItem is ToolStripMenuItem ownerMenuItem + && ownerMenuItem.CheckOnClick) + { + ownerMenuItem.CheckedChanged += + new EventHandler(OwnerMenuItem_CheckedChanged); + } + base.OnOwnerChanged(e); + } + + // When the checked state of the parent item changes, + // repaint the item so that the new Enabled state is displayed. + private void OwnerMenuItem_CheckedChanged(object sender, EventArgs e) + { + Invalidate(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/TreeModel.cs b/LibreHardwareMonitor/UI/TreeModel.cs index 9a7b6f4..6675ab7 100644 --- a/LibreHardwareMonitor/UI/TreeModel.cs +++ b/LibreHardwareMonitor/UI/TreeModel.cs @@ -10,117 +10,116 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using Aga.Controls.Tree; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class TreeModel : ITreeModel { - public class TreeModel : ITreeModel + private readonly Node _root; + private bool _forceVisible; + + public TreeModel() { - private readonly Node _root; - private bool _forceVisible; + _root = new Node { Model = this }; + } - public TreeModel() + public TreePath GetPath(Node node) + { + if (node == _root) + return TreePath.Empty; + + + Stack stack = new Stack(); + while (node != _root) { - _root = new Node { Model = this }; + stack.Push(node); + node = node.Parent; } + return new TreePath(stack.ToArray()); + } - public TreePath GetPath(Node node) + public Collection Nodes + { + get { return _root.Nodes; } + } + + private Node GetNode(TreePath treePath) + { + Node parent = _root; + foreach (object obj in treePath.FullPath) { - if (node == _root) - return TreePath.Empty; + if (!(obj is Node node) || node.Parent != parent) + return null; + parent = node; + } + return parent; + } + public IEnumerable GetChildren(TreePath treePath) + { + Node node = GetNode(treePath); + if (node != null) + { + foreach (Node n in node.Nodes) + if (_forceVisible || n.IsVisible) + yield return n; + } + else + { } + } - Stack stack = new Stack(); - while (node != _root) + public bool IsLeaf(TreePath treePath) + { + return false; + } + + public bool ForceVisible + { + get + { + return _forceVisible; + } + set + { + if (value != _forceVisible) { - stack.Push(node); - node = node.Parent; - } - return new TreePath(stack.ToArray()); - } - - public Collection Nodes - { - get { return _root.Nodes; } - } - - private Node GetNode(TreePath treePath) - { - Node parent = _root; - foreach (object obj in treePath.FullPath) - { - if (!(obj is Node node) || node.Parent != parent) - return null; - parent = node; - } - return parent; - } - - public IEnumerable GetChildren(TreePath treePath) - { - Node node = GetNode(treePath); - if (node != null) - { - foreach (Node n in node.Nodes) - if (_forceVisible || n.IsVisible) - yield return n; - } - else - { } - } - - public bool IsLeaf(TreePath treePath) - { - return false; - } - - public bool ForceVisible - { - get - { - return _forceVisible; - } - set - { - if (value != _forceVisible) - { - _forceVisible = value; - OnStructureChanged(_root); - } + _forceVisible = value; + OnStructureChanged(_root); } } + } #pragma warning disable 67 - public event EventHandler NodesChanged; - public event EventHandler StructureChanged; - public event EventHandler NodesInserted; - public event EventHandler NodesRemoved; + public event EventHandler NodesChanged; + public event EventHandler StructureChanged; + public event EventHandler NodesInserted; + public event EventHandler NodesRemoved; #pragma warning restore 67 - public void OnNodeChanged(Node parent, int index, Node node) + public void OnNodeChanged(Node parent, int index, Node node) + { + if (parent != null) { - if (parent != null) - { - TreePath path = GetPath(parent); - if (path != null) - NodesChanged?.Invoke(this, new TreeModelEventArgs(path, new[] { index }, new object[] { node })); - } + TreePath path = GetPath(parent); + if (path != null) + NodesChanged?.Invoke(this, new TreeModelEventArgs(path, new[] { index }, new object[] { node })); } - - public void OnStructureChanged(Node node) - { - StructureChanged?.Invoke(this, new TreeModelEventArgs(GetPath(node), new object[0])); - } - - public void OnNodeInserted(Node parent, int index, Node node) - { - TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new[] { index }, new object[] { node }); - NodesInserted?.Invoke(this, args); - } - - public void OnNodeRemoved(Node parent, int index, Node node) - { - TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new[] { index }, new object[] { node }); - NodesRemoved?.Invoke(this, args); - } - } -} + + public void OnStructureChanged(Node node) + { + StructureChanged?.Invoke(this, new TreeModelEventArgs(GetPath(node), new object[0])); + } + + public void OnNodeInserted(Node parent, int index, Node node) + { + TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new[] { index }, new object[] { node }); + NodesInserted?.Invoke(this, args); + } + + public void OnNodeRemoved(Node parent, int index, Node node) + { + TreeModelEventArgs args = new TreeModelEventArgs(GetPath(parent), new[] { index }, new object[] { node }); + NodesRemoved?.Invoke(this, args); + } + +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/TypeNode.cs b/LibreHardwareMonitor/UI/TypeNode.cs index 6056172..6162ce7 100644 --- a/LibreHardwareMonitor/UI/TypeNode.cs +++ b/LibreHardwareMonitor/UI/TypeNode.cs @@ -7,136 +7,135 @@ using LibreHardwareMonitor.Hardware; using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public sealed class TypeNode : Node, IExpandPersistNode { - public sealed class TypeNode : Node, IExpandPersistNode + private readonly PersistentSettings _settings; + private readonly string _expandedIdentifier; + private bool _expanded; + + public TypeNode(SensorType sensorType, Identifier parentId, PersistentSettings settings) { - private readonly PersistentSettings _settings; - private readonly string _expandedIdentifier; - private bool _expanded; + SensorType = sensorType; + _expandedIdentifier = new Identifier(parentId, SensorType.ToString(), ".expanded").ToString(); + _settings = settings; - public TypeNode(SensorType sensorType, Identifier parentId, PersistentSettings settings) + switch (sensorType) { - SensorType = sensorType; - _expandedIdentifier = new Identifier(parentId, SensorType.ToString(), ".expanded").ToString(); - _settings = settings; + case SensorType.Voltage: + Image = Utilities.EmbeddedResources.GetImage("voltage.png"); + Text = "Voltages"; + break; + case SensorType.Current: + Image = Utilities.EmbeddedResources.GetImage("voltage.png"); + Text = "Currents"; + break; + case SensorType.Energy: + Image = Utilities.EmbeddedResources.GetImage("battery.png"); + Text = "Capacities"; + break; + case SensorType.Clock: + Image = Utilities.EmbeddedResources.GetImage("clock.png"); + Text = "Clocks"; + break; + case SensorType.Load: + Image = Utilities.EmbeddedResources.GetImage("load.png"); + Text = "Load"; + break; + case SensorType.Temperature: + Image = Utilities.EmbeddedResources.GetImage("temperature.png"); + Text = "Temperatures"; + break; + case SensorType.Fan: + Image = Utilities.EmbeddedResources.GetImage("fan.png"); + Text = "Fans"; + break; + case SensorType.Flow: + Image = Utilities.EmbeddedResources.GetImage("flow.png"); + Text = "Flows"; + break; + case SensorType.Control: + Image = Utilities.EmbeddedResources.GetImage("control.png"); + Text = "Controls"; + break; + case SensorType.Level: + Image = Utilities.EmbeddedResources.GetImage("level.png"); + Text = "Levels"; + break; + case SensorType.Power: + Image = Utilities.EmbeddedResources.GetImage("power.png"); + Text = "Powers"; + break; + case SensorType.Data: + Image = Utilities.EmbeddedResources.GetImage("data.png"); + Text = "Data"; + break; + case SensorType.SmallData: + Image = Utilities.EmbeddedResources.GetImage("data.png"); + Text = "Data"; + break; + case SensorType.Factor: + Image = Utilities.EmbeddedResources.GetImage("factor.png"); + Text = "Factors"; + break; + case SensorType.Frequency: + Image = Utilities.EmbeddedResources.GetImage("clock.png"); + Text = "Frequencies"; + break; + case SensorType.Throughput: + Image = Utilities.EmbeddedResources.GetImage("throughput.png"); + Text = "Throughput"; + break; + case SensorType.TimeSpan: + Image = Utilities.EmbeddedResources.GetImage("time.png"); + Text = "Times"; + break; + case SensorType.Noise: + Image = Utilities.EmbeddedResources.GetImage("loudspeaker.png"); + Text = "Noise Levels"; + break; + } - switch (sensorType) + NodeAdded += TypeNode_NodeAdded; + NodeRemoved += TypeNode_NodeRemoved; + _expanded = settings.GetValue(_expandedIdentifier, true); + } + + private void TypeNode_NodeRemoved(Node node) + { + node.IsVisibleChanged -= Node_IsVisibleChanged; + Node_IsVisibleChanged(null); + } + + private void TypeNode_NodeAdded(Node node) + { + node.IsVisibleChanged += Node_IsVisibleChanged; + Node_IsVisibleChanged(null); + } + + private void Node_IsVisibleChanged(Node node) + { + foreach (Node n in Nodes) + { + if (n.IsVisible) { - case SensorType.Voltage: - Image = Utilities.EmbeddedResources.GetImage("voltage.png"); - Text = "Voltages"; - break; - case SensorType.Current: - Image = Utilities.EmbeddedResources.GetImage("voltage.png"); - Text = "Currents"; - break; - case SensorType.Energy: - Image = Utilities.EmbeddedResources.GetImage("battery.png"); - Text = "Capacities"; - break; - case SensorType.Clock: - Image = Utilities.EmbeddedResources.GetImage("clock.png"); - Text = "Clocks"; - break; - case SensorType.Load: - Image = Utilities.EmbeddedResources.GetImage("load.png"); - Text = "Load"; - break; - case SensorType.Temperature: - Image = Utilities.EmbeddedResources.GetImage("temperature.png"); - Text = "Temperatures"; - break; - case SensorType.Fan: - Image = Utilities.EmbeddedResources.GetImage("fan.png"); - Text = "Fans"; - break; - case SensorType.Flow: - Image = Utilities.EmbeddedResources.GetImage("flow.png"); - Text = "Flows"; - break; - case SensorType.Control: - Image = Utilities.EmbeddedResources.GetImage("control.png"); - Text = "Controls"; - break; - case SensorType.Level: - Image = Utilities.EmbeddedResources.GetImage("level.png"); - Text = "Levels"; - break; - case SensorType.Power: - Image = Utilities.EmbeddedResources.GetImage("power.png"); - Text = "Powers"; - break; - case SensorType.Data: - Image = Utilities.EmbeddedResources.GetImage("data.png"); - Text = "Data"; - break; - case SensorType.SmallData: - Image = Utilities.EmbeddedResources.GetImage("data.png"); - Text = "Data"; - break; - case SensorType.Factor: - Image = Utilities.EmbeddedResources.GetImage("factor.png"); - Text = "Factors"; - break; - case SensorType.Frequency: - Image = Utilities.EmbeddedResources.GetImage("clock.png"); - Text = "Frequencies"; - break; - case SensorType.Throughput: - Image = Utilities.EmbeddedResources.GetImage("throughput.png"); - Text = "Throughput"; - break; - case SensorType.TimeSpan: - Image = Utilities.EmbeddedResources.GetImage("time.png"); - Text = "Times"; - break; - case SensorType.Noise: - Image = Utilities.EmbeddedResources.GetImage("loudspeaker.png"); - Text = "Noise Levels"; - break; + IsVisible = true; + return; } - - NodeAdded += TypeNode_NodeAdded; - NodeRemoved += TypeNode_NodeRemoved; - _expanded = settings.GetValue(_expandedIdentifier, true); } + IsVisible = false; + } - private void TypeNode_NodeRemoved(Node node) + public SensorType SensorType { get; } + + public bool Expanded + { + get => _expanded; + set { - node.IsVisibleChanged -= Node_IsVisibleChanged; - Node_IsVisibleChanged(null); - } - - private void TypeNode_NodeAdded(Node node) - { - node.IsVisibleChanged += Node_IsVisibleChanged; - Node_IsVisibleChanged(null); - } - - private void Node_IsVisibleChanged(Node node) - { - foreach (Node n in Nodes) - { - if (n.IsVisible) - { - IsVisible = true; - return; - } - } - IsVisible = false; - } - - public SensorType SensorType { get; } - - public bool Expanded - { - get => _expanded; - set - { - _expanded = value; - _settings.SetValue(_expandedIdentifier, _expanded); - } + _expanded = value; + _settings.SetValue(_expandedIdentifier, _expanded); } } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/UnitManager.cs b/LibreHardwareMonitor/UI/UnitManager.cs index 9e1ade9..2453c2d 100644 --- a/LibreHardwareMonitor/UI/UnitManager.cs +++ b/LibreHardwareMonitor/UI/UnitManager.cs @@ -6,40 +6,38 @@ using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public enum TemperatureUnit +{ + Celsius = 0, + Fahrenheit = 1 +} + +public class UnitManager { - public enum TemperatureUnit + private readonly PersistentSettings _settings; + private TemperatureUnit _temperatureUnit; + + public UnitManager(PersistentSettings settings) { - Celsius = 0, - Fahrenheit = 1 + _settings = settings; + _temperatureUnit = (TemperatureUnit)settings.GetValue("TemperatureUnit", (int)TemperatureUnit.Celsius); } - public class UnitManager + public TemperatureUnit TemperatureUnit { - - private readonly PersistentSettings _settings; - private TemperatureUnit _temperatureUnit; - - public UnitManager(PersistentSettings settings) + get { return _temperatureUnit; } + set { - _settings = settings; - _temperatureUnit = (TemperatureUnit)settings.GetValue("TemperatureUnit", (int)TemperatureUnit.Celsius); - } - - public TemperatureUnit TemperatureUnit - { - get { return _temperatureUnit; } - set - { - _temperatureUnit = value; - _settings.SetValue("TemperatureUnit", (int)_temperatureUnit); - } - } - - public static float? CelsiusToFahrenheit(float? valueInCelsius) - { - return valueInCelsius * 1.8f + 32; + _temperatureUnit = value; + _settings.SetValue("TemperatureUnit", (int)_temperatureUnit); } } -} + + public static float? CelsiusToFahrenheit(float? valueInCelsius) + { + return valueInCelsius * 1.8f + 32; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/UpdateVisitor.cs b/LibreHardwareMonitor/UI/UpdateVisitor.cs index c11459f..fa8cf19 100644 --- a/LibreHardwareMonitor/UI/UpdateVisitor.cs +++ b/LibreHardwareMonitor/UI/UpdateVisitor.cs @@ -6,24 +6,23 @@ using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class UpdateVisitor : IVisitor { - public class UpdateVisitor : IVisitor + public void VisitComputer(IComputer computer) { - public void VisitComputer(IComputer computer) - { - computer.Traverse(this); - } - - public void VisitHardware(IHardware hardware) - { - hardware.Update(); - foreach (IHardware subHardware in hardware.SubHardware) - subHardware.Accept(this); - } - - public void VisitSensor(ISensor sensor) { } - - public void VisitParameter(IParameter parameter) { } + computer.Traverse(this); } -} + + public void VisitHardware(IHardware hardware) + { + hardware.Update(); + foreach (IHardware subHardware in hardware.SubHardware) + subHardware.Accept(this); + } + + public void VisitSensor(ISensor sensor) { } + + public void VisitParameter(IParameter parameter) { } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/UserOption.cs b/LibreHardwareMonitor/UI/UserOption.cs index 7c9e893..017410f 100644 --- a/LibreHardwareMonitor/UI/UserOption.cs +++ b/LibreHardwareMonitor/UI/UserOption.cs @@ -8,58 +8,57 @@ using System; using System.Windows.Forms; using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class UserOption { - public class UserOption + private readonly string _name; + private bool _value; + private readonly ToolStripMenuItem _menuItem; + private event EventHandler _changed; + private readonly PersistentSettings _settings; + + public UserOption(string name, bool value, ToolStripMenuItem menuItem, PersistentSettings settings) { - private readonly string _name; - private bool _value; - private readonly ToolStripMenuItem _menuItem; - private event EventHandler _changed; - private readonly PersistentSettings _settings; + _settings = settings; + _name = name; + _value = name != null ? settings.GetValue(name, value) : value; + _menuItem = menuItem; + _menuItem.Checked = _value; + _menuItem.Click += MenuItem_Click; + } - public UserOption(string name, bool value, ToolStripMenuItem menuItem, PersistentSettings settings) - { - _settings = settings; - _name = name; - _value = name != null ? settings.GetValue(name, value) : value; - _menuItem = menuItem; - _menuItem.Checked = _value; - _menuItem.Click += MenuItem_Click; - } + private void MenuItem_Click(object sender, EventArgs e) + { + Value = !Value; + } - private void MenuItem_Click(object sender, EventArgs e) + public bool Value + { + get { return _value; } + set { - Value = !Value; - } - - public bool Value - { - get { return _value; } - set + if (_value != value) { - if (_value != value) - { - _value = value; - if (_name != null) - _settings.SetValue(_name, value); - _menuItem.Checked = value; - _changed?.Invoke(this, null); - } - } - } - - public event EventHandler Changed - { - add - { - _changed += value; + _value = value; + if (_name != null) + _settings.SetValue(_name, value); + _menuItem.Checked = value; _changed?.Invoke(this, null); } - remove - { - _changed -= value; - } } } -} + + public event EventHandler Changed + { + add + { + _changed += value; + _changed?.Invoke(this, null); + } + remove + { + _changed -= value; + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/UI/UserRadioGroup.cs b/LibreHardwareMonitor/UI/UserRadioGroup.cs index 1239c62..201a0c0 100644 --- a/LibreHardwareMonitor/UI/UserRadioGroup.cs +++ b/LibreHardwareMonitor/UI/UserRadioGroup.cs @@ -8,63 +8,62 @@ using System; using System.Windows.Forms; using LibreHardwareMonitor.Utilities; -namespace LibreHardwareMonitor.UI +namespace LibreHardwareMonitor.UI; + +public class UserRadioGroup { - public class UserRadioGroup + private readonly string _name; + private int _value; + private readonly ToolStripMenuItem[] _menuItems; + private event EventHandler _changed; + private readonly PersistentSettings _settings; + + public UserRadioGroup(string name, int value, ToolStripMenuItem[] menuItems, PersistentSettings settings) { - private readonly string _name; - private int _value; - private readonly ToolStripMenuItem[] _menuItems; - private event EventHandler _changed; - private readonly PersistentSettings _settings; + _settings = settings; + _name = name; + _value = name != null ? settings.GetValue(name, value) : value; + _menuItems = menuItems; + _value = Math.Max(Math.Min(_value, menuItems.Length - 1), 0); - public UserRadioGroup(string name, int value, ToolStripMenuItem[] menuItems, PersistentSettings settings) + for (int i = 0; i < _menuItems.Length; i++) { - _settings = settings; - _name = name; - _value = name != null ? settings.GetValue(name, value) : value; - _menuItems = menuItems; - _value = Math.Max(Math.Min(_value, menuItems.Length - 1), 0); - - for (int i = 0; i < _menuItems.Length; i++) + _menuItems[i].Checked = i == _value; + int index = i; + _menuItems[i].Click += delegate { - _menuItems[i].Checked = i == _value; - int index = i; - _menuItems[i].Click += delegate - { - Value = index; - }; - } + Value = index; + }; } + } - public int Value + public int Value + { + get { return _value; } + set { - get { return _value; } - set + if (_value != value) { - if (_value != value) - { - _value = value; - if (_name != null) - _settings.SetValue(_name, value); - for (int i = 0; i < _menuItems.Length; i++) - _menuItems[i].Checked = i == value; - _changed?.Invoke(this, null); - } - } - } - - public event EventHandler Changed - { - add - { - _changed += value; + _value = value; + if (_name != null) + _settings.SetValue(_name, value); + for (int i = 0; i < _menuItems.Length; i++) + _menuItems[i].Checked = i == value; _changed?.Invoke(this, null); } - remove - { - _changed -= value; - } } } -} + + public event EventHandler Changed + { + add + { + _changed += value; + _changed?.Invoke(this, null); + } + remove + { + _changed -= value; + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/Utilities/EmbeddedResources.cs b/LibreHardwareMonitor/Utilities/EmbeddedResources.cs index ca36d59..9ad6d56 100644 --- a/LibreHardwareMonitor/Utilities/EmbeddedResources.cs +++ b/LibreHardwareMonitor/Utilities/EmbeddedResources.cs @@ -8,53 +8,52 @@ using System.Drawing; using System.IO; using System.Reflection; -namespace LibreHardwareMonitor.Utilities +namespace LibreHardwareMonitor.Utilities; + +public class EmbeddedResources { - public class EmbeddedResources + public static Image GetImage(string name) { - public static Image GetImage(string name) + name = "LibreHardwareMonitor.Resources." + name; + string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); + + for (int i = 0; i < names.Length; i++) { - name = "LibreHardwareMonitor.Resources." + name; - string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); - - for (int i = 0; i < names.Length; i++) + if (names[i].Replace('\\', '.') == name) { - if (names[i].Replace('\\', '.') == name) + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) { - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) - { - // "You must keep the stream open for the lifetime of the Image." - Image image = Image.FromStream(stream); + // "You must keep the stream open for the lifetime of the Image." + Image image = Image.FromStream(stream); - // so we just create a copy of the image - Bitmap bitmap = new Bitmap(image); + // so we just create a copy of the image + Bitmap bitmap = new Bitmap(image); - // and dispose it right here - image.Dispose(); + // and dispose it right here + image.Dispose(); - return bitmap; - } + return bitmap; } } - return new Bitmap(1, 1); } - - public static Icon GetIcon(string name) - { - name = "LibreHardwareMonitor.Resources." + name; - string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); - for (int i = 0; i < names.Length; i++) - { - if (names[i].Replace('\\', '.') == name) - { - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) - { - return new Icon(stream); - } - } - } - return null; - } - + return new Bitmap(1, 1); } -} + + public static Icon GetIcon(string name) + { + name = "LibreHardwareMonitor.Resources." + name; + string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); + for (int i = 0; i < names.Length; i++) + { + if (names[i].Replace('\\', '.') == name) + { + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) + { + return new Icon(stream); + } + } + } + return null; + } + +} \ No newline at end of file diff --git a/LibreHardwareMonitor/Utilities/HttpServer.cs b/LibreHardwareMonitor/Utilities/HttpServer.cs index e35715b..9379ebe 100644 --- a/LibreHardwareMonitor/Utilities/HttpServer.cs +++ b/LibreHardwareMonitor/Utilities/HttpServer.cs @@ -23,310 +23,310 @@ using LibreHardwareMonitor.Hardware; using LibreHardwareMonitor.UI; using Newtonsoft.Json.Linq; -namespace LibreHardwareMonitor.Utilities +namespace LibreHardwareMonitor.Utilities; + +public class HttpServer { - public class HttpServer + private readonly HttpListener _listener; + private readonly Node _root; + private Thread _listenerThread; + + public HttpServer(Node node, int port, bool authEnabled = false, string userName = "", string password = "") { - private readonly HttpListener _listener; - private readonly Node _root; - private Thread _listenerThread; + _root = node; + ListenerPort = port; + AuthEnabled = authEnabled; + UserName = userName; + Password = password; - public HttpServer(Node node, int port, bool authEnabled = false, string userName = "", string password = "") + try { - _root = node; - ListenerPort = port; - AuthEnabled = authEnabled; - UserName = userName; - Password = password; + _listener = new HttpListener { IgnoreWriteExceptions = true }; + } + catch (PlatformNotSupportedException) + { + _listener = null; + } + } - try + ~HttpServer() + { + if (PlatformNotSupported) + return; + + + StopHttpListener(); + _listener.Abort(); + } + + public bool AuthEnabled { get; set; } + + public int ListenerPort { get; set; } + + public string Password + { + get { return PasswordSHA256; } + set { PasswordSHA256 = ComputeSHA256(value); } + } + + public bool PlatformNotSupported + { + get { return _listener == null; } + } + + public string UserName { get; set; } + + private string PasswordSHA256 { get; set; } + + public bool StartHttpListener() + { + if (PlatformNotSupported) + return false; + + + try + { + if (_listener.IsListening) + return true; + + + string prefix = "http://+:" + ListenerPort + "/"; + _listener.Prefixes.Clear(); + _listener.Prefixes.Add(prefix); + _listener.Realm = "Libre Hardware Monitor"; + _listener.AuthenticationSchemes = AuthEnabled ? AuthenticationSchemes.Basic : AuthenticationSchemes.Anonymous; + _listener.Start(); + + if (_listenerThread == null) { - _listener = new HttpListener { IgnoreWriteExceptions = true }; + _listenerThread = new Thread(HandleRequests); + _listenerThread.Start(); } - catch (PlatformNotSupportedException) + } + catch (Exception) + { + return false; + } + + return true; + } + + public bool StopHttpListener() + { + if (PlatformNotSupported) + return false; + + + try + { + _listenerThread?.Abort(); + _listener.Stop(); + _listenerThread = null; + } + catch (HttpListenerException) + { } + catch (ThreadAbortException) + { } + catch (NullReferenceException) + { } + catch (Exception) + { } + + return true; + } + + private void HandleRequests() + { + while (_listener.IsListening) + { + IAsyncResult context = _listener.BeginGetContext(ListenerCallback, _listener); + context.AsyncWaitHandle.WaitOne(); + } + } + + public static IDictionary ToDictionary(NameValueCollection col) + { + IDictionary dict = new Dictionary(); + foreach (string k in col.AllKeys) + { + dict.Add(k, col[k]); + } + + return dict; + } + + public SensorNode FindSensor(Node node, string id) + { + if (node is SensorNode sNode) + { + if (sNode.Sensor.Identifier.ToString() == id) + return sNode; + } + + foreach (Node child in node.Nodes) + { + SensorNode s = FindSensor(child, id); + if (s != null) { - _listener = null; + return s; } } - ~HttpServer() + return null; + } + + public void SetSensorControlValue(SensorNode sNode, string value) + { + if (sNode.Sensor.Control == null) { - if (PlatformNotSupported) - return; - - - StopHttpListener(); - _listener.Abort(); + throw new ArgumentException("Specified sensor '" + sNode.Sensor.Identifier + "' can not be set"); } - public bool AuthEnabled { get; set; } - - public int ListenerPort { get; set; } - - public string Password + if (value == "null") { - get { return PasswordSHA256; } - set { PasswordSHA256 = ComputeSHA256(value); } + sNode.Sensor.Control.SetDefault(); } - - public bool PlatformNotSupported + else { - get { return _listener == null; } + sNode.Sensor.Control.SetSoftware(float.Parse(value, CultureInfo.InvariantCulture)); } + } - public string UserName { get; set; } + //Handles "/Sensor" requests. + //Parameters are taken from the query part of the URL. + //Get: + //http://localhost:8085/Sensor?action=Get&id=/some/node/path/0 + //The output is either: + //{"result":"fail","message":"Some error message"} + //or: + //{"result":"ok","value":42.0, "format":"{0:F2} RPM"} + // + //Set: + //http://localhost:8085/Sensor?action=Set&id=/some/node/path/0&value=42.0 + //http://localhost:8085/Sensor?action=Set&id=/some/node/path/0&value=null + //The output is either: + //{"result":"fail","message":"Some error message"} + //or: + //{"result":"ok"} + private void HandleSensorRequest(HttpListenerRequest request, JObject result) + { + IDictionary dict = ToDictionary(HttpUtility.ParseQueryString(request.Url.Query)); - private string PasswordSHA256 { get; set; } - - public bool StartHttpListener() + if (dict.ContainsKey("action")) { - if (PlatformNotSupported) - return false; - - - try + if (dict.ContainsKey("id")) { - if (_listener.IsListening) - return true; + SensorNode sNode = FindSensor(_root, dict["id"]); - - string prefix = "http://+:" + ListenerPort + "/"; - _listener.Prefixes.Clear(); - _listener.Prefixes.Add(prefix); - _listener.Realm = "Libre Hardware Monitor"; - _listener.AuthenticationSchemes = AuthEnabled ? AuthenticationSchemes.Basic : AuthenticationSchemes.Anonymous; - _listener.Start(); - - if (_listenerThread == null) + if (sNode == null) { - _listenerThread = new Thread(HandleRequests); - _listenerThread.Start(); + throw new ArgumentException("Unknown id " + dict["id"] + " specified"); } - } - catch (Exception) - { - return false; - } - return true; - } - - public bool StopHttpListener() - { - if (PlatformNotSupported) - return false; - - - try - { - _listenerThread?.Abort(); - _listener.Stop(); - _listenerThread = null; - } - catch (HttpListenerException) - { } - catch (ThreadAbortException) - { } - catch (NullReferenceException) - { } - catch (Exception) - { } - - return true; - } - - private void HandleRequests() - { - while (_listener.IsListening) - { - IAsyncResult context = _listener.BeginGetContext(ListenerCallback, _listener); - context.AsyncWaitHandle.WaitOne(); - } - } - - public static IDictionary ToDictionary(NameValueCollection col) - { - IDictionary dict = new Dictionary(); - foreach (string k in col.AllKeys) - { - dict.Add(k, col[k]); - } - - return dict; - } - - public SensorNode FindSensor(Node node, string id) - { - if (node is SensorNode sNode) - { - if (sNode.Sensor.Identifier.ToString() == id) - return sNode; - } - - foreach (Node child in node.Nodes) - { - SensorNode s = FindSensor(child, id); - if (s != null) + switch (dict["action"]) { - return s; - } - } - - return null; - } - - public void SetSensorControlValue(SensorNode sNode, string value) - { - if (sNode.Sensor.Control == null) - { - throw new ArgumentException("Specified sensor '" + sNode.Sensor.Identifier + "' can not be set"); - } - - if (value == "null") - { - sNode.Sensor.Control.SetDefault(); - } - else - { - sNode.Sensor.Control.SetSoftware(float.Parse(value, CultureInfo.InvariantCulture)); - } - } - - //Handles "/Sensor" requests. - //Parameters are taken from the query part of the URL. - //Get: - //http://localhost:8085/Sensor?action=Get&id=/some/node/path/0 - //The output is either: - //{"result":"fail","message":"Some error message"} - //or: - //{"result":"ok","value":42.0, "format":"{0:F2} RPM"} - // - //Set: - //http://localhost:8085/Sensor?action=Set&id=/some/node/path/0&value=42.0 - //http://localhost:8085/Sensor?action=Set&id=/some/node/path/0&value=null - //The output is either: - //{"result":"fail","message":"Some error message"} - //or: - //{"result":"ok"} - private void HandleSensorRequest(HttpListenerRequest request, JObject result) - { - IDictionary dict = ToDictionary(HttpUtility.ParseQueryString(request.Url.Query)); - - if (dict.ContainsKey("action")) - { - if (dict.ContainsKey("id")) - { - SensorNode sNode = FindSensor(_root, dict["id"]); - - if (sNode == null) - { - throw new ArgumentException("Unknown id " + dict["id"] + " specified"); - } - - switch (dict["action"]) - { - case "Set" when dict.ContainsKey("value"): - SetSensorControlValue(sNode, dict["value"]); - break; - case "Set": - throw new ArgumentNullException("No value provided"); - case "Get": - result["value"] = sNode.Sensor.Value; - result["format"] = sNode.Format; - break; - default: - throw new ArgumentException("Unknown action type " + dict["action"]); - } - } - else - { - throw new ArgumentNullException("No id provided"); + case "Set" when dict.ContainsKey("value"): + SetSensorControlValue(sNode, dict["value"]); + break; + case "Set": + throw new ArgumentNullException("No value provided"); + case "Get": + result["value"] = sNode.Sensor.Value; + result["format"] = sNode.Format; + break; + default: + throw new ArgumentException("Unknown action type " + dict["action"]); } } else { - throw new ArgumentNullException("No action provided"); + throw new ArgumentNullException("No id provided"); } } - - //Handles http POST requests in a REST like manner. - //Currently the only supported base URL is http://localhost:8085/Sensor. - private string HandlePostRequest(HttpListenerRequest request) + else { - JObject result = new JObject { ["result"] = "ok" }; + throw new ArgumentNullException("No action provided"); + } + } - try + //Handles http POST requests in a REST like manner. + //Currently the only supported base URL is http://localhost:8085/Sensor. + private string HandlePostRequest(HttpListenerRequest request) + { + JObject result = new JObject { ["result"] = "ok" }; + + try + { + if (request.Url.Segments.Length == 2) { - if (request.Url.Segments.Length == 2) + if (request.Url.Segments[1] == "Sensor") { - if (request.Url.Segments[1] == "Sensor") - { - HandleSensorRequest(request, result); - } - else - { - throw new ArgumentException("Invalid URL ('" + request.Url.Segments[1] + "'), possible values: ['Sensor']"); - } + HandleSensorRequest(request, result); } else - throw new ArgumentException("Empty URL, possible values: ['Sensor']"); - } - catch (Exception e) - { - result["result"] = "fail"; - result["message"] = e.ToString(); + { + throw new ArgumentException("Invalid URL ('" + request.Url.Segments[1] + "'), possible values: ['Sensor']"); + } } + else + throw new ArgumentException("Empty URL, possible values: ['Sensor']"); + } + catch (Exception e) + { + result["result"] = "fail"; + result["message"] = e.ToString(); + } #if DEBUG - return result.ToString(Newtonsoft.Json.Formatting.Indented); + return result.ToString(Newtonsoft.Json.Formatting.Indented); #else return result.ToString(Newtonsoft.Json.Formatting.None); #endif + } + + private void ListenerCallback(IAsyncResult result) + { + HttpListener listener = (HttpListener)result.AsyncState; + if (listener == null || !listener.IsListening) + return; + + + // Call EndGetContext to complete the asynchronous operation. + HttpListenerContext context; + try + { + context = listener.EndGetContext(result); + } + catch (Exception) + { + return; } - private void ListenerCallback(IAsyncResult result) + HttpListenerRequest request = context.Request; + + bool authenticated; + + if (AuthEnabled) { - HttpListener listener = (HttpListener)result.AsyncState; - if (listener == null || !listener.IsListening) - return; - - - // Call EndGetContext to complete the asynchronous operation. - HttpListenerContext context; try { - context = listener.EndGetContext(result); + HttpListenerBasicIdentity identity = (HttpListenerBasicIdentity)context.User.Identity; + authenticated = (identity.Name == UserName) & (ComputeSHA256(identity.Password) == Password); } - catch (Exception) + catch { - return; + authenticated = false; } + } + else + { + authenticated = true; + } - HttpListenerRequest request = context.Request; - - bool authenticated; - - if (AuthEnabled) + if (authenticated) + { + switch (request.HttpMethod) { - try - { - HttpListenerBasicIdentity identity = (HttpListenerBasicIdentity)context.User.Identity; - authenticated = (identity.Name == UserName) & (ComputeSHA256(identity.Password) == Password); - } - catch - { - authenticated = false; - } - } - else - { - authenticated = true; - } - - if (authenticated) - { - switch (request.HttpMethod) - { - case "POST": + case "POST": { string postResult = HandlePostRequest(request); @@ -342,7 +342,7 @@ namespace LibreHardwareMonitor.Utilities break; } - case "GET": + case "GET": { string requestedFile = request.RawUrl.Substring(1); @@ -370,338 +370,337 @@ namespace LibreHardwareMonitor.Utilities break; } - default: + default: { context.Response.StatusCode = 404; break; } - } - } - else - { - context.Response.StatusCode = 401; } + } + else + { + context.Response.StatusCode = 401; + } - if (context.Response.StatusCode == 401) - { - const string responseString = @"401 Unauthorized + if (context.Response.StatusCode == 401) + { + const string responseString = @"401 Unauthorized

401 Unauthorized

Authorization required. "; - byte[] buffer = Encoding.UTF8.GetBytes(responseString); - context.Response.ContentLength64 = buffer.Length; - context.Response.StatusCode = 401; - Stream output = context.Response.OutputStream; - output.Write(buffer, 0, buffer.Length); - output.Close(); - } - - try - { - context.Response.Close(); - } - catch - { - // client closed connection before the content was sent - } + byte[] buffer = Encoding.UTF8.GetBytes(responseString); + context.Response.ContentLength64 = buffer.Length; + context.Response.StatusCode = 401; + Stream output = context.Response.OutputStream; + output.Write(buffer, 0, buffer.Length); + output.Close(); } - private void ServeResourceFile(HttpListenerResponse response, string name, string ext) + try { - // resource names do not support the hyphen - name = "LibreHardwareMonitor.Resources." + - name.Replace("custom-theme", "custom_theme"); - - string[] names = - Assembly.GetExecutingAssembly().GetManifestResourceNames(); - - for (int i = 0; i < names.Length; i++) - { - if (names[i].Replace('\\', '.') == name) - { - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) - { - response.ContentType = GetContentType("." + ext); - response.ContentLength64 = stream.Length; - byte[] buffer = new byte[512 * 1024]; - try - { - Stream output = response.OutputStream; - int len; - while ((len = stream.Read(buffer, 0, buffer.Length)) > 0) - { - output.Write(buffer, 0, len); - } - - output.Flush(); - output.Close(); - response.Close(); - } - catch (HttpListenerException) - { } - catch (InvalidOperationException) - { } - - return; - } - } - } - - response.StatusCode = 404; - response.Close(); + context.Response.Close(); } - - private void ServeResourceImage(HttpListenerResponse response, string name) + catch { - name = "LibreHardwareMonitor.Resources." + name; + // client closed connection before the content was sent + } + } - string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); + private void ServeResourceFile(HttpListenerResponse response, string name, string ext) + { + // resource names do not support the hyphen + name = "LibreHardwareMonitor.Resources." + + name.Replace("custom-theme", "custom_theme"); - for (int i = 0; i < names.Length; i++) + string[] names = + Assembly.GetExecutingAssembly().GetManifestResourceNames(); + + for (int i = 0; i < names.Length; i++) + { + if (names[i].Replace('\\', '.') == name) { - if (names[i].Replace('\\', '.') == name) + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) { - using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) + response.ContentType = GetContentType("." + ext); + response.ContentLength64 = stream.Length; + byte[] buffer = new byte[512 * 1024]; + try { - Image image = Image.FromStream(stream); - response.ContentType = "image/png"; - try + Stream output = response.OutputStream; + int len; + while ((len = stream.Read(buffer, 0, buffer.Length)) > 0) { - Stream output = response.OutputStream; - using (MemoryStream ms = new MemoryStream()) - { - image.Save(ms, ImageFormat.Png); - ms.WriteTo(output); - } - - output.Close(); + output.Write(buffer, 0, len); } - catch (HttpListenerException) - { } - image.Dispose(); + output.Flush(); + output.Close(); response.Close(); - return; } + catch (HttpListenerException) + { } + catch (InvalidOperationException) + { } + + return; } } - - response.StatusCode = 404; - response.Close(); } - private void SendJson(HttpListenerResponse response, HttpListenerRequest request = null) + response.StatusCode = 404; + response.Close(); + } + + private void ServeResourceImage(HttpListenerResponse response, string name) + { + name = "LibreHardwareMonitor.Resources." + name; + + string[] names = Assembly.GetExecutingAssembly().GetManifestResourceNames(); + + for (int i = 0; i < names.Length; i++) { - JObject json = new JObject(); + if (names[i].Replace('\\', '.') == name) + { + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(names[i])) + { + Image image = Image.FromStream(stream); + response.ContentType = "image/png"; + try + { + Stream output = response.OutputStream; + using (MemoryStream ms = new MemoryStream()) + { + image.Save(ms, ImageFormat.Png); + ms.WriteTo(output); + } - int nodeIndex = 0; + output.Close(); + } + catch (HttpListenerException) + { } - json["id"] = nodeIndex++; - json["Text"] = "Sensor"; - json["Min"] = "Min"; - json["Value"] = "Value"; - json["Max"] = "Max"; - json["ImageURL"] = string.Empty; + image.Dispose(); + response.Close(); + return; + } + } + } - JArray children = new JArray { GenerateJsonForNode(_root, ref nodeIndex) }; - json["Children"] = children; + response.StatusCode = 404; + response.Close(); + } + + private void SendJson(HttpListenerResponse response, HttpListenerRequest request = null) + { + JObject json = new JObject(); + + int nodeIndex = 0; + + json["id"] = nodeIndex++; + json["Text"] = "Sensor"; + json["Min"] = "Min"; + json["Value"] = "Value"; + json["Max"] = "Max"; + json["ImageURL"] = string.Empty; + + JArray children = new JArray { GenerateJsonForNode(_root, ref nodeIndex) }; + json["Children"] = children; #if DEBUG - string responseContent = json.ToString(Newtonsoft.Json.Formatting.Indented); + string responseContent = json.ToString(Newtonsoft.Json.Formatting.Indented); #else string responseContent = json.ToString(Newtonsoft.Json.Formatting.None); #endif - byte[] buffer = Encoding.UTF8.GetBytes(responseContent); + byte[] buffer = Encoding.UTF8.GetBytes(responseContent); - bool acceptGzip; - try - { - acceptGzip = (request != null) && (request.Headers["Accept-Encoding"].ToLower().IndexOf("gzip", StringComparison.OrdinalIgnoreCase) >= 0); - } - catch - { - acceptGzip = false; - } + bool acceptGzip; + try + { + acceptGzip = (request != null) && (request.Headers["Accept-Encoding"].ToLower().IndexOf("gzip", StringComparison.OrdinalIgnoreCase) >= 0); + } + catch + { + acceptGzip = false; + } + if (acceptGzip) + response.AddHeader("Content-Encoding", "gzip"); + + response.AddHeader("Cache-Control", "no-cache"); + response.AddHeader("Access-Control-Allow-Origin", "*"); + response.ContentType = "application/json"; + try + { if (acceptGzip) - response.AddHeader("Content-Encoding", "gzip"); - - response.AddHeader("Cache-Control", "no-cache"); - response.AddHeader("Access-Control-Allow-Origin", "*"); - response.ContentType = "application/json"; - try { - if (acceptGzip) + using (var ms = new MemoryStream()) { - using (var ms = new MemoryStream()) - { - using (var zip = new GZipStream(ms, CompressionMode.Compress, true)) - zip.Write(buffer, 0, buffer.Length); + using (var zip = new GZipStream(ms, CompressionMode.Compress, true)) + zip.Write(buffer, 0, buffer.Length); - buffer = ms.ToArray(); - } + buffer = ms.ToArray(); } - - response.ContentLength64 = buffer.Length; - Stream output = response.OutputStream; - output.Write(buffer, 0, buffer.Length); - output.Close(); } - catch (HttpListenerException) - { } - response.Close(); + response.ContentLength64 = buffer.Length; + Stream output = response.OutputStream; + output.Write(buffer, 0, buffer.Length); + output.Close(); + } + catch (HttpListenerException) + { } + + response.Close(); + } + + private JObject GenerateJsonForNode(Node n, ref int nodeIndex) + { + JObject jsonNode = new JObject + { + ["id"] = nodeIndex++, + ["Text"] = n.Text, + ["Min"] = string.Empty, + ["Value"] = string.Empty, + ["Max"] = string.Empty + }; + + if (n is SensorNode sensorNode) + { + jsonNode["SensorId"] = sensorNode.Sensor.Identifier.ToString(); + jsonNode["Type"] = sensorNode.Sensor.SensorType.ToString(); + jsonNode["Min"] = sensorNode.Min; + jsonNode["Value"] = sensorNode.Value; + jsonNode["Max"] = sensorNode.Max; + jsonNode["ImageURL"] = "images/transparent.png"; + } + else if (n is HardwareNode hardwareNode) + { + jsonNode["ImageURL"] = "images_icon/" + GetHardwareImageFile(hardwareNode); + } + else if (n is TypeNode typeNode) + { + jsonNode["ImageURL"] = "images_icon/" + GetTypeImageFile(typeNode); + } + else + { + jsonNode["ImageURL"] = "images_icon/computer.png"; } - private JObject GenerateJsonForNode(Node n, ref int nodeIndex) + JArray children = new JArray(); + foreach (Node child in n.Nodes) { - JObject jsonNode = new JObject - { - ["id"] = nodeIndex++, - ["Text"] = n.Text, - ["Min"] = string.Empty, - ["Value"] = string.Empty, - ["Max"] = string.Empty - }; - - if (n is SensorNode sensorNode) - { - jsonNode["SensorId"] = sensorNode.Sensor.Identifier.ToString(); - jsonNode["Type"] = sensorNode.Sensor.SensorType.ToString(); - jsonNode["Min"] = sensorNode.Min; - jsonNode["Value"] = sensorNode.Value; - jsonNode["Max"] = sensorNode.Max; - jsonNode["ImageURL"] = "images/transparent.png"; - } - else if (n is HardwareNode hardwareNode) - { - jsonNode["ImageURL"] = "images_icon/" + GetHardwareImageFile(hardwareNode); - } - else if (n is TypeNode typeNode) - { - jsonNode["ImageURL"] = "images_icon/" + GetTypeImageFile(typeNode); - } - else - { - jsonNode["ImageURL"] = "images_icon/computer.png"; - } - - JArray children = new JArray(); - foreach (Node child in n.Nodes) - { - children.Add(GenerateJsonForNode(child, ref nodeIndex)); - } - - jsonNode["Children"] = children; - - return jsonNode; + children.Add(GenerateJsonForNode(child, ref nodeIndex)); } - private static string GetContentType(string extension) + jsonNode["Children"] = children; + + return jsonNode; + } + + private static string GetContentType(string extension) + { + switch (extension) { - switch (extension) - { - case ".avi": return "video/x-msvideo"; - case ".css": return "text/css"; - case ".doc": return "application/msword"; - case ".gif": return "image/gif"; - case ".htm": - case ".html": return "text/html"; - case ".jpg": - case ".jpeg": return "image/jpeg"; - case ".js": return "application/x-javascript"; - case ".mp3": return "audio/mpeg"; - case ".png": return "image/png"; - case ".pdf": return "application/pdf"; - case ".ppt": return "application/vnd.ms-powerpoint"; - case ".zip": return "application/zip"; - case ".txt": return "text/plain"; - default: return "application/octet-stream"; - } - } - - private static string GetHardwareImageFile(HardwareNode hn) - { - switch (hn.Hardware.HardwareType) - { - case HardwareType.Cpu: - return "cpu.png"; - case HardwareType.GpuNvidia: - return "nvidia.png"; - case HardwareType.GpuAmd: - return "ati.png"; - case HardwareType.GpuIntel: - return "intel.png"; - case HardwareType.Storage: - return "hdd.png"; - case HardwareType.Motherboard: - return "mainboard.png"; - case HardwareType.SuperIO: - return "chip.png"; - case HardwareType.Memory: - return "ram.png"; - case HardwareType.Cooler: - return "fan.png"; - case HardwareType.Network: - return "nic.png"; - case HardwareType.Psu: - return "power-supply.png"; - case HardwareType.Battery: - return "battery.png"; - default: - return "cpu.png"; - } - } - - private static string GetTypeImageFile(TypeNode tn) - { - switch (tn.SensorType) - { - case SensorType.Voltage: - case SensorType.Current: - return "voltage.png"; - case SensorType.Clock: - return "clock.png"; - case SensorType.Load: - return "load.png"; - case SensorType.Temperature: - return "temperature.png"; - case SensorType.Fan: - return "fan.png"; - case SensorType.Flow: - return "flow.png"; - case SensorType.Control: - return "control.png"; - case SensorType.Level: - return "level.png"; - case SensorType.Power: - return "power.png"; - case SensorType.Noise: - return "loudspeaker.png"; - case SensorType.Throughput: - return "throughput.png"; - default: - return "power.png"; - } - } - - private string ComputeSHA256(string text) - { - using (SHA256 hash = SHA256.Create()) - { - return string.Concat(hash - .ComputeHash(Encoding.UTF8.GetBytes(text)) - .Select(item => item.ToString("x2"))); - } - } - - public void Quit() - { - if (PlatformNotSupported) - return; - - - StopHttpListener(); - _listener.Abort(); + case ".avi": return "video/x-msvideo"; + case ".css": return "text/css"; + case ".doc": return "application/msword"; + case ".gif": return "image/gif"; + case ".htm": + case ".html": return "text/html"; + case ".jpg": + case ".jpeg": return "image/jpeg"; + case ".js": return "application/x-javascript"; + case ".mp3": return "audio/mpeg"; + case ".png": return "image/png"; + case ".pdf": return "application/pdf"; + case ".ppt": return "application/vnd.ms-powerpoint"; + case ".zip": return "application/zip"; + case ".txt": return "text/plain"; + default: return "application/octet-stream"; } } -} + + private static string GetHardwareImageFile(HardwareNode hn) + { + switch (hn.Hardware.HardwareType) + { + case HardwareType.Cpu: + return "cpu.png"; + case HardwareType.GpuNvidia: + return "nvidia.png"; + case HardwareType.GpuAmd: + return "ati.png"; + case HardwareType.GpuIntel: + return "intel.png"; + case HardwareType.Storage: + return "hdd.png"; + case HardwareType.Motherboard: + return "mainboard.png"; + case HardwareType.SuperIO: + return "chip.png"; + case HardwareType.Memory: + return "ram.png"; + case HardwareType.Cooler: + return "fan.png"; + case HardwareType.Network: + return "nic.png"; + case HardwareType.Psu: + return "power-supply.png"; + case HardwareType.Battery: + return "battery.png"; + default: + return "cpu.png"; + } + } + + private static string GetTypeImageFile(TypeNode tn) + { + switch (tn.SensorType) + { + case SensorType.Voltage: + case SensorType.Current: + return "voltage.png"; + case SensorType.Clock: + return "clock.png"; + case SensorType.Load: + return "load.png"; + case SensorType.Temperature: + return "temperature.png"; + case SensorType.Fan: + return "fan.png"; + case SensorType.Flow: + return "flow.png"; + case SensorType.Control: + return "control.png"; + case SensorType.Level: + return "level.png"; + case SensorType.Power: + return "power.png"; + case SensorType.Noise: + return "loudspeaker.png"; + case SensorType.Throughput: + return "throughput.png"; + default: + return "power.png"; + } + } + + private string ComputeSHA256(string text) + { + using (SHA256 hash = SHA256.Create()) + { + return string.Concat(hash + .ComputeHash(Encoding.UTF8.GetBytes(text)) + .Select(item => item.ToString("x2"))); + } + } + + public void Quit() + { + if (PlatformNotSupported) + return; + + + StopHttpListener(); + _listener.Abort(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/Utilities/IconFactory.cs b/LibreHardwareMonitor/Utilities/IconFactory.cs index a47bee8..54947e9 100644 --- a/LibreHardwareMonitor/Utilities/IconFactory.cs +++ b/LibreHardwareMonitor/Utilities/IconFactory.cs @@ -10,189 +10,188 @@ using System.Drawing.Imaging; using System.IO; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Utilities +namespace LibreHardwareMonitor.Utilities; + +public static class IconFactory { - public static class IconFactory + private struct BITMAPINFOHEADER { - private struct BITMAPINFOHEADER + public readonly uint Size; + public readonly int Width; + public readonly int Height; + public readonly ushort Planes; + public readonly ushort BitCount; + public readonly uint Compression; + public readonly uint SizeImage; + public readonly int XPelsPerMeter; + public readonly int YPelsPerMeter; + public readonly uint ClrUsed; + public readonly uint ClrImportant; + + public BITMAPINFOHEADER(int width, int height, int bitCount) { - public readonly uint Size; - public readonly int Width; - public readonly int Height; - public readonly ushort Planes; - public readonly ushort BitCount; - public readonly uint Compression; - public readonly uint SizeImage; - public readonly int XPelsPerMeter; - public readonly int YPelsPerMeter; - public readonly uint ClrUsed; - public readonly uint ClrImportant; - - public BITMAPINFOHEADER(int width, int height, int bitCount) - { - Size = 40; - Width = width; - Height = height; - Planes = 1; - BitCount = (ushort)bitCount; - Compression = 0; - SizeImage = 0; - XPelsPerMeter = 0; - YPelsPerMeter = 0; - ClrUsed = 0; - ClrImportant = 0; - } - - public void Write(BinaryWriter bw) - { - bw.Write(Size); - bw.Write(Width); - bw.Write(Height); - bw.Write(Planes); - bw.Write(BitCount); - bw.Write(Compression); - bw.Write(SizeImage); - bw.Write(XPelsPerMeter); - bw.Write(YPelsPerMeter); - bw.Write(ClrUsed); - bw.Write(ClrImportant); - } + Size = 40; + Width = width; + Height = height; + Planes = 1; + BitCount = (ushort)bitCount; + Compression = 0; + SizeImage = 0; + XPelsPerMeter = 0; + YPelsPerMeter = 0; + ClrUsed = 0; + ClrImportant = 0; } - private struct ICONIMAGE + public void Write(BinaryWriter bw) { - public BITMAPINFOHEADER Header; - public readonly byte[] Colors; - public readonly int MaskSize; - - public ICONIMAGE(int width, int height, byte[] colors) - { - Header = new BITMAPINFOHEADER(width, height << 1, (8 * colors.Length) / (width * height)); - Colors = colors; - MaskSize = (width * height) >> 3; - } - - public void Write(BinaryWriter bw) - { - Header.Write(bw); - int stride = Header.Width << 2; - for (int i = (Header.Height >> 1) - 1; i >= 0; i--) - bw.Write(Colors, i * stride, stride); - for (int i = 0; i < 2 * MaskSize; i++) - bw.Write((byte)0); - } - } - - private struct ICONDIRENTRY - { - public readonly byte Width; - public readonly byte Height; - public readonly byte ColorCount; - public readonly byte Reserved; - public readonly ushort Planes; - public readonly ushort BitCount; - public readonly uint BytesInRes; - public uint ImageOffset; - - public ICONDIRENTRY(ICONIMAGE image, int imageOffset) - { - Width = (byte)image.Header.Width; - Height = (byte)(image.Header.Height >> 1); - ColorCount = 0; - Reserved = 0; - Planes = image.Header.Planes; - BitCount = image.Header.BitCount; - BytesInRes = (uint)(image.Header.Size + image.Colors.Length + image.MaskSize + image.MaskSize); - ImageOffset = (uint)imageOffset; - } - - public void Write(BinaryWriter bw) - { - bw.Write(Width); - bw.Write(Height); - bw.Write(ColorCount); - bw.Write(Reserved); - bw.Write(Planes); - bw.Write(BitCount); - bw.Write(BytesInRes); - bw.Write(ImageOffset); - } - - public uint Size - { - get { return 16; } - } - } - - private struct ICONDIR - { - public readonly ushort Reserved; - public readonly ushort Type; - public readonly ushort Count; - public readonly ICONDIRENTRY[] Entries; - - public ICONDIR(ICONDIRENTRY[] entries) - { - Reserved = 0; - Type = 1; - Count = (ushort)entries.Length; - Entries = entries; - } - - public void Write(BinaryWriter bw) - { - bw.Write(Reserved); - bw.Write(Type); - bw.Write(Count); - for (int i = 0; i < Entries.Length; i++) - Entries[i].Write(bw); - } - - public uint Size - { - get - { - return (uint)(6 + Entries.Length * (Entries.Length > 0 ? Entries[0].Size : 0)); - } - } - } - - private static readonly BinaryWriter BinaryWriter = new BinaryWriter(new MemoryStream()); - - public static Icon Create(byte[] colors, int width, int height, PixelFormat format) - { - if (format != PixelFormat.Format32bppArgb) - throw new NotImplementedException(); - - ICONIMAGE image = new ICONIMAGE(width, height, colors); - ICONDIR dir = new ICONDIR(new[] { new ICONDIRENTRY(image, 0) }); - dir.Entries[0].ImageOffset = dir.Size; - - BinaryWriter.BaseStream.Position = 0; - dir.Write(BinaryWriter); - image.Write(BinaryWriter); - - BinaryWriter.BaseStream.Position = 0; - Icon icon = new Icon(BinaryWriter.BaseStream); - - return icon; - } - - [DllImport("user32", SetLastError = true)] - static extern bool DestroyIcon(IntPtr handle); - - public static Icon Create(Bitmap bitmap) - { - IntPtr hIcon = bitmap.GetHicon(); - Icon icon = Icon.FromHandle(hIcon); - - return icon; - } - - public static void Destroy(this Icon icon) - { - DestroyIcon(icon.Handle); - icon.Dispose(); + bw.Write(Size); + bw.Write(Width); + bw.Write(Height); + bw.Write(Planes); + bw.Write(BitCount); + bw.Write(Compression); + bw.Write(SizeImage); + bw.Write(XPelsPerMeter); + bw.Write(YPelsPerMeter); + bw.Write(ClrUsed); + bw.Write(ClrImportant); } } -} + + private struct ICONIMAGE + { + public BITMAPINFOHEADER Header; + public readonly byte[] Colors; + public readonly int MaskSize; + + public ICONIMAGE(int width, int height, byte[] colors) + { + Header = new BITMAPINFOHEADER(width, height << 1, (8 * colors.Length) / (width * height)); + Colors = colors; + MaskSize = (width * height) >> 3; + } + + public void Write(BinaryWriter bw) + { + Header.Write(bw); + int stride = Header.Width << 2; + for (int i = (Header.Height >> 1) - 1; i >= 0; i--) + bw.Write(Colors, i * stride, stride); + for (int i = 0; i < 2 * MaskSize; i++) + bw.Write((byte)0); + } + } + + private struct ICONDIRENTRY + { + public readonly byte Width; + public readonly byte Height; + public readonly byte ColorCount; + public readonly byte Reserved; + public readonly ushort Planes; + public readonly ushort BitCount; + public readonly uint BytesInRes; + public uint ImageOffset; + + public ICONDIRENTRY(ICONIMAGE image, int imageOffset) + { + Width = (byte)image.Header.Width; + Height = (byte)(image.Header.Height >> 1); + ColorCount = 0; + Reserved = 0; + Planes = image.Header.Planes; + BitCount = image.Header.BitCount; + BytesInRes = (uint)(image.Header.Size + image.Colors.Length + image.MaskSize + image.MaskSize); + ImageOffset = (uint)imageOffset; + } + + public void Write(BinaryWriter bw) + { + bw.Write(Width); + bw.Write(Height); + bw.Write(ColorCount); + bw.Write(Reserved); + bw.Write(Planes); + bw.Write(BitCount); + bw.Write(BytesInRes); + bw.Write(ImageOffset); + } + + public uint Size + { + get { return 16; } + } + } + + private struct ICONDIR + { + public readonly ushort Reserved; + public readonly ushort Type; + public readonly ushort Count; + public readonly ICONDIRENTRY[] Entries; + + public ICONDIR(ICONDIRENTRY[] entries) + { + Reserved = 0; + Type = 1; + Count = (ushort)entries.Length; + Entries = entries; + } + + public void Write(BinaryWriter bw) + { + bw.Write(Reserved); + bw.Write(Type); + bw.Write(Count); + for (int i = 0; i < Entries.Length; i++) + Entries[i].Write(bw); + } + + public uint Size + { + get + { + return (uint)(6 + Entries.Length * (Entries.Length > 0 ? Entries[0].Size : 0)); + } + } + } + + private static readonly BinaryWriter BinaryWriter = new BinaryWriter(new MemoryStream()); + + public static Icon Create(byte[] colors, int width, int height, PixelFormat format) + { + if (format != PixelFormat.Format32bppArgb) + throw new NotImplementedException(); + + ICONIMAGE image = new ICONIMAGE(width, height, colors); + ICONDIR dir = new ICONDIR(new[] { new ICONDIRENTRY(image, 0) }); + dir.Entries[0].ImageOffset = dir.Size; + + BinaryWriter.BaseStream.Position = 0; + dir.Write(BinaryWriter); + image.Write(BinaryWriter); + + BinaryWriter.BaseStream.Position = 0; + Icon icon = new Icon(BinaryWriter.BaseStream); + + return icon; + } + + [DllImport("user32", SetLastError = true)] + static extern bool DestroyIcon(IntPtr handle); + + public static Icon Create(Bitmap bitmap) + { + IntPtr hIcon = bitmap.GetHicon(); + Icon icon = Icon.FromHandle(hIcon); + + return icon; + } + + public static void Destroy(this Icon icon) + { + DestroyIcon(icon.Handle); + icon.Dispose(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/Utilities/Logger.cs b/LibreHardwareMonitor/Utilities/Logger.cs index bb67914..533244b 100644 --- a/LibreHardwareMonitor/Utilities/Logger.cs +++ b/LibreHardwareMonitor/Utilities/Logger.cs @@ -11,198 +11,197 @@ using System.IO; using System.Linq; using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitor.Utilities +namespace LibreHardwareMonitor.Utilities; + +public class Logger { - public class Logger + private const string FileNameFormat = "LibreHardwareMonitorLog-{0:yyyy-MM-dd}.csv"; + + private readonly IComputer _computer; + + private DateTime _day = DateTime.MinValue; + private string _fileName; + private string[] _identifiers; + private ISensor[] _sensors; + private DateTime _lastLoggedTime = DateTime.MinValue; + + public Logger(IComputer computer) { - private const string FileNameFormat = "LibreHardwareMonitorLog-{0:yyyy-MM-dd}.csv"; + _computer = computer; + _computer.HardwareAdded += HardwareAdded; + _computer.HardwareRemoved += HardwareRemoved; + } - private readonly IComputer _computer; + private void HardwareRemoved(IHardware hardware) + { + hardware.SensorAdded -= SensorAdded; + hardware.SensorRemoved -= SensorRemoved; - private DateTime _day = DateTime.MinValue; - private string _fileName; - private string[] _identifiers; - private ISensor[] _sensors; - private DateTime _lastLoggedTime = DateTime.MinValue; + foreach (ISensor sensor in hardware.Sensors) + SensorRemoved(sensor); - public Logger(IComputer computer) + foreach (IHardware subHardware in hardware.SubHardware) + HardwareRemoved(subHardware); + } + + private void HardwareAdded(IHardware hardware) + { + foreach (ISensor sensor in hardware.Sensors) + SensorAdded(sensor); + + hardware.SensorAdded += SensorAdded; + hardware.SensorRemoved += SensorRemoved; + + foreach (IHardware subHardware in hardware.SubHardware) + HardwareAdded(subHardware); + } + + private void SensorAdded(ISensor sensor) + { + if (_sensors == null) + return; + + for (int i = 0; i < _sensors.Length; i++) { - _computer = computer; - _computer.HardwareAdded += HardwareAdded; - _computer.HardwareRemoved += HardwareRemoved; + if (sensor.Identifier.ToString() == _identifiers[i]) + _sensors[i] = sensor; + } + } + + private void SensorRemoved(ISensor sensor) + { + if (_sensors == null) + return; + + for (int i = 0; i < _sensors.Length; i++) + { + if (sensor == _sensors[i]) + _sensors[i] = null; + } + } + + private static string GetFileName(DateTime date) + { + return AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + string.Format(FileNameFormat, date); + } + + private bool OpenExistingLogFile() + { + if (!File.Exists(_fileName)) + return false; + + try + { + string line; + using (StreamReader reader = new StreamReader(_fileName)) + line = reader.ReadLine(); + + if (string.IsNullOrEmpty(line)) + return false; + + _identifiers = line.Split(',').Skip(1).ToArray(); + } + catch + { + _identifiers = null; + return false; } - private void HardwareRemoved(IHardware hardware) + if (_identifiers.Length == 0) { - hardware.SensorAdded -= SensorAdded; - hardware.SensorRemoved -= SensorRemoved; - - foreach (ISensor sensor in hardware.Sensors) - SensorRemoved(sensor); - - foreach (IHardware subHardware in hardware.SubHardware) - HardwareRemoved(subHardware); + _identifiers = null; + return false; } - private void HardwareAdded(IHardware hardware) + _sensors = new ISensor[_identifiers.Length]; + SensorVisitor visitor = new SensorVisitor(sensor => { - foreach (ISensor sensor in hardware.Sensors) - SensorAdded(sensor); - - hardware.SensorAdded += SensorAdded; - hardware.SensorRemoved += SensorRemoved; - - foreach (IHardware subHardware in hardware.SubHardware) - HardwareAdded(subHardware); - } - - private void SensorAdded(ISensor sensor) - { - if (_sensors == null) - return; - - for (int i = 0; i < _sensors.Length; i++) - { + for (int i = 0; i < _identifiers.Length; i++) if (sensor.Identifier.ToString() == _identifiers[i]) _sensors[i] = sensor; - } - } + }); + visitor.VisitComputer(_computer); + return true; + } - private void SensorRemoved(ISensor sensor) + private void CreateNewLogFile() + { + IList list = new List(); + SensorVisitor visitor = new SensorVisitor(sensor => { - if (_sensors == null) - return; + list.Add(sensor); + }); + visitor.VisitComputer(_computer); + _sensors = list.ToArray(); + _identifiers = _sensors.Select(s => s.Identifier.ToString()).ToArray(); + using (StreamWriter writer = new StreamWriter(_fileName, false)) + { + writer.Write(","); for (int i = 0; i < _sensors.Length; i++) { - if (sensor == _sensors[i]) - _sensors[i] = null; + writer.Write(_sensors[i].Identifier); + if (i < _sensors.Length - 1) + writer.Write(","); + else + writer.WriteLine(); + } + + writer.Write("Time,"); + for (int i = 0; i < _sensors.Length; i++) + { + writer.Write('"'); + writer.Write(_sensors[i].Name); + writer.Write('"'); + if (i < _sensors.Length - 1) + writer.Write(","); + else + writer.WriteLine(); } } + } - private static string GetFileName(DateTime date) + public TimeSpan LoggingInterval { get; set; } + + public void Log() + { + DateTime now = DateTime.Now; + + if (_lastLoggedTime + LoggingInterval - new TimeSpan(5000000) > now) + return; + + if (_day != now.Date || !File.Exists(_fileName)) { - return AppDomain.CurrentDomain.BaseDirectory + Path.DirectorySeparatorChar + string.Format(FileNameFormat, date); + _day = now.Date; + _fileName = GetFileName(_day); + + if (!OpenExistingLogFile()) + CreateNewLogFile(); } - private bool OpenExistingLogFile() + try { - if (!File.Exists(_fileName)) - return false; - - try - { - string line; - using (StreamReader reader = new StreamReader(_fileName)) - line = reader.ReadLine(); - - if (string.IsNullOrEmpty(line)) - return false; - - _identifiers = line.Split(',').Skip(1).ToArray(); - } - catch - { - _identifiers = null; - return false; - } - - if (_identifiers.Length == 0) - { - _identifiers = null; - return false; - } - - _sensors = new ISensor[_identifiers.Length]; - SensorVisitor visitor = new SensorVisitor(sensor => - { - for (int i = 0; i < _identifiers.Length; i++) - if (sensor.Identifier.ToString() == _identifiers[i]) - _sensors[i] = sensor; - }); - visitor.VisitComputer(_computer); - return true; - } - - private void CreateNewLogFile() - { - IList list = new List(); - SensorVisitor visitor = new SensorVisitor(sensor => - { - list.Add(sensor); - }); - visitor.VisitComputer(_computer); - _sensors = list.ToArray(); - _identifiers = _sensors.Select(s => s.Identifier.ToString()).ToArray(); - - using (StreamWriter writer = new StreamWriter(_fileName, false)) + using (StreamWriter writer = new StreamWriter(new FileStream(_fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))) { + writer.Write(now.ToString("G", CultureInfo.InvariantCulture)); writer.Write(","); for (int i = 0; i < _sensors.Length; i++) { - writer.Write(_sensors[i].Identifier); - if (i < _sensors.Length - 1) - writer.Write(","); - else - writer.WriteLine(); - } - - writer.Write("Time,"); - for (int i = 0; i < _sensors.Length; i++) - { - writer.Write('"'); - writer.Write(_sensors[i].Name); - writer.Write('"'); - if (i < _sensors.Length - 1) - writer.Write(","); - else - writer.WriteLine(); - } - } - } - - public TimeSpan LoggingInterval { get; set; } - - public void Log() - { - DateTime now = DateTime.Now; - - if (_lastLoggedTime + LoggingInterval - new TimeSpan(5000000) > now) - return; - - if (_day != now.Date || !File.Exists(_fileName)) - { - _day = now.Date; - _fileName = GetFileName(_day); - - if (!OpenExistingLogFile()) - CreateNewLogFile(); - } - - try - { - using (StreamWriter writer = new StreamWriter(new FileStream(_fileName, FileMode.Append, FileAccess.Write, FileShare.ReadWrite))) - { - writer.Write(now.ToString("G", CultureInfo.InvariantCulture)); - writer.Write(","); - for (int i = 0; i < _sensors.Length; i++) + if (_sensors[i] != null) { - if (_sensors[i] != null) - { - float? value = _sensors[i].Value; - if (value.HasValue) - writer.Write(value.Value.ToString("R", CultureInfo.InvariantCulture)); - } - if (i < _sensors.Length - 1) - writer.Write(","); - else - writer.WriteLine(); + float? value = _sensors[i].Value; + if (value.HasValue) + writer.Write(value.Value.ToString("R", CultureInfo.InvariantCulture)); } + if (i < _sensors.Length - 1) + writer.Write(","); + else + writer.WriteLine(); } } - catch (IOException) { } - - _lastLoggedTime = now; } + catch (IOException) { } + + _lastLoggedTime = now; } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitor/Utilities/PersistentSettings.cs b/LibreHardwareMonitor/Utilities/PersistentSettings.cs index 7be9545..3d08756 100644 --- a/LibreHardwareMonitor/Utilities/PersistentSettings.cs +++ b/LibreHardwareMonitor/Utilities/PersistentSettings.cs @@ -12,220 +12,219 @@ using System.Text; using System.Xml; using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitor.Utilities -{ - public class PersistentSettings : ISettings - { - private readonly IDictionary _settings = new Dictionary(); +namespace LibreHardwareMonitor.Utilities; - public void Load(string fileName) +public class PersistentSettings : ISettings +{ + private readonly IDictionary _settings = new Dictionary(); + + public void Load(string fileName) + { + XmlDocument doc = new XmlDocument(); + try + { + doc.Load(fileName); + } + catch { - XmlDocument doc = new XmlDocument(); try { - doc.Load(fileName); - } - catch - { - try - { - File.Delete(fileName); - } - catch { } - - string backupFileName = fileName + ".backup"; - try - { - doc.Load(backupFileName); - } - catch - { - try - { - File.Delete(backupFileName); - } - catch { } - - return; - } - } - - XmlNodeList list = doc.GetElementsByTagName("appSettings"); - foreach (XmlNode node in list) - { - XmlNode parent = node.ParentNode; - if (parent != null && parent.Name == "configuration" && parent.ParentNode is XmlDocument) - { - foreach (XmlNode child in node.ChildNodes) - { - if (child.Name == "add") - { - XmlAttributeCollection attributes = child.Attributes; - XmlAttribute keyAttribute = attributes["key"]; - XmlAttribute valueAttribute = attributes["value"]; - if (keyAttribute != null && valueAttribute != null && keyAttribute.Value != null) - { - _settings.Add(keyAttribute.Value, valueAttribute.Value); - } - } - } - } - } - } - - public void Save(string fileName) - { - XmlDocument doc = new XmlDocument(); - doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null)); - XmlElement configuration = doc.CreateElement("configuration"); - doc.AppendChild(configuration); - XmlElement appSettings = doc.CreateElement("appSettings"); - configuration.AppendChild(appSettings); - foreach (KeyValuePair keyValuePair in _settings) - { - XmlElement add = doc.CreateElement("add"); - add.SetAttribute("key", keyValuePair.Key); - add.SetAttribute("value", keyValuePair.Value); - appSettings.AppendChild(add); - } - - byte[] file; - using (var memory = new MemoryStream()) - { - using (var writer = new StreamWriter(memory, Encoding.UTF8)) - { - doc.Save(writer); - } - file = memory.ToArray(); + File.Delete(fileName); } + catch { } string backupFileName = fileName + ".backup"; - if (File.Exists(fileName)) + try + { + doc.Load(backupFileName); + } + catch { try { File.Delete(backupFileName); } catch { } - try - { - File.Move(fileName, backupFileName); - } - catch { } - } - using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write)) + return; + } + } + + XmlNodeList list = doc.GetElementsByTagName("appSettings"); + foreach (XmlNode node in list) + { + XmlNode parent = node.ParentNode; + if (parent != null && parent.Name == "configuration" && parent.ParentNode is XmlDocument) { - stream.Write(file, 0, file.Length); + foreach (XmlNode child in node.ChildNodes) + { + if (child.Name == "add") + { + XmlAttributeCollection attributes = child.Attributes; + XmlAttribute keyAttribute = attributes["key"]; + XmlAttribute valueAttribute = attributes["value"]; + if (keyAttribute != null && valueAttribute != null && keyAttribute.Value != null) + { + _settings.Add(keyAttribute.Value, valueAttribute.Value); + } + } + } } + } + } + public void Save(string fileName) + { + XmlDocument doc = new XmlDocument(); + doc.AppendChild(doc.CreateXmlDeclaration("1.0", "utf-8", null)); + XmlElement configuration = doc.CreateElement("configuration"); + doc.AppendChild(configuration); + XmlElement appSettings = doc.CreateElement("appSettings"); + configuration.AppendChild(appSettings); + foreach (KeyValuePair keyValuePair in _settings) + { + XmlElement add = doc.CreateElement("add"); + add.SetAttribute("key", keyValuePair.Key); + add.SetAttribute("value", keyValuePair.Value); + appSettings.AppendChild(add); + } + + byte[] file; + using (var memory = new MemoryStream()) + { + using (var writer = new StreamWriter(memory, Encoding.UTF8)) + { + doc.Save(writer); + } + file = memory.ToArray(); + } + + string backupFileName = fileName + ".backup"; + if (File.Exists(fileName)) + { try { File.Delete(backupFileName); } catch { } - } - - public bool Contains(string name) - { - return _settings.ContainsKey(name); - } - - public void SetValue(string name, string value) - { - _settings[name] = value; - } - - public string GetValue(string name, string value) - { - if (_settings.TryGetValue(name, out string result)) - return result; - - - return value; - } - - public void Remove(string name) - { - _settings.Remove(name); - } - - public void SetValue(string name, int value) - { - _settings[name] = value.ToString(); - } - - public int GetValue(string name, int value) - { - if (_settings.TryGetValue(name, out string str)) + try { - if (int.TryParse(str, out int parsedValue)) - return parsedValue; - - - return value; + File.Move(fileName, backupFileName); } - - return value; + catch { } } - public void SetValue(string name, float value) + using (var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write)) { - _settings[name] = value.ToString(CultureInfo.InvariantCulture); + stream.Write(file, 0, file.Length); } - public float GetValue(string name, float value) + try { - if (_settings.TryGetValue(name, out string str)) - { - if (float.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out float parsedValue)) - return parsedValue; - } - - return value; - - } - - public double GetValue(string name, double value) - { - if (_settings.TryGetValue(name, out string str)) - { - if (double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out double parsedValue)) - return parsedValue; - } - - return value; - } - - public void SetValue(string name, bool value) - { - _settings[name] = value ? "true" : "false"; - } - - public bool GetValue(string name, bool value) - { - if (_settings.TryGetValue(name, out string str)) - { - return str == "true"; - } - - return value; - } - - public void SetValue(string name, Color color) - { - _settings[name] = color.ToArgb().ToString("X8"); - } - - public Color GetValue(string name, Color value) - { - if (_settings.TryGetValue(name, out string str)) - { - if (int.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int parsedValue)) - return Color.FromArgb(parsedValue); - } - - return value; + File.Delete(backupFileName); } + catch { } } -} + + public bool Contains(string name) + { + return _settings.ContainsKey(name); + } + + public void SetValue(string name, string value) + { + _settings[name] = value; + } + + public string GetValue(string name, string value) + { + if (_settings.TryGetValue(name, out string result)) + return result; + + + return value; + } + + public void Remove(string name) + { + _settings.Remove(name); + } + + public void SetValue(string name, int value) + { + _settings[name] = value.ToString(); + } + + public int GetValue(string name, int value) + { + if (_settings.TryGetValue(name, out string str)) + { + if (int.TryParse(str, out int parsedValue)) + return parsedValue; + + + return value; + } + + return value; + } + + public void SetValue(string name, float value) + { + _settings[name] = value.ToString(CultureInfo.InvariantCulture); + } + + public float GetValue(string name, float value) + { + if (_settings.TryGetValue(name, out string str)) + { + if (float.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out float parsedValue)) + return parsedValue; + } + + return value; + + } + + public double GetValue(string name, double value) + { + if (_settings.TryGetValue(name, out string str)) + { + if (double.TryParse(str, NumberStyles.Float, CultureInfo.InvariantCulture, out double parsedValue)) + return parsedValue; + } + + return value; + } + + public void SetValue(string name, bool value) + { + _settings[name] = value ? "true" : "false"; + } + + public bool GetValue(string name, bool value) + { + if (_settings.TryGetValue(name, out string str)) + { + return str == "true"; + } + + return value; + } + + public void SetValue(string name, Color color) + { + _settings[name] = color.ToArgb().ToString("X8"); + } + + public Color GetValue(string name, Color value) + { + if (_settings.TryGetValue(name, out string str)) + { + if (int.TryParse(str, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int parsedValue)) + return Color.FromArgb(parsedValue); + } + + return value; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/WMI/Hardware.cs b/LibreHardwareMonitor/WMI/Hardware.cs index 678aef9..da7a4ac 100644 --- a/LibreHardwareMonitor/WMI/Hardware.cs +++ b/LibreHardwareMonitor/WMI/Hardware.cs @@ -7,30 +7,29 @@ using System.Management.Instrumentation; using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitor.Wmi +namespace LibreHardwareMonitor.Wmi; + +[InstrumentationClass(InstrumentationType.Instance)] +public class Hardware : IWmiObject { - [InstrumentationClass(InstrumentationType.Instance)] - public class Hardware : IWmiObject + #region WMI Exposed + + public string HardwareType { get; } + public string Identifier { get; } + public string Name { get; } + public string Parent { get; } + + #endregion + + public Hardware(IHardware hardware) { - #region WMI Exposed - - public string HardwareType { get; } - public string Identifier { get; } - public string Name { get; } - public string Parent { get; } - - #endregion - - public Hardware(IHardware hardware) - { - Name = hardware.Name; - Identifier = hardware.Identifier.ToString(); - HardwareType = hardware.HardwareType.ToString(); - Parent = (hardware.Parent != null) - ? hardware.Parent.Identifier.ToString() - : ""; - } - - public void Update() { } + Name = hardware.Name; + Identifier = hardware.Identifier.ToString(); + HardwareType = hardware.HardwareType.ToString(); + Parent = (hardware.Parent != null) + ? hardware.Parent.Identifier.ToString() + : ""; } -} + + public void Update() { } +} \ No newline at end of file diff --git a/LibreHardwareMonitor/WMI/IWmiObject.cs b/LibreHardwareMonitor/WMI/IWmiObject.cs index bebc028..ba90b93 100644 --- a/LibreHardwareMonitor/WMI/IWmiObject.cs +++ b/LibreHardwareMonitor/WMI/IWmiObject.cs @@ -4,15 +4,14 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Wmi -{ - interface IWmiObject - { - // Both of these get exposed to WMI - string Name { get; } - string Identifier { get; } +namespace LibreHardwareMonitor.Wmi; - // Not exposed. - void Update(); - } -} +interface IWmiObject +{ + // Both of these get exposed to WMI + string Name { get; } + string Identifier { get; } + + // Not exposed. + void Update(); +} \ No newline at end of file diff --git a/LibreHardwareMonitor/WMI/Sensor.cs b/LibreHardwareMonitor/WMI/Sensor.cs index 1b9520f..2fb2389 100644 --- a/LibreHardwareMonitor/WMI/Sensor.cs +++ b/LibreHardwareMonitor/WMI/Sensor.cs @@ -7,47 +7,46 @@ using System.Management.Instrumentation; using LibreHardwareMonitor.Hardware; -namespace LibreHardwareMonitor.Wmi +namespace LibreHardwareMonitor.Wmi; + +[InstrumentationClass(InstrumentationType.Instance)] +public class Sensor : IWmiObject { - [InstrumentationClass(InstrumentationType.Instance)] - public class Sensor : IWmiObject + private readonly ISensor _sensor; + + #region WMI Exposed + + public string SensorType { get; } + public string Identifier { get; } + public string Parent { get; } + public string Name { get; } + public float Value { get; private set; } + public float Min { get; private set; } + public float Max { get; private set; } + public int Index { get; } + + #endregion + + public Sensor(ISensor sensor) { - private readonly ISensor _sensor; + Name = sensor.Name; + Index = sensor.Index; - #region WMI Exposed + SensorType = sensor.SensorType.ToString(); + Identifier = sensor.Identifier.ToString(); + Parent = sensor.Hardware.Identifier.ToString(); - public string SensorType { get; } - public string Identifier { get; } - public string Parent { get; } - public string Name { get; } - public float Value { get; private set; } - public float Min { get; private set; } - public float Max { get; private set; } - public int Index { get; } - - #endregion - - public Sensor(ISensor sensor) - { - Name = sensor.Name; - Index = sensor.Index; - - SensorType = sensor.SensorType.ToString(); - Identifier = sensor.Identifier.ToString(); - Parent = sensor.Hardware.Identifier.ToString(); - - _sensor = sensor; - } - - public void Update() - { - Value = _sensor.Value ?? 0; - - if (_sensor.Min != null) - Min = (float)_sensor.Min; - - if (_sensor.Max != null) - Max = (float)_sensor.Max; - } + _sensor = sensor; } -} + + public void Update() + { + Value = _sensor.Value ?? 0; + + if (_sensor.Min != null) + Min = (float)_sensor.Min; + + if (_sensor.Max != null) + Max = (float)_sensor.Max; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs b/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs index c617671..d8c4a15 100644 --- a/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs +++ b/LibreHardwareMonitorLib/Hardware/Battery/Battery.cs @@ -9,218 +9,217 @@ using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; using Microsoft.Win32.SafeHandles; -namespace LibreHardwareMonitor.Hardware.Battery +namespace LibreHardwareMonitor.Hardware.Battery; + +internal sealed class Battery : Hardware { - internal sealed class Battery : Hardware + private readonly SafeFileHandle _batteryHandle; + private readonly Kernel32.BATTERY_INFORMATION _batteryInformation; + private readonly uint _batteryTag; + private readonly Sensor _chargeDischargeCurrent; + private readonly Sensor _chargeDischargeRate; + private readonly Sensor _chargeLevel; + private readonly Sensor _degradationPercentage; + private readonly Sensor _designedCapacity; + private readonly Sensor _fullChargedCapacity; + private readonly Sensor _remainingCapacity; + private readonly Sensor _remainingTime; + private readonly Sensor _voltage; + + public Battery + ( + string name, + string manufacturer, + SafeFileHandle batteryHandle, + Kernel32.BATTERY_INFORMATION batteryInfo, + uint batteryTag, + ISettings settings) : + base(name, new Identifier("battery"), settings) { - private readonly SafeFileHandle _batteryHandle; - private readonly Kernel32.BATTERY_INFORMATION _batteryInformation; - private readonly uint _batteryTag; - private readonly Sensor _chargeDischargeCurrent; - private readonly Sensor _chargeDischargeRate; - private readonly Sensor _chargeLevel; - private readonly Sensor _degradationPercentage; - private readonly Sensor _designedCapacity; - private readonly Sensor _fullChargedCapacity; - private readonly Sensor _remainingCapacity; - private readonly Sensor _remainingTime; - private readonly Sensor _voltage; + Name = name; + Manufacturer = manufacturer; - public Battery - ( - string name, - string manufacturer, - SafeFileHandle batteryHandle, - Kernel32.BATTERY_INFORMATION batteryInfo, - uint batteryTag, - ISettings settings) : - base(name, new Identifier("battery"), settings) + _batteryTag = batteryTag; + _batteryHandle = batteryHandle; + _batteryInformation = batteryInfo; + + if (batteryInfo.Chemistry.SequenceEqual(new[] { 'P', 'b', 'A', 'c' })) { - Name = name; - Manufacturer = manufacturer; + Chemistry = BatteryChemistry.LeadAcid; + } + else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'L', 'I', 'O', 'N' }) || batteryInfo.Chemistry.SequenceEqual(new[] { 'L', 'i', '-', 'I' })) + { + Chemistry = BatteryChemistry.LithiumIon; + } + else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'C', 'd' })) + { + Chemistry = BatteryChemistry.NickelCadmium; + } + else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'M', 'H' })) + { + Chemistry = BatteryChemistry.NickelMetalHydride; + } + else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'Z', 'n' })) + { + Chemistry = BatteryChemistry.NickelZinc; + } + else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'R', 'A', 'M', '\x00' })) + { + Chemistry = BatteryChemistry.AlkalineManganese; + } + else + { + Chemistry = BatteryChemistry.Unknown; + } - _batteryTag = batteryTag; - _batteryHandle = batteryHandle; - _batteryInformation = batteryInfo; + DegradationLevel = 100f - (batteryInfo.FullChargedCapacity * 100f / batteryInfo.DesignedCapacity); + DesignedCapacity = batteryInfo.DesignedCapacity; + FullChargedCapacity = batteryInfo.FullChargedCapacity; - if (batteryInfo.Chemistry.SequenceEqual(new[] { 'P', 'b', 'A', 'c' })) + _chargeLevel = new Sensor("Charge Level", 0, SensorType.Level, this, settings); + ActivateSensor(_chargeLevel); + + _voltage = new Sensor("Voltage", 1, SensorType.Voltage, this, settings); + ActivateSensor(_voltage); + + _chargeDischargeCurrent = new Sensor("Current", 2, SensorType.Current, this, settings); + ActivateSensor(_chargeDischargeCurrent); + + _designedCapacity = new Sensor("Designed Capacity", 3, SensorType.Energy, this, settings); + ActivateSensor(_designedCapacity); + + _fullChargedCapacity = new Sensor("Full Charged Capacity", 4, SensorType.Energy, this, settings); + ActivateSensor(_fullChargedCapacity); + + _remainingCapacity = new Sensor("Remaining Capacity", 5, SensorType.Energy, this, settings); + ActivateSensor(_remainingCapacity); + + _chargeDischargeRate = new Sensor("Charge/Discharge Rate", 0, SensorType.Power, this, settings); + ActivateSensor(_chargeDischargeRate); + + _degradationPercentage = new Sensor("Degradation Level", 0, SensorType.Level, this, settings); + ActivateSensor(_degradationPercentage); + + _remainingTime = new Sensor("Remaining Time (Estimated)", 0, SensorType.TimeSpan, this, settings); + ActivateSensor(_remainingTime); + } + + public float ChargeDischargeCurrent { get; private set; } + + public float ChargeDischargeRate { get; private set; } + + public float ChargeLevel { get; private set; } + + public BatteryChemistry Chemistry { get; } + + public float DegradationLevel { get; } + + public float DesignedCapacity { get; } + + public float FullChargedCapacity { get; } + + public override HardwareType HardwareType => HardwareType.Battery; + + public string Manufacturer { get; } + + public float RemainingCapacity { get; private set; } + + public uint RemainingTime { get; private set; } + + public float Voltage { get; private set; } + + public override void Update() + { + Kernel32.BATTERY_WAIT_STATUS bws = default; + bws.BatteryTag = _batteryTag; + Kernel32.BATTERY_STATUS batteryStatus = default; + if (Kernel32.DeviceIoControl(_batteryHandle, + Kernel32.IOCTL.IOCTL_BATTERY_QUERY_STATUS, + ref bws, + Marshal.SizeOf(bws), + ref batteryStatus, + Marshal.SizeOf(batteryStatus), + out _, + IntPtr.Zero)) + { + _designedCapacity.Value = Convert.ToSingle(_batteryInformation.DesignedCapacity); + _fullChargedCapacity.Value = Convert.ToSingle(_batteryInformation.FullChargedCapacity); + + _remainingCapacity.Value = Convert.ToSingle(batteryStatus.Capacity); + RemainingCapacity = Convert.ToSingle(batteryStatus.Capacity); + + _voltage.Value = Convert.ToSingle(batteryStatus.Voltage) / 1000f; + Voltage = Convert.ToSingle(batteryStatus.Voltage) / 1000f; + + _chargeLevel.Value = _remainingCapacity.Value * 100f / _fullChargedCapacity.Value; + ChargeLevel = (_remainingCapacity.Value * 100f / _fullChargedCapacity.Value).GetValueOrDefault(); + + ChargeDischargeRate = batteryStatus.Rate / 1000f; + + switch (batteryStatus.Rate) { - Chemistry = BatteryChemistry.LeadAcid; + case > 0: + _chargeDischargeRate.Name = "Charge Rate"; + _chargeDischargeRate.Value = batteryStatus.Rate / 1000f; + + _chargeDischargeCurrent.Name = "Charge Current"; + _chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value; + ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault(); + + break; + case < 0: + _chargeDischargeRate.Name = "Discharge Rate"; + _chargeDischargeRate.Value = Math.Abs(batteryStatus.Rate) / 1000f; + + _chargeDischargeCurrent.Name = "Discharge Current"; + _chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value; + ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault(); + + break; + default: + _chargeDischargeRate.Name = "Charge/Discharge Rate"; + _chargeDischargeRate.Value = 0f; + ChargeDischargeRate = 0f; + + _chargeDischargeCurrent.Name = "Charge/Discharge Current"; + _chargeDischargeCurrent.Value = 0f; + ChargeDischargeCurrent = 0f; + + break; } - else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'L', 'I', 'O', 'N' }) || batteryInfo.Chemistry.SequenceEqual(new[] { 'L', 'i', '-', 'I' })) + + _degradationPercentage.Value = 100f - (_fullChargedCapacity.Value * 100f / _designedCapacity.Value); + } + + uint estimatedRunTime = 0; + Kernel32.BATTERY_QUERY_INFORMATION bqi = default; + bqi.BatteryTag = _batteryTag; + bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryEstimatedTime; + if (Kernel32.DeviceIoControl(_batteryHandle, + Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION, + ref bqi, + Marshal.SizeOf(bqi), + ref estimatedRunTime, + Marshal.SizeOf(), + out _, + IntPtr.Zero)) + { + RemainingTime = estimatedRunTime; + if (estimatedRunTime != Kernel32.BATTERY_UNKNOWN_TIME) { - Chemistry = BatteryChemistry.LithiumIon; - } - else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'C', 'd' })) - { - Chemistry = BatteryChemistry.NickelCadmium; - } - else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'M', 'H' })) - { - Chemistry = BatteryChemistry.NickelMetalHydride; - } - else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'Z', 'n' })) - { - Chemistry = BatteryChemistry.NickelZinc; - } - else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'R', 'A', 'M', '\x00' })) - { - Chemistry = BatteryChemistry.AlkalineManganese; + ActivateSensor(_remainingTime); + _remainingTime.Value = estimatedRunTime; } else { - Chemistry = BatteryChemistry.Unknown; + DeactivateSensor(_remainingTime); } - - DegradationLevel = 100f - (batteryInfo.FullChargedCapacity * 100f / batteryInfo.DesignedCapacity); - DesignedCapacity = batteryInfo.DesignedCapacity; - FullChargedCapacity = batteryInfo.FullChargedCapacity; - - _chargeLevel = new Sensor("Charge Level", 0, SensorType.Level, this, settings); - ActivateSensor(_chargeLevel); - - _voltage = new Sensor("Voltage", 1, SensorType.Voltage, this, settings); - ActivateSensor(_voltage); - - _chargeDischargeCurrent = new Sensor("Current", 2, SensorType.Current, this, settings); - ActivateSensor(_chargeDischargeCurrent); - - _designedCapacity = new Sensor("Designed Capacity", 3, SensorType.Energy, this, settings); - ActivateSensor(_designedCapacity); - - _fullChargedCapacity = new Sensor("Full Charged Capacity", 4, SensorType.Energy, this, settings); - ActivateSensor(_fullChargedCapacity); - - _remainingCapacity = new Sensor("Remaining Capacity", 5, SensorType.Energy, this, settings); - ActivateSensor(_remainingCapacity); - - _chargeDischargeRate = new Sensor("Charge/Discharge Rate", 0, SensorType.Power, this, settings); - ActivateSensor(_chargeDischargeRate); - - _degradationPercentage = new Sensor("Degradation Level", 0, SensorType.Level, this, settings); - ActivateSensor(_degradationPercentage); - - _remainingTime = new Sensor("Remaining Time (Estimated)", 0, SensorType.TimeSpan, this, settings); - ActivateSensor(_remainingTime); - } - - public float ChargeDischargeCurrent { get; private set; } - - public float ChargeDischargeRate { get; private set; } - - public float ChargeLevel { get; private set; } - - public BatteryChemistry Chemistry { get; } - - public float DegradationLevel { get; } - - public float DesignedCapacity { get; } - - public float FullChargedCapacity { get; } - - public override HardwareType HardwareType => HardwareType.Battery; - - public string Manufacturer { get; } - - public float RemainingCapacity { get; private set; } - - public uint RemainingTime { get; private set; } - - public float Voltage { get; private set; } - - public override void Update() - { - Kernel32.BATTERY_WAIT_STATUS bws = default; - bws.BatteryTag = _batteryTag; - Kernel32.BATTERY_STATUS batteryStatus = default; - if (Kernel32.DeviceIoControl(_batteryHandle, - Kernel32.IOCTL.IOCTL_BATTERY_QUERY_STATUS, - ref bws, - Marshal.SizeOf(bws), - ref batteryStatus, - Marshal.SizeOf(batteryStatus), - out _, - IntPtr.Zero)) - { - _designedCapacity.Value = Convert.ToSingle(_batteryInformation.DesignedCapacity); - _fullChargedCapacity.Value = Convert.ToSingle(_batteryInformation.FullChargedCapacity); - - _remainingCapacity.Value = Convert.ToSingle(batteryStatus.Capacity); - RemainingCapacity = Convert.ToSingle(batteryStatus.Capacity); - - _voltage.Value = Convert.ToSingle(batteryStatus.Voltage) / 1000f; - Voltage = Convert.ToSingle(batteryStatus.Voltage) / 1000f; - - _chargeLevel.Value = _remainingCapacity.Value * 100f / _fullChargedCapacity.Value; - ChargeLevel = (_remainingCapacity.Value * 100f / _fullChargedCapacity.Value).GetValueOrDefault(); - - ChargeDischargeRate = batteryStatus.Rate / 1000f; - - switch (batteryStatus.Rate) - { - case > 0: - _chargeDischargeRate.Name = "Charge Rate"; - _chargeDischargeRate.Value = batteryStatus.Rate / 1000f; - - _chargeDischargeCurrent.Name = "Charge Current"; - _chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value; - ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault(); - - break; - case < 0: - _chargeDischargeRate.Name = "Discharge Rate"; - _chargeDischargeRate.Value = Math.Abs(batteryStatus.Rate) / 1000f; - - _chargeDischargeCurrent.Name = "Discharge Current"; - _chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value; - ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault(); - - break; - default: - _chargeDischargeRate.Name = "Charge/Discharge Rate"; - _chargeDischargeRate.Value = 0f; - ChargeDischargeRate = 0f; - - _chargeDischargeCurrent.Name = "Charge/Discharge Current"; - _chargeDischargeCurrent.Value = 0f; - ChargeDischargeCurrent = 0f; - - break; - } - - _degradationPercentage.Value = 100f - (_fullChargedCapacity.Value * 100f / _designedCapacity.Value); - } - - uint estimatedRunTime = 0; - Kernel32.BATTERY_QUERY_INFORMATION bqi = default; - bqi.BatteryTag = _batteryTag; - bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryEstimatedTime; - if (Kernel32.DeviceIoControl(_batteryHandle, - Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION, - ref bqi, - Marshal.SizeOf(bqi), - ref estimatedRunTime, - Marshal.SizeOf(), - out _, - IntPtr.Zero)) - { - RemainingTime = estimatedRunTime; - if (estimatedRunTime != Kernel32.BATTERY_UNKNOWN_TIME) - { - ActivateSensor(_remainingTime); - _remainingTime.Value = estimatedRunTime; - } - else - { - DeactivateSensor(_remainingTime); - } - } - } - - public override void Close() - { - base.Close(); - _batteryHandle.Close(); } } -} + + public override void Close() + { + base.Close(); + _batteryHandle.Close(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs b/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs index 4b08485..f09137d 100644 --- a/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Battery/BatteryGroup.cs @@ -11,209 +11,208 @@ using System.Text; using LibreHardwareMonitor.Interop; using Microsoft.Win32.SafeHandles; -namespace LibreHardwareMonitor.Hardware.Battery +namespace LibreHardwareMonitor.Hardware.Battery; + +internal class BatteryGroup : IGroup { - internal class BatteryGroup : IGroup + private readonly List _hardware = new(); + + public unsafe BatteryGroup(ISettings settings) { - private readonly List _hardware = new(); + // No implementation for battery information on Unix systems + if (Software.OperatingSystem.IsUnix) + return; - public unsafe BatteryGroup(ISettings settings) + IntPtr hdev = SetupApi.SetupDiGetClassDevs(ref SetupApi.GUID_DEVICE_BATTERY, IntPtr.Zero, IntPtr.Zero, SetupApi.DIGCF_PRESENT | SetupApi.DIGCF_DEVICEINTERFACE); + if (hdev != SetupApi.INVALID_HANDLE_VALUE) { - // No implementation for battery information on Unix systems - if (Software.OperatingSystem.IsUnix) - return; - - IntPtr hdev = SetupApi.SetupDiGetClassDevs(ref SetupApi.GUID_DEVICE_BATTERY, IntPtr.Zero, IntPtr.Zero, SetupApi.DIGCF_PRESENT | SetupApi.DIGCF_DEVICEINTERFACE); - if (hdev != SetupApi.INVALID_HANDLE_VALUE) + for (uint i = 0; ; i++) { - for (uint i = 0; ; i++) + SetupApi.SP_DEVICE_INTERFACE_DATA did = default; + did.cbSize = (uint)Marshal.SizeOf(typeof(SetupApi.SP_DEVICE_INTERFACE_DATA)); + + if (!SetupApi.SetupDiEnumDeviceInterfaces(hdev, + IntPtr.Zero, + ref SetupApi.GUID_DEVICE_BATTERY, + i, + ref did)) { - SetupApi.SP_DEVICE_INTERFACE_DATA did = default; - did.cbSize = (uint)Marshal.SizeOf(typeof(SetupApi.SP_DEVICE_INTERFACE_DATA)); + if (Marshal.GetLastWin32Error() == SetupApi.ERROR_NO_MORE_ITEMS) + break; + } + else + { + SetupApi.SetupDiGetDeviceInterfaceDetail(hdev, + did, + IntPtr.Zero, + 0, + out uint cbRequired, + IntPtr.Zero); - if (!SetupApi.SetupDiEnumDeviceInterfaces(hdev, - IntPtr.Zero, - ref SetupApi.GUID_DEVICE_BATTERY, - i, - ref did)) + if (Marshal.GetLastWin32Error() == SetupApi.ERROR_INSUFFICIENT_BUFFER) { - if (Marshal.GetLastWin32Error() == SetupApi.ERROR_NO_MORE_ITEMS) - break; - } - else - { - SetupApi.SetupDiGetDeviceInterfaceDetail(hdev, - did, - IntPtr.Zero, - 0, - out uint cbRequired, - IntPtr.Zero); + IntPtr pdidd = Kernel32.LocalAlloc(Kernel32.LPTR, cbRequired); + Marshal.WriteInt32(pdidd, Environment.Is64BitOperatingSystem ? 8 : 4); // cbSize. - if (Marshal.GetLastWin32Error() == SetupApi.ERROR_INSUFFICIENT_BUFFER) + if (SetupApi.SetupDiGetDeviceInterfaceDetail(hdev, + did, + pdidd, + cbRequired, + out _, + IntPtr.Zero)) { - IntPtr pdidd = Kernel32.LocalAlloc(Kernel32.LPTR, cbRequired); - Marshal.WriteInt32(pdidd, Environment.Is64BitOperatingSystem ? 8 : 4); // cbSize. + string devicePath = new((char*)(pdidd + 4)); - if (SetupApi.SetupDiGetDeviceInterfaceDetail(hdev, - did, - pdidd, - cbRequired, - out _, - IntPtr.Zero)) + SafeFileHandle battery = Kernel32.CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); + if (!battery.IsInvalid) { - string devicePath = new((char*)(pdidd + 4)); + Kernel32.BATTERY_QUERY_INFORMATION bqi = default; - SafeFileHandle battery = Kernel32.CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); - if (!battery.IsInvalid) + uint dwWait = 0; + if (Kernel32.DeviceIoControl(battery, + Kernel32.IOCTL.IOCTL_BATTERY_QUERY_TAG, + ref dwWait, + Marshal.SizeOf(dwWait), + ref bqi.BatteryTag, + Marshal.SizeOf(bqi.BatteryTag), + out _, + IntPtr.Zero)) { - Kernel32.BATTERY_QUERY_INFORMATION bqi = default; + Kernel32.BATTERY_INFORMATION bi = default; + bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryInformation; - uint dwWait = 0; if (Kernel32.DeviceIoControl(battery, - Kernel32.IOCTL.IOCTL_BATTERY_QUERY_TAG, - ref dwWait, - Marshal.SizeOf(dwWait), - ref bqi.BatteryTag, - Marshal.SizeOf(bqi.BatteryTag), + Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION, + ref bqi, + Marshal.SizeOf(bqi), + ref bi, + Marshal.SizeOf(bi), out _, IntPtr.Zero)) { - Kernel32.BATTERY_INFORMATION bi = default; - bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryInformation; - - if (Kernel32.DeviceIoControl(battery, - Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION, - ref bqi, - Marshal.SizeOf(bqi), - ref bi, - Marshal.SizeOf(bi), - out _, - IntPtr.Zero)) + // Only batteries count. + if (bi.Capabilities == Kernel32.BatteryCapabilities.BATTERY_SYSTEM_BATTERY) { - // Only batteries count. - if (bi.Capabilities == Kernel32.BatteryCapabilities.BATTERY_SYSTEM_BATTERY) - { - const int maxLoadString = 100; + const int maxLoadString = 100; - IntPtr ptrDevName = Marshal.AllocCoTaskMem(maxLoadString); - bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryDeviceName; + IntPtr ptrDevName = Marshal.AllocCoTaskMem(maxLoadString); + bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryDeviceName; + + if (Kernel32.DeviceIoControl(battery, + Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION, + ref bqi, + Marshal.SizeOf(bqi), + ptrDevName, + maxLoadString, + out _, + IntPtr.Zero)) + { + IntPtr ptrManName = Marshal.AllocCoTaskMem(maxLoadString); + bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryManufactureName; if (Kernel32.DeviceIoControl(battery, Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION, ref bqi, Marshal.SizeOf(bqi), - ptrDevName, + ptrManName, maxLoadString, out _, IntPtr.Zero)) { - IntPtr ptrManName = Marshal.AllocCoTaskMem(maxLoadString); - bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryManufactureName; + string name = Marshal.PtrToStringUni(ptrDevName); + string manufacturer = Marshal.PtrToStringUni(ptrManName); - if (Kernel32.DeviceIoControl(battery, - Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION, - ref bqi, - Marshal.SizeOf(bqi), - ptrManName, - maxLoadString, - out _, - IntPtr.Zero)) - { - string name = Marshal.PtrToStringUni(ptrDevName); - string manufacturer = Marshal.PtrToStringUni(ptrManName); - - _hardware.Add(new Battery(name, manufacturer, battery, bi, bqi.BatteryTag, settings)); - } - - Marshal.FreeCoTaskMem(ptrManName); + _hardware.Add(new Battery(name, manufacturer, battery, bi, bqi.BatteryTag, settings)); } - Marshal.FreeCoTaskMem(ptrDevName); + Marshal.FreeCoTaskMem(ptrManName); } + + Marshal.FreeCoTaskMem(ptrDevName); } } } } - - Kernel32.LocalFree(pdidd); } + + Kernel32.LocalFree(pdidd); } } - - SetupApi.SetupDiDestroyDeviceInfoList(hdev); - } - } - - /// - public IReadOnlyList Hardware => _hardware; - - /// - public void Close() - { - foreach (Battery battery in _hardware) - battery.Close(); - } - - /// - public string GetReport() - { - StringBuilder reportBuilder = new(); - - uint count = 1; - - foreach (Battery bat in _hardware) - { - string chemistry = bat.Chemistry switch - { - BatteryChemistry.LeadAcid => "Lead Acid", - BatteryChemistry.NickelCadmium => "Nickel-Cadmium", - BatteryChemistry.NickelMetalHydride => "Nickel-Metal Hydride", - BatteryChemistry.LithiumIon => "Lithium Ion", - BatteryChemistry.NickelZinc => "Nickel-Zinc", - BatteryChemistry.AlkalineManganese => "Rechargeable Alkaline-Manganese", - _ => "Unknown" - }; - - reportBuilder.Append("Battery #").Append(count).AppendLine(":") - .Append(" Name: ").AppendLine(bat.Name) - .Append(" Manufacturer: ").AppendLine(bat.Manufacturer) - .Append(" Chemistry: ").AppendLine(chemistry) - .Append(" Degradation Level: ").AppendFormat("{0:F2}", bat.DegradationLevel).AppendLine(" %") - .Append(" Designed Capacity: ").Append(bat.DesignedCapacity).AppendLine(" mWh") - .Append(" Full Charged Capacity: ").Append(bat.FullChargedCapacity).AppendLine(" mWh") - .Append(" Remaining Capacity: ").Append(bat.RemainingCapacity).AppendLine(" mWh") - .Append(" Charge Level: ").AppendFormat("{0:F2}", bat.RemainingCapacity * 100f / bat.FullChargedCapacity).AppendLine(" %") - .Append(" Voltage: ").AppendFormat("{0:F3}", bat.Voltage).AppendLine(" V"); - - if (bat.RemainingTime != Kernel32.BATTERY_UNKNOWN_TIME) - { - reportBuilder.Append(" Remaining Time (Estimated): ").AppendFormat("{0:g}", TimeSpan.FromSeconds(bat.RemainingTime)).AppendLine(); - } - - switch (bat.ChargeDischargeRate) - { - case > 0: - reportBuilder.Append(" Charge Rate: ").AppendFormat("{0:F1}", bat.ChargeDischargeRate).AppendLine(" W") - .Append(" Charge Current: ").AppendFormat("{0:F3}", bat.ChargeDischargeRate / bat.Voltage).AppendLine(" A"); - - break; - case < 0: - reportBuilder.Append(" Discharge Rate: ").AppendFormat("{0:F1}", Math.Abs(bat.ChargeDischargeRate)).AppendLine(" W") - .Append(" Discharge Current: ").AppendFormat("{0:F3}", Math.Abs(bat.ChargeDischargeRate) / bat.Voltage).AppendLine(" A"); - - break; - default: - reportBuilder.AppendLine(" Charge/Discharge Rate: 0 W") - .AppendLine(" Charge/Discharge Current: 0 A"); - - break; - } - - reportBuilder.AppendLine(); - count++; } - return reportBuilder.ToString(); + SetupApi.SetupDiDestroyDeviceInfoList(hdev); } } -} + + /// + public IReadOnlyList Hardware => _hardware; + + /// + public void Close() + { + foreach (Battery battery in _hardware) + battery.Close(); + } + + /// + public string GetReport() + { + StringBuilder reportBuilder = new(); + + uint count = 1; + + foreach (Battery bat in _hardware) + { + string chemistry = bat.Chemistry switch + { + BatteryChemistry.LeadAcid => "Lead Acid", + BatteryChemistry.NickelCadmium => "Nickel-Cadmium", + BatteryChemistry.NickelMetalHydride => "Nickel-Metal Hydride", + BatteryChemistry.LithiumIon => "Lithium Ion", + BatteryChemistry.NickelZinc => "Nickel-Zinc", + BatteryChemistry.AlkalineManganese => "Rechargeable Alkaline-Manganese", + _ => "Unknown" + }; + + reportBuilder.Append("Battery #").Append(count).AppendLine(":") + .Append(" Name: ").AppendLine(bat.Name) + .Append(" Manufacturer: ").AppendLine(bat.Manufacturer) + .Append(" Chemistry: ").AppendLine(chemistry) + .Append(" Degradation Level: ").AppendFormat("{0:F2}", bat.DegradationLevel).AppendLine(" %") + .Append(" Designed Capacity: ").Append(bat.DesignedCapacity).AppendLine(" mWh") + .Append(" Full Charged Capacity: ").Append(bat.FullChargedCapacity).AppendLine(" mWh") + .Append(" Remaining Capacity: ").Append(bat.RemainingCapacity).AppendLine(" mWh") + .Append(" Charge Level: ").AppendFormat("{0:F2}", bat.RemainingCapacity * 100f / bat.FullChargedCapacity).AppendLine(" %") + .Append(" Voltage: ").AppendFormat("{0:F3}", bat.Voltage).AppendLine(" V"); + + if (bat.RemainingTime != Kernel32.BATTERY_UNKNOWN_TIME) + { + reportBuilder.Append(" Remaining Time (Estimated): ").AppendFormat("{0:g}", TimeSpan.FromSeconds(bat.RemainingTime)).AppendLine(); + } + + switch (bat.ChargeDischargeRate) + { + case > 0: + reportBuilder.Append(" Charge Rate: ").AppendFormat("{0:F1}", bat.ChargeDischargeRate).AppendLine(" W") + .Append(" Charge Current: ").AppendFormat("{0:F3}", bat.ChargeDischargeRate / bat.Voltage).AppendLine(" A"); + + break; + case < 0: + reportBuilder.Append(" Discharge Rate: ").AppendFormat("{0:F1}", Math.Abs(bat.ChargeDischargeRate)).AppendLine(" W") + .Append(" Discharge Current: ").AppendFormat("{0:F3}", Math.Abs(bat.ChargeDischargeRate) / bat.Voltage).AppendLine(" A"); + + break; + default: + reportBuilder.AppendLine(" Charge/Discharge Rate: 0 W") + .AppendLine(" Charge/Discharge Current: 0 A"); + + break; + } + + reportBuilder.AppendLine(); + count++; + } + + return reportBuilder.ToString(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/CompositeSensor.cs b/LibreHardwareMonitorLib/Hardware/CompositeSensor.cs index 66a11db..0fb237d 100644 --- a/LibreHardwareMonitorLib/Hardware/CompositeSensor.cs +++ b/LibreHardwareMonitorLib/Hardware/CompositeSensor.cs @@ -6,35 +6,34 @@ using System; using System.Linq; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal class CompositeSensor : Sensor { - internal class CompositeSensor : Sensor + private readonly ISensor[] _components; + private readonly Func _reducer; + private readonly float _seedValue; + + public CompositeSensor + ( + string name, + int index, + SensorType sensorType, + Hardware hardware, + ISettings settings, + ISensor[] components, + Func reducer, + float seedValue = .0f) + : base(name, index, sensorType, hardware, settings) { - private readonly ISensor[] _components; - private readonly Func _reducer; - private readonly float _seedValue; - - public CompositeSensor - ( - string name, - int index, - SensorType sensorType, - Hardware hardware, - ISettings settings, - ISensor[] components, - Func reducer, - float seedValue = .0f) - : base(name, index, sensorType, hardware, settings) - { - _components = components; - _reducer = reducer; - _seedValue = seedValue; - } - - public override float? Value - { - get { return _components.Aggregate(_seedValue, _reducer); } - set => throw new NotImplementedException(); - } + _components = components; + _reducer = reducer; + _seedValue = seedValue; } -} + + public override float? Value + { + get { return _components.Aggregate(_seedValue, _reducer); } + set => throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Computer.cs b/LibreHardwareMonitorLib/Hardware/Computer.cs index 1c607bb..5fcfd4e 100644 --- a/LibreHardwareMonitorLib/Hardware/Computer.cs +++ b/LibreHardwareMonitorLib/Hardware/Computer.cs @@ -23,670 +23,669 @@ using LibreHardwareMonitor.Hardware.Network; using LibreHardwareMonitor.Hardware.Psu.Corsair; using LibreHardwareMonitor.Hardware.Storage; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Stores all hardware groups and decides which devices should be enabled and updated. +/// +public class Computer : IComputer { - /// - /// Stores all hardware groups and decides which devices should be enabled and updated. - /// - public class Computer : IComputer - { - private readonly List _groups = new(); - private readonly object _lock = new(); - private readonly ISettings _settings; + private readonly List _groups = new(); + private readonly object _lock = new(); + private readonly ISettings _settings; - private bool _batteryEnabled; - private bool _controllerEnabled; - private bool _cpuEnabled; - private bool _gpuEnabled; - private bool _memoryEnabled; - private bool _motherboardEnabled; - private bool _networkEnabled; - private bool _open; - private bool _psuEnabled; - private SMBios _smbios; - private bool _storageEnabled; + private bool _batteryEnabled; + private bool _controllerEnabled; + private bool _cpuEnabled; + private bool _gpuEnabled; + private bool _memoryEnabled; + private bool _motherboardEnabled; + private bool _networkEnabled; + private bool _open; + private bool _psuEnabled; + private SMBios _smbios; + private bool _storageEnabled; - /// - /// Creates a new instance with basic initial . - /// - public Computer() - { - _settings = new Settings(); - } + /// + /// Creates a new instance with basic initial . + /// + public Computer() + { + _settings = new Settings(); + } - /// - /// Creates a new instance with additional . - /// - /// Computer settings that will be transferred to each . - public Computer(ISettings settings) - { - _settings = settings ?? new Settings(); - } + /// + /// Creates a new instance with additional . + /// + /// Computer settings that will be transferred to each . + public Computer(ISettings settings) + { + _settings = settings ?? new Settings(); + } - /// - public event HardwareEventHandler HardwareAdded; + /// + public event HardwareEventHandler HardwareAdded; - /// - public event HardwareEventHandler HardwareRemoved; + /// + public event HardwareEventHandler HardwareRemoved; - /// - public IList Hardware - { - get - { - lock (_lock) - { - List list = new(); - - foreach (IGroup group in _groups) - list.AddRange(group.Hardware); - - return list; - } - } - } - - /// - public bool IsBatteryEnabled - { - get { return _batteryEnabled; } - set - { - if (_open && value != _batteryEnabled) - { - if (value) - { - Add(new BatteryGroup(_settings)); - } - else - { - RemoveType(); - } - } - - _batteryEnabled = value; - } - } - - /// - public bool IsControllerEnabled - { - get { return _controllerEnabled; } - set - { - if (_open && value != _controllerEnabled) - { - if (value) - { - Add(new TBalancerGroup(_settings)); - Add(new HeatmasterGroup(_settings)); - Add(new AquaComputerGroup(_settings)); - Add(new AeroCoolGroup(_settings)); - Add(new NzxtGroup(_settings)); - } - else - { - RemoveType(); - RemoveType(); - RemoveType(); - RemoveType(); - RemoveType(); - } - } - - _controllerEnabled = value; - } - } - - /// - public bool IsCpuEnabled - { - get { return _cpuEnabled; } - set - { - if (_open && value != _cpuEnabled) - { - if (value) - Add(new CpuGroup(_settings)); - else - RemoveType(); - } - - _cpuEnabled = value; - } - } - - /// - public bool IsGpuEnabled - { - get { return _gpuEnabled; } - set - { - if (_open && value != _gpuEnabled) - { - if (value) - { - Add(new AmdGpuGroup(_settings)); - Add(new NvidiaGroup(_settings)); - Add(new IntelGpuGroup(GetIntelCpus(), _settings)); - } - else - { - RemoveType(); - RemoveType(); - RemoveType(); - } - } - - _gpuEnabled = value; - } - } - - /// - public bool IsMemoryEnabled - { - get { return _memoryEnabled; } - set - { - if (_open && value != _memoryEnabled) - { - if (value) - Add(new MemoryGroup(_settings)); - else - RemoveType(); - } - - _memoryEnabled = value; - } - } - - /// - public bool IsMotherboardEnabled - { - get { return _motherboardEnabled; } - set - { - if (_open && value != _motherboardEnabled) - { - if (value) - Add(new MotherboardGroup(_smbios, _settings)); - else - RemoveType(); - } - - _motherboardEnabled = value; - } - } - - /// - public bool IsNetworkEnabled - { - get { return _networkEnabled; } - set - { - if (_open && value != _networkEnabled) - { - if (value) - Add(new NetworkGroup(_settings)); - else - RemoveType(); - } - - _networkEnabled = value; - } - } - - /// - public bool IsPsuEnabled - { - get { return _psuEnabled; } - set - { - if (_open && value != _psuEnabled) - { - if (value) - { - Add(new CorsairPsuGroup(_settings)); - } - else - { - RemoveType(); - } - } - - _psuEnabled = value; - } - } - - /// - public bool IsStorageEnabled - { - get { return _storageEnabled; } - set - { - if (_open && value != _storageEnabled) - { - if (value) - Add(new StorageGroup(_settings)); - else - RemoveType(); - } - - _storageEnabled = value; - } - } - - /// - /// Contains computer information table read in accordance with System Management BIOS (SMBIOS) Reference Specification. - /// - public SMBios SMBios - { - get - { - if (!_open) - throw new InvalidOperationException("SMBIOS cannot be accessed before opening."); - - return _smbios; - } - } - - //// - public string GetReport() + /// + public IList Hardware + { + get { lock (_lock) { - using StringWriter w = new(CultureInfo.InvariantCulture); - - w.WriteLine(); - w.WriteLine(nameof(LibreHardwareMonitor) + " Report"); - w.WriteLine(); - - Version version = typeof(Computer).Assembly.GetName().Version; - - NewSection(w); - w.Write("Version: "); - w.WriteLine(version.ToString()); - w.WriteLine(); - - NewSection(w); - w.Write("Common Language Runtime: "); - w.WriteLine(Environment.Version.ToString()); - w.Write("Operating System: "); - w.WriteLine(Environment.OSVersion.ToString()); - w.Write("Process Type: "); - w.WriteLine(IntPtr.Size == 4 ? "32-Bit" : "64-Bit"); - w.WriteLine(); - - string r = Ring0.GetReport(); - if (r != null) - { - NewSection(w); - w.Write(r); - w.WriteLine(); - } - - NewSection(w); - w.WriteLine("Sensors"); - w.WriteLine(); + List list = new(); foreach (IGroup group in _groups) - { - foreach (IHardware hardware in group.Hardware) - ReportHardwareSensorTree(hardware, w, string.Empty); - } + list.AddRange(group.Hardware); - w.WriteLine(); - - NewSection(w); - w.WriteLine("Parameters"); - w.WriteLine(); - - foreach (IGroup group in _groups) - { - foreach (IHardware hardware in group.Hardware) - ReportHardwareParameterTree(hardware, w, string.Empty); - } - - w.WriteLine(); - - foreach (IGroup group in _groups) - { - string report = group.GetReport(); - if (!string.IsNullOrEmpty(report)) - { - NewSection(w); - w.Write(report); - } - - foreach (IHardware hardware in group.Hardware) - ReportHardware(hardware, w); - } - - return w.ToString(); + return list; } } - - /// - /// Triggers the method for the given observer. - /// - /// Observer who call to devices. - public void Accept(IVisitor visitor) - { - if (visitor == null) - throw new ArgumentNullException(nameof(visitor)); - - visitor.VisitComputer(this); - } - - /// - /// Triggers the method with the given visitor for each device in each group. - /// - /// Observer who call to devices. - public void Traverse(IVisitor visitor) - { - lock (_lock) - { - // Use a for-loop instead of foreach to avoid a collection modified exception after sleep, even though everything is under a lock. - for (int i = 0; i < _groups.Count; i++) - { - IGroup group = _groups[i]; - - for (int j = 0; j < group.Hardware.Count; j++) - group.Hardware[j].Accept(visitor); - } - } - } - - private void HardwareAddedEvent(IHardware hardware) - { - HardwareAdded?.Invoke(hardware); - } - - private void HardwareRemovedEvent(IHardware hardware) - { - HardwareRemoved?.Invoke(hardware); - } - - private void Add(IGroup group) - { - if (group == null) - return; - - lock (_lock) - { - if (_groups.Contains(group)) - return; - - _groups.Add(group); - - if (group is IHardwareChanged hardwareChanged) - { - hardwareChanged.HardwareAdded += HardwareAddedEvent; - hardwareChanged.HardwareRemoved += HardwareRemovedEvent; - } - } - - if (HardwareAdded != null) - { - foreach (IHardware hardware in group.Hardware) - HardwareAdded(hardware); - } - } - - private void Remove(IGroup group) - { - lock (_lock) - { - if (!_groups.Contains(group)) - return; - - _groups.Remove(group); - - if (group is IHardwareChanged hardwareChanged) - { - hardwareChanged.HardwareAdded -= HardwareAddedEvent; - hardwareChanged.HardwareRemoved -= HardwareRemovedEvent; - } - } - - if (HardwareRemoved != null) - { - foreach (IHardware hardware in group.Hardware) - HardwareRemoved(hardware); - } - - group.Close(); - } - - private void RemoveType() where T : IGroup - { - List list = new(); - - lock (_lock) - { - foreach (IGroup group in _groups) - { - if (group is T t) - list.Add(t); - } - } - - foreach (T group in list) - Remove(group); - } - - /// - /// If hasn't been opened before, opens , , and triggers the private method depending on which categories are - /// enabled. - /// - public void Open() - { - if (_open) - return; - - _smbios = new SMBios(); - - Ring0.Open(); - OpCode.Open(); - - AddGroups(); - - _open = true; - } - - private void AddGroups() - { - if (_motherboardEnabled) - Add(new MotherboardGroup(_smbios, _settings)); - - if (_cpuEnabled) - Add(new CpuGroup(_settings)); - - if (_memoryEnabled) - Add(new MemoryGroup(_settings)); - - if (_gpuEnabled) - { - Add(new AmdGpuGroup(_settings)); - Add(new NvidiaGroup(_settings)); - Add(new IntelGpuGroup(GetIntelCpus(), _settings)); - } - - if (_controllerEnabled) - { - Add(new TBalancerGroup(_settings)); - Add(new HeatmasterGroup(_settings)); - Add(new AquaComputerGroup(_settings)); - Add(new AeroCoolGroup(_settings)); - Add(new NzxtGroup(_settings)); - } - - if (_storageEnabled) - Add(new StorageGroup(_settings)); - - if (_networkEnabled) - Add(new NetworkGroup(_settings)); - - if (_psuEnabled) - Add(new CorsairPsuGroup(_settings)); - - if (_batteryEnabled) - Add(new BatteryGroup(_settings)); - } - - private static void NewSection(TextWriter writer) - { - for (int i = 0; i < 8; i++) - writer.Write("----------"); - - writer.WriteLine(); - writer.WriteLine(); - } - - private static int CompareSensor(ISensor a, ISensor b) - { - int c = a.SensorType.CompareTo(b.SensorType); - if (c == 0) - return a.Index.CompareTo(b.Index); - - return c; - } - - private static void ReportHardwareSensorTree(IHardware hardware, TextWriter w, string space) - { - w.WriteLine("{0}|", space); - w.WriteLine("{0}+- {1} ({2})", space, hardware.Name, hardware.Identifier); - - ISensor[] sensors = hardware.Sensors; - Array.Sort(sensors, CompareSensor); - - foreach (ISensor sensor in sensors) - w.WriteLine("{0}| +- {1,-14} : {2,8:G6} {3,8:G6} {4,8:G6} ({5})", space, sensor.Name, sensor.Value, sensor.Min, sensor.Max, sensor.Identifier); - - foreach (IHardware subHardware in hardware.SubHardware) - ReportHardwareSensorTree(subHardware, w, "| "); - } - - private static void ReportHardwareParameterTree(IHardware hardware, TextWriter w, string space) - { - w.WriteLine("{0}|", space); - w.WriteLine("{0}+- {1} ({2})", space, hardware.Name, hardware.Identifier); - - ISensor[] sensors = hardware.Sensors; - Array.Sort(sensors, CompareSensor); - - foreach (ISensor sensor in sensors) - { - string innerSpace = space + "| "; - if (sensor.Parameters.Count > 0) - { - w.WriteLine("{0}|", innerSpace); - w.WriteLine("{0}+- {1} ({2})", innerSpace, sensor.Name, sensor.Identifier); - - foreach (IParameter parameter in sensor.Parameters) - { - string innerInnerSpace = innerSpace + "| "; - w.WriteLine("{0}+- {1} : {2}", innerInnerSpace, parameter.Name, string.Format(CultureInfo.InvariantCulture, "{0} : {1}", parameter.DefaultValue, parameter.Value)); - } - } - } - - foreach (IHardware subHardware in hardware.SubHardware) - ReportHardwareParameterTree(subHardware, w, "| "); - } - - private static void ReportHardware(IHardware hardware, TextWriter w) - { - string hardwareReport = hardware.GetReport(); - if (!string.IsNullOrEmpty(hardwareReport)) - { - NewSection(w); - w.Write(hardwareReport); - } - - foreach (IHardware subHardware in hardware.SubHardware) - ReportHardware(subHardware, w); - } - - /// - /// If opened before, removes all and triggers , and . - /// - public void Close() - { - if (!_open) - return; - - lock (_lock) - { - while (_groups.Count > 0) - { - IGroup group = _groups[_groups.Count - 1]; - Remove(group); - } - } - - OpCode.Close(); - InpOut.Close(); - Ring0.Close(); - - _smbios = null; - _open = false; - } - - /// - /// If opened before, removes all and recreates it. - /// - public void Reset() - { - if (!_open) - return; - - RemoveGroups(); - AddGroups(); - } - - private void RemoveGroups() - { - lock (_lock) - { - while (_groups.Count > 0) - { - IGroup group = _groups[_groups.Count - 1]; - Remove(group); - } - } - } - - private List GetIntelCpus() - { - // Create a temporary cpu group if one has not been added. - lock (_lock) - { - IGroup cpuGroup = _groups.Find(x => x is CpuGroup) ?? new CpuGroup(_settings); - return cpuGroup.Hardware.Select(x => x as IntelCpu).ToList(); - } - } - - /// - /// specific additional settings passed to its . - /// - private class Settings : ISettings - { - public bool Contains(string name) - { - return false; - } - - public void SetValue(string name, string value) - { } - - public string GetValue(string name, string value) - { - return value; - } - - public void Remove(string name) - { } - } + } + + /// + public bool IsBatteryEnabled + { + get { return _batteryEnabled; } + set + { + if (_open && value != _batteryEnabled) + { + if (value) + { + Add(new BatteryGroup(_settings)); + } + else + { + RemoveType(); + } + } + + _batteryEnabled = value; + } + } + + /// + public bool IsControllerEnabled + { + get { return _controllerEnabled; } + set + { + if (_open && value != _controllerEnabled) + { + if (value) + { + Add(new TBalancerGroup(_settings)); + Add(new HeatmasterGroup(_settings)); + Add(new AquaComputerGroup(_settings)); + Add(new AeroCoolGroup(_settings)); + Add(new NzxtGroup(_settings)); + } + else + { + RemoveType(); + RemoveType(); + RemoveType(); + RemoveType(); + RemoveType(); + } + } + + _controllerEnabled = value; + } + } + + /// + public bool IsCpuEnabled + { + get { return _cpuEnabled; } + set + { + if (_open && value != _cpuEnabled) + { + if (value) + Add(new CpuGroup(_settings)); + else + RemoveType(); + } + + _cpuEnabled = value; + } + } + + /// + public bool IsGpuEnabled + { + get { return _gpuEnabled; } + set + { + if (_open && value != _gpuEnabled) + { + if (value) + { + Add(new AmdGpuGroup(_settings)); + Add(new NvidiaGroup(_settings)); + Add(new IntelGpuGroup(GetIntelCpus(), _settings)); + } + else + { + RemoveType(); + RemoveType(); + RemoveType(); + } + } + + _gpuEnabled = value; + } + } + + /// + public bool IsMemoryEnabled + { + get { return _memoryEnabled; } + set + { + if (_open && value != _memoryEnabled) + { + if (value) + Add(new MemoryGroup(_settings)); + else + RemoveType(); + } + + _memoryEnabled = value; + } + } + + /// + public bool IsMotherboardEnabled + { + get { return _motherboardEnabled; } + set + { + if (_open && value != _motherboardEnabled) + { + if (value) + Add(new MotherboardGroup(_smbios, _settings)); + else + RemoveType(); + } + + _motherboardEnabled = value; + } + } + + /// + public bool IsNetworkEnabled + { + get { return _networkEnabled; } + set + { + if (_open && value != _networkEnabled) + { + if (value) + Add(new NetworkGroup(_settings)); + else + RemoveType(); + } + + _networkEnabled = value; + } + } + + /// + public bool IsPsuEnabled + { + get { return _psuEnabled; } + set + { + if (_open && value != _psuEnabled) + { + if (value) + { + Add(new CorsairPsuGroup(_settings)); + } + else + { + RemoveType(); + } + } + + _psuEnabled = value; + } + } + + /// + public bool IsStorageEnabled + { + get { return _storageEnabled; } + set + { + if (_open && value != _storageEnabled) + { + if (value) + Add(new StorageGroup(_settings)); + else + RemoveType(); + } + + _storageEnabled = value; + } + } + + /// + /// Contains computer information table read in accordance with System Management BIOS (SMBIOS) Reference Specification. + /// + public SMBios SMBios + { + get + { + if (!_open) + throw new InvalidOperationException("SMBIOS cannot be accessed before opening."); + + return _smbios; + } + } + + //// + public string GetReport() + { + lock (_lock) + { + using StringWriter w = new(CultureInfo.InvariantCulture); + + w.WriteLine(); + w.WriteLine(nameof(LibreHardwareMonitor) + " Report"); + w.WriteLine(); + + Version version = typeof(Computer).Assembly.GetName().Version; + + NewSection(w); + w.Write("Version: "); + w.WriteLine(version.ToString()); + w.WriteLine(); + + NewSection(w); + w.Write("Common Language Runtime: "); + w.WriteLine(Environment.Version.ToString()); + w.Write("Operating System: "); + w.WriteLine(Environment.OSVersion.ToString()); + w.Write("Process Type: "); + w.WriteLine(IntPtr.Size == 4 ? "32-Bit" : "64-Bit"); + w.WriteLine(); + + string r = Ring0.GetReport(); + if (r != null) + { + NewSection(w); + w.Write(r); + w.WriteLine(); + } + + NewSection(w); + w.WriteLine("Sensors"); + w.WriteLine(); + + foreach (IGroup group in _groups) + { + foreach (IHardware hardware in group.Hardware) + ReportHardwareSensorTree(hardware, w, string.Empty); + } + + w.WriteLine(); + + NewSection(w); + w.WriteLine("Parameters"); + w.WriteLine(); + + foreach (IGroup group in _groups) + { + foreach (IHardware hardware in group.Hardware) + ReportHardwareParameterTree(hardware, w, string.Empty); + } + + w.WriteLine(); + + foreach (IGroup group in _groups) + { + string report = group.GetReport(); + if (!string.IsNullOrEmpty(report)) + { + NewSection(w); + w.Write(report); + } + + foreach (IHardware hardware in group.Hardware) + ReportHardware(hardware, w); + } + + return w.ToString(); + } + } + + /// + /// Triggers the method for the given observer. + /// + /// Observer who call to devices. + public void Accept(IVisitor visitor) + { + if (visitor == null) + throw new ArgumentNullException(nameof(visitor)); + + visitor.VisitComputer(this); + } + + /// + /// Triggers the method with the given visitor for each device in each group. + /// + /// Observer who call to devices. + public void Traverse(IVisitor visitor) + { + lock (_lock) + { + // Use a for-loop instead of foreach to avoid a collection modified exception after sleep, even though everything is under a lock. + for (int i = 0; i < _groups.Count; i++) + { + IGroup group = _groups[i]; + + for (int j = 0; j < group.Hardware.Count; j++) + group.Hardware[j].Accept(visitor); + } + } + } + + private void HardwareAddedEvent(IHardware hardware) + { + HardwareAdded?.Invoke(hardware); + } + + private void HardwareRemovedEvent(IHardware hardware) + { + HardwareRemoved?.Invoke(hardware); + } + + private void Add(IGroup group) + { + if (group == null) + return; + + lock (_lock) + { + if (_groups.Contains(group)) + return; + + _groups.Add(group); + + if (group is IHardwareChanged hardwareChanged) + { + hardwareChanged.HardwareAdded += HardwareAddedEvent; + hardwareChanged.HardwareRemoved += HardwareRemovedEvent; + } + } + + if (HardwareAdded != null) + { + foreach (IHardware hardware in group.Hardware) + HardwareAdded(hardware); + } + } + + private void Remove(IGroup group) + { + lock (_lock) + { + if (!_groups.Contains(group)) + return; + + _groups.Remove(group); + + if (group is IHardwareChanged hardwareChanged) + { + hardwareChanged.HardwareAdded -= HardwareAddedEvent; + hardwareChanged.HardwareRemoved -= HardwareRemovedEvent; + } + } + + if (HardwareRemoved != null) + { + foreach (IHardware hardware in group.Hardware) + HardwareRemoved(hardware); + } + + group.Close(); + } + + private void RemoveType() where T : IGroup + { + List list = new(); + + lock (_lock) + { + foreach (IGroup group in _groups) + { + if (group is T t) + list.Add(t); + } + } + + foreach (T group in list) + Remove(group); + } + + /// + /// If hasn't been opened before, opens , , and triggers the private method depending on which categories are + /// enabled. + /// + public void Open() + { + if (_open) + return; + + _smbios = new SMBios(); + + Ring0.Open(); + OpCode.Open(); + + AddGroups(); + + _open = true; + } + + private void AddGroups() + { + if (_motherboardEnabled) + Add(new MotherboardGroup(_smbios, _settings)); + + if (_cpuEnabled) + Add(new CpuGroup(_settings)); + + if (_memoryEnabled) + Add(new MemoryGroup(_settings)); + + if (_gpuEnabled) + { + Add(new AmdGpuGroup(_settings)); + Add(new NvidiaGroup(_settings)); + Add(new IntelGpuGroup(GetIntelCpus(), _settings)); + } + + if (_controllerEnabled) + { + Add(new TBalancerGroup(_settings)); + Add(new HeatmasterGroup(_settings)); + Add(new AquaComputerGroup(_settings)); + Add(new AeroCoolGroup(_settings)); + Add(new NzxtGroup(_settings)); + } + + if (_storageEnabled) + Add(new StorageGroup(_settings)); + + if (_networkEnabled) + Add(new NetworkGroup(_settings)); + + if (_psuEnabled) + Add(new CorsairPsuGroup(_settings)); + + if (_batteryEnabled) + Add(new BatteryGroup(_settings)); + } + + private static void NewSection(TextWriter writer) + { + for (int i = 0; i < 8; i++) + writer.Write("----------"); + + writer.WriteLine(); + writer.WriteLine(); + } + + private static int CompareSensor(ISensor a, ISensor b) + { + int c = a.SensorType.CompareTo(b.SensorType); + if (c == 0) + return a.Index.CompareTo(b.Index); + + return c; + } + + private static void ReportHardwareSensorTree(IHardware hardware, TextWriter w, string space) + { + w.WriteLine("{0}|", space); + w.WriteLine("{0}+- {1} ({2})", space, hardware.Name, hardware.Identifier); + + ISensor[] sensors = hardware.Sensors; + Array.Sort(sensors, CompareSensor); + + foreach (ISensor sensor in sensors) + w.WriteLine("{0}| +- {1,-14} : {2,8:G6} {3,8:G6} {4,8:G6} ({5})", space, sensor.Name, sensor.Value, sensor.Min, sensor.Max, sensor.Identifier); + + foreach (IHardware subHardware in hardware.SubHardware) + ReportHardwareSensorTree(subHardware, w, "| "); + } + + private static void ReportHardwareParameterTree(IHardware hardware, TextWriter w, string space) + { + w.WriteLine("{0}|", space); + w.WriteLine("{0}+- {1} ({2})", space, hardware.Name, hardware.Identifier); + + ISensor[] sensors = hardware.Sensors; + Array.Sort(sensors, CompareSensor); + + foreach (ISensor sensor in sensors) + { + string innerSpace = space + "| "; + if (sensor.Parameters.Count > 0) + { + w.WriteLine("{0}|", innerSpace); + w.WriteLine("{0}+- {1} ({2})", innerSpace, sensor.Name, sensor.Identifier); + + foreach (IParameter parameter in sensor.Parameters) + { + string innerInnerSpace = innerSpace + "| "; + w.WriteLine("{0}+- {1} : {2}", innerInnerSpace, parameter.Name, string.Format(CultureInfo.InvariantCulture, "{0} : {1}", parameter.DefaultValue, parameter.Value)); + } + } + } + + foreach (IHardware subHardware in hardware.SubHardware) + ReportHardwareParameterTree(subHardware, w, "| "); + } + + private static void ReportHardware(IHardware hardware, TextWriter w) + { + string hardwareReport = hardware.GetReport(); + if (!string.IsNullOrEmpty(hardwareReport)) + { + NewSection(w); + w.Write(hardwareReport); + } + + foreach (IHardware subHardware in hardware.SubHardware) + ReportHardware(subHardware, w); + } + + /// + /// If opened before, removes all and triggers , and . + /// + public void Close() + { + if (!_open) + return; + + lock (_lock) + { + while (_groups.Count > 0) + { + IGroup group = _groups[_groups.Count - 1]; + Remove(group); + } + } + + OpCode.Close(); + InpOut.Close(); + Ring0.Close(); + + _smbios = null; + _open = false; + } + + /// + /// If opened before, removes all and recreates it. + /// + public void Reset() + { + if (!_open) + return; + + RemoveGroups(); + AddGroups(); + } + + private void RemoveGroups() + { + lock (_lock) + { + while (_groups.Count > 0) + { + IGroup group = _groups[_groups.Count - 1]; + Remove(group); + } + } + } + + private List GetIntelCpus() + { + // Create a temporary cpu group if one has not been added. + lock (_lock) + { + IGroup cpuGroup = _groups.Find(x => x is CpuGroup) ?? new CpuGroup(_settings); + return cpuGroup.Hardware.Select(x => x as IntelCpu).ToList(); + } + } + + /// + /// specific additional settings passed to its . + /// + private class Settings : ISettings + { + public bool Contains(string name) + { + return false; + } + + public void SetValue(string name, string value) + { } + + public string GetValue(string name, string value) + { + return value; + } + + public void Remove(string name) + { } } } diff --git a/LibreHardwareMonitorLib/Hardware/Control.cs b/LibreHardwareMonitorLib/Hardware/Control.cs index 03f876a..3a638af 100644 --- a/LibreHardwareMonitorLib/Hardware/Control.cs +++ b/LibreHardwareMonitorLib/Hardware/Control.cs @@ -6,93 +6,92 @@ using System.Globalization; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal delegate void ControlEventHandler(Control control); + +internal class Control : IControl { - internal delegate void ControlEventHandler(Control control); + private readonly ISettings _settings; + private ControlMode _mode; + private float _softwareValue; - internal class Control : IControl + public Control + ( + ISensor sensor, + ISettings settings, + float minSoftwareValue, + float maxSoftwareValue) { - private readonly ISettings _settings; - private ControlMode _mode; - private float _softwareValue; + _settings = settings; - public Control - ( - ISensor sensor, - ISettings settings, - float minSoftwareValue, - float maxSoftwareValue) + Identifier = new Identifier(sensor.Identifier, "control"); + Sensor = sensor; + MinSoftwareValue = minSoftwareValue; + MaxSoftwareValue = maxSoftwareValue; + + if (!float.TryParse(settings.GetValue(new Identifier(Identifier, "value").ToString(), "0"), NumberStyles.Float, CultureInfo.InvariantCulture, out _softwareValue)) + _softwareValue = 0; + + if (!int.TryParse(settings.GetValue(new Identifier(Identifier, "mode").ToString(), ((int)ControlMode.Undefined).ToString(CultureInfo.InvariantCulture)), + NumberStyles.Integer, + CultureInfo.InvariantCulture, + out int mode)) { - _settings = settings; + _mode = ControlMode.Undefined; + } + else + _mode = (ControlMode)mode; + } - Identifier = new Identifier(sensor.Identifier, "control"); - Sensor = sensor; - MinSoftwareValue = minSoftwareValue; - MaxSoftwareValue = maxSoftwareValue; + internal event ControlEventHandler ControlModeChanged; - if (!float.TryParse(settings.GetValue(new Identifier(Identifier, "value").ToString(), "0"), NumberStyles.Float, CultureInfo.InvariantCulture, out _softwareValue)) - _softwareValue = 0; + internal event ControlEventHandler SoftwareControlValueChanged; - if (!int.TryParse(settings.GetValue(new Identifier(Identifier, "mode").ToString(), ((int)ControlMode.Undefined).ToString(CultureInfo.InvariantCulture)), - NumberStyles.Integer, - CultureInfo.InvariantCulture, - out int mode)) + public ControlMode ControlMode + { + get { return _mode; } + private set + { + if (_mode != value) { - _mode = ControlMode.Undefined; + _mode = value; + ControlModeChanged?.Invoke(this); + _settings.SetValue(new Identifier(Identifier, "mode").ToString(), ((int)_mode).ToString(CultureInfo.InvariantCulture)); } - else - _mode = (ControlMode)mode; - } - - internal event ControlEventHandler ControlModeChanged; - - internal event ControlEventHandler SoftwareControlValueChanged; - - public ControlMode ControlMode - { - get { return _mode; } - private set - { - if (_mode != value) - { - _mode = value; - ControlModeChanged?.Invoke(this); - _settings.SetValue(new Identifier(Identifier, "mode").ToString(), ((int)_mode).ToString(CultureInfo.InvariantCulture)); - } - } - } - - public Identifier Identifier { get; } - - public float MaxSoftwareValue { get; } - - public float MinSoftwareValue { get; } - - public ISensor Sensor { get; } - - public float SoftwareValue - { - get { return _softwareValue; } - private set - { - if (_softwareValue != value) - { - _softwareValue = value; - SoftwareControlValueChanged?.Invoke(this); - _settings.SetValue(new Identifier(Identifier, "value").ToString(), value.ToString(CultureInfo.InvariantCulture)); - } - } - } - - public void SetDefault() - { - ControlMode = ControlMode.Default; - } - - public void SetSoftware(float value) - { - ControlMode = ControlMode.Software; - SoftwareValue = value; } } + + public Identifier Identifier { get; } + + public float MaxSoftwareValue { get; } + + public float MinSoftwareValue { get; } + + public ISensor Sensor { get; } + + public float SoftwareValue + { + get { return _softwareValue; } + private set + { + if (_softwareValue != value) + { + _softwareValue = value; + SoftwareControlValueChanged?.Invoke(this); + _settings.SetValue(new Identifier(Identifier, "value").ToString(), value.ToString(CultureInfo.InvariantCulture)); + } + } + } + + public void SetDefault() + { + ControlMode = ControlMode.Default; + } + + public void SetSoftware(float value) + { + ControlMode = ControlMode.Software; + SoftwareValue = value; + } } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/AeroCoolGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/AeroCoolGroup.cs index cd52e8d..3be349f 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/AeroCoolGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/AeroCoolGroup.cs @@ -7,52 +7,51 @@ using System.Collections.Generic; using System.Text; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.AeroCool +namespace LibreHardwareMonitor.Hardware.Controller.AeroCool; + +public class AeroCoolGroup : IGroup { - public class AeroCoolGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public AeroCoolGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); + _report.AppendLine("AeroCool Hardware"); + _report.AppendLine(); - public AeroCoolGroup(ISettings settings) + foreach (HidDevice dev in DeviceList.Local.GetHidDevices(0x2E97)) { - _report.AppendLine("AeroCool Hardware"); - _report.AppendLine(); - - foreach (HidDevice dev in DeviceList.Local.GetHidDevices(0x2E97)) + int hubno = dev.ProductID - 0x1000; + if (dev.DevicePath.Contains("mi_02") && hubno is >= 1 and <= 8) { - int hubno = dev.ProductID - 0x1000; - if (dev.DevicePath.Contains("mi_02") && hubno is >= 1 and <= 8) - { - var device = new P7H1(dev, settings); - _report.AppendLine($"Device name: {device.Name}"); - _report.AppendLine($"HUB number: {device.HubNumber}"); - _report.AppendLine(); - _hardware.Add(device); - } - } - - if (_hardware.Count == 0) - { - _report.AppendLine("No AeroCool Hardware found."); + var device = new P7H1(dev, settings); + _report.AppendLine($"Device name: {device.Name}"); + _report.AppendLine($"HUB number: {device.HubNumber}"); _report.AppendLine(); + _hardware.Add(device); } } - public IReadOnlyList Hardware => _hardware; - - public void Close() + if (_hardware.Count == 0) { - foreach (IHardware iHardware in _hardware) - { - if (iHardware is Hardware hardware) - hardware.Close(); - } - } - - public string GetReport() - { - return _report.ToString(); + _report.AppendLine("No AeroCool Hardware found."); + _report.AppendLine(); } } -} + + public IReadOnlyList Hardware => _hardware; + + public void Close() + { + foreach (IHardware iHardware in _hardware) + { + if (iHardware is Hardware hardware) + hardware.Close(); + } + } + + public string GetReport() + { + return _report.ToString(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/P7-H1.cs b/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/P7-H1.cs index d3323b0..2be3f88 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/P7-H1.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AeroCool/P7-H1.cs @@ -7,91 +7,90 @@ using System; using System.Threading.Tasks; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.AeroCool +namespace LibreHardwareMonitor.Hardware.Controller.AeroCool; + +internal sealed class P7H1 : Hardware { - internal sealed class P7H1 : Hardware + private const byte REPORT_ID = 0x0; + private readonly HidDevice _device; + + private readonly Sensor[] _rpm = new Sensor[5]; + private readonly float[] _speeds = new float[5]; + private readonly HidStream _stream; + private bool _running; + + public P7H1(HidDevice dev, ISettings settings) : base("AeroCool P7-H1", new Identifier(dev.DevicePath), settings) { - private const byte REPORT_ID = 0x0; - private readonly HidDevice _device; + _device = dev; + HubNumber = _device.ProductID - 0x1000; + Name = $"AeroCool P7-H1 #{HubNumber}"; - private readonly Sensor[] _rpm = new Sensor[5]; - private readonly float[] _speeds = new float[5]; - private readonly HidStream _stream; - private bool _running; - - public P7H1(HidDevice dev, ISettings settings) : base("AeroCool P7-H1", new Identifier(dev.DevicePath), settings) + if (_device.TryOpen(out _stream)) { - _device = dev; - HubNumber = _device.ProductID - 0x1000; - Name = $"AeroCool P7-H1 #{HubNumber}"; + _running = true; - if (_device.TryOpen(out _stream)) - { - _running = true; + Task.Run(ReadStream); - Task.Run(ReadStream); - - for (int i = 0; i < 5; i++) - { - _rpm[i] = new Sensor($"Fan #{i + 1}", i, SensorType.Fan, this, settings); - ActivateSensor(_rpm[i]); - } - } - } - - public override HardwareType HardwareType - { - get { return HardwareType.Cooler; } - } - - public int HubNumber { get; } - - private void ReadStream() - { - byte[] inputReportBuffer = new byte[_device.GetMaxInputReportLength()]; - - while (_running) - { - IAsyncResult ar = null; - - while (_running) - { - ar ??= _stream.BeginRead(inputReportBuffer, 0, inputReportBuffer.Length, null, null); - - if (ar.IsCompleted) - { - int byteCount = _stream.EndRead(ar); - ar = null; - - if (byteCount == 16 && inputReportBuffer[0] == REPORT_ID) - { - for (int i = 0; i < 5; i++) - { - _speeds[i] = (inputReportBuffer[(i * 3) + 2] * 256) + inputReportBuffer[(i * 3) + 3]; - } - } - } - else - { - ar.AsyncWaitHandle.WaitOne(1000); - } - } - } - } - - public override void Close() - { - _running = false; - _stream.Close(); - base.Close(); - } - - public override void Update() - { for (int i = 0; i < 5; i++) { - _rpm[i].Value = _speeds[i]; + _rpm[i] = new Sensor($"Fan #{i + 1}", i, SensorType.Fan, this, settings); + ActivateSensor(_rpm[i]); } } } -} + + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + public int HubNumber { get; } + + private void ReadStream() + { + byte[] inputReportBuffer = new byte[_device.GetMaxInputReportLength()]; + + while (_running) + { + IAsyncResult ar = null; + + while (_running) + { + ar ??= _stream.BeginRead(inputReportBuffer, 0, inputReportBuffer.Length, null, null); + + if (ar.IsCompleted) + { + int byteCount = _stream.EndRead(ar); + ar = null; + + if (byteCount == 16 && inputReportBuffer[0] == REPORT_ID) + { + for (int i = 0; i < 5; i++) + { + _speeds[i] = (inputReportBuffer[(i * 3) + 2] * 256) + inputReportBuffer[(i * 3) + 3]; + } + } + } + else + { + ar.AsyncWaitHandle.WaitOne(1000); + } + } + } + } + + public override void Close() + { + _running = false; + _stream.Close(); + base.Close(); + } + + public override void Update() + { + for (int i = 0; i < 5; i++) + { + _rpm[i].Value = _speeds[i]; + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs index c2a18dd..ac17195 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquaComputerGroup.cs @@ -7,88 +7,87 @@ using System.Collections.Generic; using System.Text; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer +namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer; + +public class AquaComputerGroup : IGroup { - public class AquaComputerGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public AquaComputerGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); + _report.AppendLine("AquaComputer Hardware"); + _report.AppendLine(); - public AquaComputerGroup(ISettings settings) + foreach (HidDevice dev in DeviceList.Local.GetHidDevices(0x0c70)) { - _report.AppendLine("AquaComputer Hardware"); + string productName = dev.GetProductName(); + productName = productName.Substring(0, 1).ToUpper() + productName.Substring(1); + + switch (dev.ProductID) + { + case 0xF00E: + var d5Next = new D5Next(dev, settings); + _report.AppendLine($"Device name: {productName}"); + _report.AppendLine($"Firmware version: {d5Next.FirmwareVersion}"); + _report.AppendLine(); + _hardware.Add(d5Next); + break; + + case 0xf0b6: + var aquastreamXt = new AquastreamXT(dev, settings); + _report.AppendLine($"Device name: {productName}"); + _report.AppendLine($"Device variant: {aquastreamXt.Variant}"); + _report.AppendLine($"Firmware version: {aquastreamXt.FirmwareVersion}"); + _report.AppendLine($"{aquastreamXt.Status}"); + _report.AppendLine(); + _hardware.Add(aquastreamXt); + break; + + case 0xf003: + var mps = new MPS(dev, settings); + _report.AppendLine($"Device name: {productName}"); + _report.AppendLine($"Firmware version: {mps.FirmwareVersion}"); + _report.AppendLine($"{mps.Status}"); + _report.AppendLine(); + _hardware.Add(mps); + break; + + case 0xF011: + var octo = new Octo(dev, settings); + _report.AppendLine($"Device name: {productName}"); + _report.AppendLine($"Firmware version: {octo.FirmwareVersion}"); + _report.AppendLine(); + _hardware.Add(octo); + break; + + default: + _report.AppendLine($"Unknown Hardware PID: {dev.ProductID} Name: {productName}"); + _report.AppendLine(); + break; + } + } + + if (_hardware.Count == 0) + { + _report.AppendLine("No AquaComputer Hardware found."); _report.AppendLine(); - - foreach (HidDevice dev in DeviceList.Local.GetHidDevices(0x0c70)) - { - string productName = dev.GetProductName(); - productName = productName.Substring(0, 1).ToUpper() + productName.Substring(1); - - switch (dev.ProductID) - { - case 0xF00E: - var d5Next = new D5Next(dev, settings); - _report.AppendLine($"Device name: {productName}"); - _report.AppendLine($"Firmware version: {d5Next.FirmwareVersion}"); - _report.AppendLine(); - _hardware.Add(d5Next); - break; - - case 0xf0b6: - var aquastreamXt = new AquastreamXT(dev, settings); - _report.AppendLine($"Device name: {productName}"); - _report.AppendLine($"Device variant: {aquastreamXt.Variant}"); - _report.AppendLine($"Firmware version: {aquastreamXt.FirmwareVersion}"); - _report.AppendLine($"{aquastreamXt.Status}"); - _report.AppendLine(); - _hardware.Add(aquastreamXt); - break; - - case 0xf003: - var mps = new MPS(dev, settings); - _report.AppendLine($"Device name: {productName}"); - _report.AppendLine($"Firmware version: {mps.FirmwareVersion}"); - _report.AppendLine($"{mps.Status}"); - _report.AppendLine(); - _hardware.Add(mps); - break; - - case 0xF011: - var octo = new Octo(dev, settings); - _report.AppendLine($"Device name: {productName}"); - _report.AppendLine($"Firmware version: {octo.FirmwareVersion}"); - _report.AppendLine(); - _hardware.Add(octo); - break; - - default: - _report.AppendLine($"Unknown Hardware PID: {dev.ProductID} Name: {productName}"); - _report.AppendLine(); - break; - } - } - - if (_hardware.Count == 0) - { - _report.AppendLine("No AquaComputer Hardware found."); - _report.AppendLine(); - } - } - - public IReadOnlyList Hardware => _hardware; - - public void Close() - { - foreach (IHardware iHardware in _hardware) - { - if (iHardware is Hardware hardware) - hardware.Close(); - } - } - - public string GetReport() - { - return _report.ToString(); } } -} + + public IReadOnlyList Hardware => _hardware; + + public void Close() + { + foreach (IHardware iHardware in _hardware) + { + if (iHardware is Hardware hardware) + hardware.Close(); + } + } + + public string GetReport() + { + return _report.ToString(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquastreamXT.cs b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquastreamXT.cs index 25c05bf..896185a 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquastreamXT.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/AquastreamXT.cs @@ -7,155 +7,153 @@ using System; using System.Diagnostics.CodeAnalysis; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer +namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer; +//TODO: +//Check tested and fix unknown variables in Update() +//Check if property "Variant" is valid interpreted +//Implement Fan Control in SetControl() + +internal sealed class AquastreamXT : Hardware { - //TODO: - //Check tested and fix unknown variables in Update() - //Check if property "Variant" is valid interpreted - //Implement Fan Control in SetControl() + private readonly Sensor _fanControl; + private readonly Sensor[] _frequencies = new Sensor[2]; + private readonly Sensor _pumpFlow; + private readonly Sensor _pumpPower; + private readonly byte[] _rawData = new byte[64]; + private readonly Sensor[] _rpmSensors = new Sensor[2]; + private readonly HidStream _stream; + private readonly Sensor[] _temperatures = new Sensor[3]; + private readonly Sensor[] _voltages = new Sensor[2]; - internal sealed class AquastreamXT : Hardware + public AquastreamXT(HidDevice dev, ISettings settings) : base("Aquastream XT", new Identifier(dev.DevicePath), settings) { - private readonly Sensor _fanControl; - private readonly Sensor[] _frequencies = new Sensor[2]; - private readonly Sensor _pumpFlow; - private readonly Sensor _pumpPower; - private readonly byte[] _rawData = new byte[64]; - private readonly Sensor[] _rpmSensors = new Sensor[2]; - private readonly HidStream _stream; - private readonly Sensor[] _temperatures = new Sensor[3]; - private readonly Sensor[] _voltages = new Sensor[2]; - - public AquastreamXT(HidDevice dev, ISettings settings) : base("Aquastream XT", new Identifier(dev.DevicePath), settings) + if (dev.TryOpen(out _stream)) { - if (dev.TryOpen(out _stream)) + do { - do - { - _rawData[0] = 0x4; - _stream.GetFeature(_rawData); - } - while (_rawData[0] != 0x4); - - Name = $"Aquastream XT {Variant}"; - FirmwareVersion = BitConverter.ToUInt16(_rawData, 50); - - _temperatures[0] = new Sensor("External Fan VRM", 0, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[0]); - _temperatures[1] = new Sensor("External", 1, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[1]); - _temperatures[2] = new Sensor("Internal Water", 2, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[2]); - - _voltages[0] = new Sensor("External Fan", 1, SensorType.Voltage, this, Array.Empty(), settings); - ActivateSensor(_voltages[0]); - _voltages[1] = new Sensor("Pump", 2, SensorType.Voltage, this, Array.Empty(), settings); - ActivateSensor(_voltages[1]); - - _pumpPower = new Sensor("Pump", 0, SensorType.Power, this, Array.Empty(), settings); - ActivateSensor(_pumpPower); - - _pumpFlow = new Sensor("Pump", 0, SensorType.Flow, this, Array.Empty(), settings); - ActivateSensor(_pumpFlow); - - _rpmSensors[0] = new Sensor("External Fan", 0, SensorType.Fan, this, Array.Empty(), settings); - ActivateSensor(_rpmSensors[0]); - _rpmSensors[1] = new Sensor("Pump", 1, SensorType.Fan, this, Array.Empty(), settings); - ActivateSensor(_rpmSensors[1]); - - _fanControl = new Sensor("External Fan", 0, SensorType.Control, this, Array.Empty(), settings); - _fanControl.Control = new Control(_fanControl, settings, 0, 100); - - ActivateSensor(_fanControl); - _frequencies[0] = new Sensor("Pump Frequency", 0, SensorType.Frequency, this, Array.Empty(), settings); - ActivateSensor(_frequencies[0]); - _frequencies[1] = new Sensor("Pump MaxFrequency", 1, SensorType.Frequency, this, Array.Empty(), settings); - ActivateSensor(_frequencies[1]); + _rawData[0] = 0x4; + _stream.GetFeature(_rawData); } - } + while (_rawData[0] != 0x4); - public ushort FirmwareVersion { get; private set; } + Name = $"Aquastream XT {Variant}"; + FirmwareVersion = BitConverter.ToUInt16(_rawData, 50); - public override HardwareType HardwareType - { - get { return HardwareType.Cooler; } - } + _temperatures[0] = new Sensor("External Fan VRM", 0, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[0]); + _temperatures[1] = new Sensor("External", 1, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[1]); + _temperatures[2] = new Sensor("Internal Water", 2, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[2]); - public string Status - { - get - { - FirmwareVersion = BitConverter.ToUInt16(_rawData, 50); - return FirmwareVersion < 1008 ? $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 1018" : "Status: OK"; - } - } + _voltages[0] = new Sensor("External Fan", 1, SensorType.Voltage, this, Array.Empty(), settings); + ActivateSensor(_voltages[0]); + _voltages[1] = new Sensor("Pump", 2, SensorType.Voltage, this, Array.Empty(), settings); + ActivateSensor(_voltages[1]); - //TODO: Check if valid - public string Variant - { - get - { - MODE mode = (MODE)_rawData[33]; + _pumpPower = new Sensor("Pump", 0, SensorType.Power, this, Array.Empty(), settings); + ActivateSensor(_pumpPower); - if (mode.HasFlag(MODE.MODE_PUMP_ADV)) - return "Ultra + Internal Flow Sensor"; + _pumpFlow = new Sensor("Pump", 0, SensorType.Flow, this, Array.Empty(), settings); + ActivateSensor(_pumpFlow); - if (mode.HasFlag(MODE.MODE_FAN_CONTROLLER)) - return "Ultra"; + _rpmSensors[0] = new Sensor("External Fan", 0, SensorType.Fan, this, Array.Empty(), settings); + ActivateSensor(_rpmSensors[0]); + _rpmSensors[1] = new Sensor("Pump", 1, SensorType.Fan, this, Array.Empty(), settings); + ActivateSensor(_rpmSensors[1]); - if (mode.HasFlag(MODE.MODE_FAN_AMP)) - return "Advanced"; + _fanControl = new Sensor("External Fan", 0, SensorType.Control, this, Array.Empty(), settings); + _fanControl.Control = new Control(_fanControl, settings, 0, 100); - return "Standard"; - } - } - - public override void Close() - { - _stream.Close(); - - base.Close(); - } - - //TODO: Check tested and fix unknown variables - public override void Update() - { - _rawData[0] = 0x4; - _stream.GetFeature(_rawData); - - if (_rawData[0] != 0x4) - return; - - //var rawSensorsFan = BitConverter.ToUInt16(rawData, 1); //unknown - redundant? - //var rawSensorsExt = BitConverter.ToUInt16(rawData, 3); //unknown - redundant? - //var rawSensorsWater = BitConverter.ToUInt16(rawData, 5); //unknown - redundant? - - _voltages[0].Value = BitConverter.ToUInt16(_rawData, 7) / 61f; //External Fan Voltage: tested - OK - _voltages[1].Value = BitConverter.ToUInt16(_rawData, 9) / 61f; //Pump Voltage: tested - OK - _pumpPower.Value = _voltages[1].Value * BitConverter.ToInt16(_rawData, 11) / 625f; //Pump Voltage * Pump Current: tested - OK - - _temperatures[0].Value = BitConverter.ToUInt16(_rawData, 13) / 100f; //External Fan VRM Temperature: untested - _temperatures[1].Value = BitConverter.ToUInt16(_rawData, 15) / 100f; //External Temperature Sensor: untested - _temperatures[2].Value = BitConverter.ToUInt16(_rawData, 17) / 100f; //Internal Water Temperature Sensor: tested - OK - - _frequencies[0].Value = (1f / BitConverter.ToInt16(_rawData, 19)) * 750000; //Pump Frequency: tested - OK - _rpmSensors[1].Value = _frequencies[0].Value * 60f; //Pump RPM: tested - OK - _frequencies[1].Value = (1f / BitConverter.ToUInt16(_rawData, 21)) * 750000; //Pump Max Frequency: tested - OK - - _pumpFlow.Value = BitConverter.ToUInt32(_rawData, 23); //Internal Pump Flow Sensor: unknown - - _rpmSensors[0].Value = BitConverter.ToUInt32(_rawData, 27); //External Fan RPM: untested - - _fanControl.Value = 100f / byte.MaxValue * _rawData[31]; //External Fan Control: tested, External Fan Voltage scales by this value - OK - } - - [Flags] - [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum MODE : byte - { - MODE_PUMP_ADV = 1, - MODE_FAN_AMP = 2, - MODE_FAN_CONTROLLER = 4 + ActivateSensor(_fanControl); + _frequencies[0] = new Sensor("Pump Frequency", 0, SensorType.Frequency, this, Array.Empty(), settings); + ActivateSensor(_frequencies[0]); + _frequencies[1] = new Sensor("Pump MaxFrequency", 1, SensorType.Frequency, this, Array.Empty(), settings); + ActivateSensor(_frequencies[1]); } } -} + + public ushort FirmwareVersion { get; private set; } + + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + public string Status + { + get + { + FirmwareVersion = BitConverter.ToUInt16(_rawData, 50); + return FirmwareVersion < 1008 ? $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 1018" : "Status: OK"; + } + } + + //TODO: Check if valid + public string Variant + { + get + { + MODE mode = (MODE)_rawData[33]; + + if (mode.HasFlag(MODE.MODE_PUMP_ADV)) + return "Ultra + Internal Flow Sensor"; + + if (mode.HasFlag(MODE.MODE_FAN_CONTROLLER)) + return "Ultra"; + + if (mode.HasFlag(MODE.MODE_FAN_AMP)) + return "Advanced"; + + return "Standard"; + } + } + + public override void Close() + { + _stream.Close(); + + base.Close(); + } + + //TODO: Check tested and fix unknown variables + public override void Update() + { + _rawData[0] = 0x4; + _stream.GetFeature(_rawData); + + if (_rawData[0] != 0x4) + return; + + //var rawSensorsFan = BitConverter.ToUInt16(rawData, 1); //unknown - redundant? + //var rawSensorsExt = BitConverter.ToUInt16(rawData, 3); //unknown - redundant? + //var rawSensorsWater = BitConverter.ToUInt16(rawData, 5); //unknown - redundant? + + _voltages[0].Value = BitConverter.ToUInt16(_rawData, 7) / 61f; //External Fan Voltage: tested - OK + _voltages[1].Value = BitConverter.ToUInt16(_rawData, 9) / 61f; //Pump Voltage: tested - OK + _pumpPower.Value = _voltages[1].Value * BitConverter.ToInt16(_rawData, 11) / 625f; //Pump Voltage * Pump Current: tested - OK + + _temperatures[0].Value = BitConverter.ToUInt16(_rawData, 13) / 100f; //External Fan VRM Temperature: untested + _temperatures[1].Value = BitConverter.ToUInt16(_rawData, 15) / 100f; //External Temperature Sensor: untested + _temperatures[2].Value = BitConverter.ToUInt16(_rawData, 17) / 100f; //Internal Water Temperature Sensor: tested - OK + + _frequencies[0].Value = (1f / BitConverter.ToInt16(_rawData, 19)) * 750000; //Pump Frequency: tested - OK + _rpmSensors[1].Value = _frequencies[0].Value * 60f; //Pump RPM: tested - OK + _frequencies[1].Value = (1f / BitConverter.ToUInt16(_rawData, 21)) * 750000; //Pump Max Frequency: tested - OK + + _pumpFlow.Value = BitConverter.ToUInt32(_rawData, 23); //Internal Pump Flow Sensor: unknown + + _rpmSensors[0].Value = BitConverter.ToUInt32(_rawData, 27); //External Fan RPM: untested + + _fanControl.Value = 100f / byte.MaxValue * _rawData[31]; //External Fan Control: tested, External Fan Voltage scales by this value - OK + } + + [Flags] + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum MODE : byte + { + MODE_PUMP_ADV = 1, + MODE_FAN_AMP = 2, + MODE_FAN_CONTROLLER = 4 + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/D5Next.cs b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/D5Next.cs index 9f06222..f429563 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/D5Next.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/D5Next.cs @@ -6,61 +6,60 @@ using System; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer +namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer; + +internal sealed class D5Next : Hardware { - internal sealed class D5Next : Hardware + //Available Reports, found them by looking at the below methods + //var test = dev.GetRawReportDescriptor(); + //var test2 = dev.GetReportDescriptor(); + + // ID 1; Length 158; INPUT + // ID 2; Length 11; OUTPUT + // ID 3; Length 1025; <-- works FEATURE + // ID 8; Length 1025; <-- works FEATURE + // ID 12; Length 1025; <-- 0xC FEATURE + + private readonly byte[] _rawData = new byte[1025]; + private readonly Sensor[] _rpmSensors = new Sensor[1]; + private readonly HidStream _stream; + private readonly Sensor[] _temperatures = new Sensor[1]; + + public D5Next(HidDevice dev, ISettings settings) : base("D5Next", new Identifier(dev.DevicePath), settings) { - //Available Reports, found them by looking at the below methods - //var test = dev.GetRawReportDescriptor(); - //var test2 = dev.GetReportDescriptor(); - - // ID 1; Length 158; INPUT - // ID 2; Length 11; OUTPUT - // ID 3; Length 1025; <-- works FEATURE - // ID 8; Length 1025; <-- works FEATURE - // ID 12; Length 1025; <-- 0xC FEATURE - - private readonly byte[] _rawData = new byte[1025]; - private readonly Sensor[] _rpmSensors = new Sensor[1]; - private readonly HidStream _stream; - private readonly Sensor[] _temperatures = new Sensor[1]; - - public D5Next(HidDevice dev, ISettings settings) : base("D5Next", new Identifier(dev.DevicePath), settings) - { - if (dev.TryOpen(out _stream)) - { - //Reading output report instead of feature report, as the measurements are in the output report - _stream.Read(_rawData); - - Name = "D5Next"; - FirmwareVersion = Convert.ToUInt16(_rawData[14] | (_rawData[13] << 8)); - _temperatures[0] = new Sensor("Water Temperature", 0, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[0]); - - _rpmSensors[0] = new Sensor("Pump", 0, SensorType.Fan, this, Array.Empty(), settings); - ActivateSensor(_rpmSensors[0]); - } - } - - public ushort FirmwareVersion { get; } - - public override HardwareType HardwareType - { - get { return HardwareType.Cooler; } - } - - public override void Close() - { - _stream.Close(); - base.Close(); - } - - public override void Update() + if (dev.TryOpen(out _stream)) { //Reading output report instead of feature report, as the measurements are in the output report _stream.Read(_rawData); - _temperatures[0].Value = (_rawData[88] | (_rawData[87] << 8)) / 100f; //Water Temp - _rpmSensors[0].Value = _rawData[117] | (_rawData[116] << 8); //Pump RPM + + Name = "D5Next"; + FirmwareVersion = Convert.ToUInt16(_rawData[14] | (_rawData[13] << 8)); + _temperatures[0] = new Sensor("Water Temperature", 0, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[0]); + + _rpmSensors[0] = new Sensor("Pump", 0, SensorType.Fan, this, Array.Empty(), settings); + ActivateSensor(_rpmSensors[0]); } } + + public ushort FirmwareVersion { get; } + + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + public override void Close() + { + _stream.Close(); + base.Close(); + } + + public override void Update() + { + //Reading output report instead of feature report, as the measurements are in the output report + _stream.Read(_rawData); + _temperatures[0].Value = (_rawData[88] | (_rawData[87] << 8)) / 100f; //Water Temp + _rpmSensors[0].Value = _rawData[117] | (_rawData[116] << 8); //Pump RPM + } } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/MPS.cs b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/MPS.cs index d97802e..8c30c97 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/MPS.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/MPS.cs @@ -6,101 +6,100 @@ using System; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer +namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer; + +internal sealed class MPS : Hardware { - internal sealed class MPS : Hardware + public const int ExternalTemperature = 43; + public const int InternalWaterTemperature = 45; + public const int PumpFlow = 35; + private const byte MPS_REPORT_ID = 0x2; + + private readonly Sensor _pumpFlow; + private readonly byte[] _rawData = new byte[64]; + private readonly HidStream _stream; + private readonly Sensor[] _temperatures = new Sensor[2]; + + private ushort _externalTemperature; + + public MPS(HidDevice dev, ISettings settings) : base("MPS", new Identifier(dev.DevicePath), settings) { - public const int ExternalTemperature = 43; - public const int InternalWaterTemperature = 45; - public const int PumpFlow = 35; - private const byte MPS_REPORT_ID = 0x2; - - private readonly Sensor _pumpFlow; - private readonly byte[] _rawData = new byte[64]; - private readonly HidStream _stream; - private readonly Sensor[] _temperatures = new Sensor[2]; - - private ushort _externalTemperature; - - public MPS(HidDevice dev, ISettings settings) : base("MPS", new Identifier(dev.DevicePath), settings) + if (dev.TryOpen(out _stream)) { - if (dev.TryOpen(out _stream)) + do { - do - { - _rawData[0] = MPS_REPORT_ID; - _stream.GetFeature(_rawData); - } - while (_rawData[0] != MPS_REPORT_ID); - - Name = "MPS"; - FirmwareVersion = ExtractFirmwareVersion(); - - _temperatures[0] = new Sensor("External", 0, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[0]); - _temperatures[1] = new Sensor("Internal Water", 1, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[1]); - - _pumpFlow = new Sensor("Pump", 0, SensorType.Flow, this, Array.Empty(), settings); - ActivateSensor(_pumpFlow); + _rawData[0] = MPS_REPORT_ID; + _stream.GetFeature(_rawData); } - } + while (_rawData[0] != MPS_REPORT_ID); - public ushort FirmwareVersion { get; private set; } + Name = "MPS"; + FirmwareVersion = ExtractFirmwareVersion(); - public override HardwareType HardwareType - { - get { return HardwareType.Cooler; } - } + _temperatures[0] = new Sensor("External", 0, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[0]); + _temperatures[1] = new Sensor("Internal Water", 1, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[1]); - public string Status - { - get - { - FirmwareVersion = ExtractFirmwareVersion(); - if (FirmwareVersion < 1012) - { - return $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 1012"; - } - - return "Status: OK"; - } - } - - public override void Close() - { - _stream.Close(); - - base.Close(); - } - - public override void Update() - { - _rawData[0] = MPS_REPORT_ID; - _stream.GetFeature(_rawData); - - if (_rawData[0] != MPS_REPORT_ID) - return; - - _pumpFlow.Value = BitConverter.ToUInt16(_rawData, PumpFlow) / 10f; - - _externalTemperature = BitConverter.ToUInt16(_rawData, ExternalTemperature); - //sensor reading returns Int16.MaxValue (32767), when not connected - if (_externalTemperature != short.MaxValue) - { - _temperatures[0].Value = _externalTemperature / 100f; - } - else - { - _temperatures[0].Value = null; - } - - _temperatures[1].Value = BitConverter.ToUInt16(_rawData, InternalWaterTemperature) / 100f; - } - - private ushort ExtractFirmwareVersion() - { - return BitConverter.ToUInt16(_rawData, 3); + _pumpFlow = new Sensor("Pump", 0, SensorType.Flow, this, Array.Empty(), settings); + ActivateSensor(_pumpFlow); } } + + public ushort FirmwareVersion { get; private set; } + + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + public string Status + { + get + { + FirmwareVersion = ExtractFirmwareVersion(); + if (FirmwareVersion < 1012) + { + return $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 1012"; + } + + return "Status: OK"; + } + } + + public override void Close() + { + _stream.Close(); + + base.Close(); + } + + public override void Update() + { + _rawData[0] = MPS_REPORT_ID; + _stream.GetFeature(_rawData); + + if (_rawData[0] != MPS_REPORT_ID) + return; + + _pumpFlow.Value = BitConverter.ToUInt16(_rawData, PumpFlow) / 10f; + + _externalTemperature = BitConverter.ToUInt16(_rawData, ExternalTemperature); + //sensor reading returns Int16.MaxValue (32767), when not connected + if (_externalTemperature != short.MaxValue) + { + _temperatures[0].Value = _externalTemperature / 100f; + } + else + { + _temperatures[0].Value = null; + } + + _temperatures[1].Value = BitConverter.ToUInt16(_rawData, InternalWaterTemperature) / 100f; + } + + private ushort ExtractFirmwareVersion() + { + return BitConverter.ToUInt16(_rawData, 3); + } } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/Octo.cs b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/Octo.cs index 44b2003..5acc104 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/Octo.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/AquaComputer/Octo.cs @@ -6,183 +6,182 @@ using System; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer +namespace LibreHardwareMonitor.Hardware.Controller.AquaComputer; + +internal sealed class Octo : Hardware { - internal sealed class Octo : Hardware + private readonly byte[] _rawData = new byte[1025]; + private readonly Sensor[] _rpmSensors = new Sensor[8]; + private readonly HidStream _stream; + private readonly Sensor[] _temperatures = new Sensor[4]; + private readonly Sensor[] _voltages = new Sensor[9]; + private readonly Sensor[] _currents = new Sensor[8]; + private readonly Sensor[] _powers = new Sensor[8]; + + public Octo(HidDevice dev, ISettings settings) : base("Octo", new Identifier(dev.DevicePath), settings) { - private readonly byte[] _rawData = new byte[1025]; - private readonly Sensor[] _rpmSensors = new Sensor[8]; - private readonly HidStream _stream; - private readonly Sensor[] _temperatures = new Sensor[4]; - private readonly Sensor[] _voltages = new Sensor[9]; - private readonly Sensor[] _currents = new Sensor[8]; - private readonly Sensor[] _powers = new Sensor[8]; - - public Octo(HidDevice dev, ISettings settings) : base("Octo", new Identifier(dev.DevicePath), settings) - { - if (dev.TryOpen(out _stream)) - { - //Reading output report instead of feature report, as the measurements are in the output report - _stream.Read(_rawData); - - Name = "OCTO"; - FirmwareVersion = GetConvertedValue(OctoDataIndexes.FIRMWARE_VERSION).GetValueOrDefault(0); - - // Initialize the 4 temperature sensors - for (int i = 0; i < 4; i++) - { - _temperatures[i] = new Sensor($"Temperature {i+1}", i, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[i]); - } - - // Initialize the 8 fan speed sensors - for (int i = 0; i < 8; i++) - { - _rpmSensors[i] = new Sensor($"Fan {i+1}", i, SensorType.Fan, this, Array.Empty(), settings); - ActivateSensor(_rpmSensors[i]); - } - - // Initialize the input voltage sensor - _voltages[0] = new Sensor("Input", 0, SensorType.Voltage, this, Array.Empty(), settings); - ActivateSensor(_voltages[0]); - - // Initialize the 8 fan voltage sensors - for (int i = 1; i < 9; i++) - { - _voltages[i] = new Sensor($"Fan {i}", i, SensorType.Voltage, this, Array.Empty(), settings); - ActivateSensor(_voltages[i]); - } - - // Initialize the 8 fan current sensors - for (int i = 0; i < 8; i++) - { - _currents[i] = new Sensor($"Fan {i+1}", i, SensorType.Current, this, Array.Empty(), settings); - ActivateSensor(_currents[i]); - } - - // Initialize the 8 fan power sensors - for (int i = 0; i < 8; i++) - { - _powers[i] = new Sensor($"Fan {i+1}", i, SensorType.Power, this, Array.Empty(), settings); - ActivateSensor(_powers[i]); - } - } - } - - public ushort FirmwareVersion { get; } - - public override HardwareType HardwareType - { - get { return HardwareType.Cooler; } - } - - public override void Close() - { - _stream.Close(); - base.Close(); - } - - public override void Update() + if (dev.TryOpen(out _stream)) { //Reading output report instead of feature report, as the measurements are in the output report _stream.Read(_rawData); - - _temperatures[0].Value = GetConvertedValue(OctoDataIndexes.TEMP_1) / 100f; // Temp 1 - _temperatures[1].Value = GetConvertedValue(OctoDataIndexes.TEMP_2) / 100f; // Temp 2 - _temperatures[2].Value = GetConvertedValue(OctoDataIndexes.TEMP_3) / 100f; // Temp 3 - _temperatures[3].Value = GetConvertedValue(OctoDataIndexes.TEMP_4) / 100f; // Temp 4 + + Name = "OCTO"; + FirmwareVersion = GetConvertedValue(OctoDataIndexes.FIRMWARE_VERSION).GetValueOrDefault(0); - _rpmSensors[0].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_1); // Fan 1 speed - _rpmSensors[1].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_2); // Fan 2 speed - _rpmSensors[2].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_3); // Fan 3 speed - _rpmSensors[3].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_4); // Fan 4 speed - _rpmSensors[4].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_5); // Fan 5 speed - _rpmSensors[5].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_6); // Fan 6 speed - _rpmSensors[6].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_7); // Fan 7 speed - _rpmSensors[7].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_8); // Fan 8 speed - - _voltages[0].Value = GetConvertedValue(OctoDataIndexes.VOLTAGE) / 100f; // Input voltage - _voltages[1].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_1) / 100f; // Fan 1 voltage - _voltages[2].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_2) / 100f; // Fan 2 voltage - _voltages[3].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_3) / 100f; // Fan 3 voltage - _voltages[4].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_4) / 100f; // Fan 4 voltage - _voltages[5].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_5) / 100f; // Fan 5 voltage - _voltages[6].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_6) / 100f; // Fan 6 voltage - _voltages[7].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_7) / 100f; // Fan 7 voltage - _voltages[8].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_8) / 100f; // Fan 8 voltage - - _currents[0].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_1) / 1000f; // Fan 1 current - _currents[1].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_2) / 1000f; // Fan 2 current - _currents[2].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_3) / 1000f; // Fan 3 current - _currents[3].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_4) / 1000f; // Fan 4 current - _currents[4].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_5) / 1000f; // Fan 5 current - _currents[5].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_6) / 1000f; // Fan 6 current - _currents[6].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_7) / 1000f; // Fan 7 current - _currents[7].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_8) / 1000f; // Fan 8 current - - _powers[0].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_1) / 100f; // Fan 1 power - _powers[1].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_2) / 100f; // Fan 2 power - _powers[2].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_3) / 100f; // Fan 3 power - _powers[3].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_4) / 100f; // Fan 4 power - _powers[4].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_5) / 100f; // Fan 5 power - _powers[5].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_6) / 100f; // Fan 6 power - _powers[6].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_7) / 100f; // Fan 7 power - _powers[7].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_8) / 100f; // Fan 8 power - } + // Initialize the 4 temperature sensors + for (int i = 0; i < 4; i++) + { + _temperatures[i] = new Sensor($"Temperature {i+1}", i, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[i]); + } - private sealed class OctoDataIndexes - { - public const int FIRMWARE_VERSION = 13; - - public const int TEMP_1 = 61; - public const int TEMP_2 = 63; - public const int TEMP_3 = 65; - public const int TEMP_4 = 67; + // Initialize the 8 fan speed sensors + for (int i = 0; i < 8; i++) + { + _rpmSensors[i] = new Sensor($"Fan {i+1}", i, SensorType.Fan, this, Array.Empty(), settings); + ActivateSensor(_rpmSensors[i]); + } + + // Initialize the input voltage sensor + _voltages[0] = new Sensor("Input", 0, SensorType.Voltage, this, Array.Empty(), settings); + ActivateSensor(_voltages[0]); - public const int FAN_SPEED_1 = 133; - public const int FAN_SPEED_2 = 146; - public const int FAN_SPEED_3 = 159; - public const int FAN_SPEED_4 = 172; - public const int FAN_SPEED_5 = 185; - public const int FAN_SPEED_6 = 198; - public const int FAN_SPEED_7 = 211; - public const int FAN_SPEED_8 = 224; - - public const int FAN_POWER_1 = 131; - public const int FAN_POWER_2 = 144; - public const int FAN_POWER_3 = 157; - public const int FAN_POWER_4 = 170; - public const int FAN_POWER_5 = 183; - public const int FAN_POWER_6 = 196; - public const int FAN_POWER_7 = 209; - public const int FAN_POWER_8 = 222; - - public const int VOLTAGE = 117; - public const int FAN_VOLTAGE_1 = 127; - public const int FAN_VOLTAGE_2 = 140; - public const int FAN_VOLTAGE_3 = 153; - public const int FAN_VOLTAGE_4 = 166; - public const int FAN_VOLTAGE_5 = 179; - public const int FAN_VOLTAGE_6 = 192; - public const int FAN_VOLTAGE_7 = 205; - public const int FAN_VOLTAGE_8 = 218; - - public const int FAN_CURRENT_1 = 129; - public const int FAN_CURRENT_2 = 142; - public const int FAN_CURRENT_3 = 155; - public const int FAN_CURRENT_4 = 168; - public const int FAN_CURRENT_5 = 181; - public const int FAN_CURRENT_6 = 194; - public const int FAN_CURRENT_7 = 207; - public const int FAN_CURRENT_8 = 220; - } - - private ushort? GetConvertedValue(int index) - { - if (_rawData[index] == sbyte.MaxValue) - return null; - - return Convert.ToUInt16(_rawData[index + 1] | (_rawData[index] << 8)); + // Initialize the 8 fan voltage sensors + for (int i = 1; i < 9; i++) + { + _voltages[i] = new Sensor($"Fan {i}", i, SensorType.Voltage, this, Array.Empty(), settings); + ActivateSensor(_voltages[i]); + } + + // Initialize the 8 fan current sensors + for (int i = 0; i < 8; i++) + { + _currents[i] = new Sensor($"Fan {i+1}", i, SensorType.Current, this, Array.Empty(), settings); + ActivateSensor(_currents[i]); + } + + // Initialize the 8 fan power sensors + for (int i = 0; i < 8; i++) + { + _powers[i] = new Sensor($"Fan {i+1}", i, SensorType.Power, this, Array.Empty(), settings); + ActivateSensor(_powers[i]); + } } } -} + + public ushort FirmwareVersion { get; } + + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + public override void Close() + { + _stream.Close(); + base.Close(); + } + + public override void Update() + { + //Reading output report instead of feature report, as the measurements are in the output report + _stream.Read(_rawData); + + _temperatures[0].Value = GetConvertedValue(OctoDataIndexes.TEMP_1) / 100f; // Temp 1 + _temperatures[1].Value = GetConvertedValue(OctoDataIndexes.TEMP_2) / 100f; // Temp 2 + _temperatures[2].Value = GetConvertedValue(OctoDataIndexes.TEMP_3) / 100f; // Temp 3 + _temperatures[3].Value = GetConvertedValue(OctoDataIndexes.TEMP_4) / 100f; // Temp 4 + + _rpmSensors[0].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_1); // Fan 1 speed + _rpmSensors[1].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_2); // Fan 2 speed + _rpmSensors[2].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_3); // Fan 3 speed + _rpmSensors[3].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_4); // Fan 4 speed + _rpmSensors[4].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_5); // Fan 5 speed + _rpmSensors[5].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_6); // Fan 6 speed + _rpmSensors[6].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_7); // Fan 7 speed + _rpmSensors[7].Value = GetConvertedValue(OctoDataIndexes.FAN_SPEED_8); // Fan 8 speed + + _voltages[0].Value = GetConvertedValue(OctoDataIndexes.VOLTAGE) / 100f; // Input voltage + _voltages[1].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_1) / 100f; // Fan 1 voltage + _voltages[2].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_2) / 100f; // Fan 2 voltage + _voltages[3].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_3) / 100f; // Fan 3 voltage + _voltages[4].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_4) / 100f; // Fan 4 voltage + _voltages[5].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_5) / 100f; // Fan 5 voltage + _voltages[6].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_6) / 100f; // Fan 6 voltage + _voltages[7].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_7) / 100f; // Fan 7 voltage + _voltages[8].Value = GetConvertedValue(OctoDataIndexes.FAN_VOLTAGE_8) / 100f; // Fan 8 voltage + + _currents[0].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_1) / 1000f; // Fan 1 current + _currents[1].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_2) / 1000f; // Fan 2 current + _currents[2].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_3) / 1000f; // Fan 3 current + _currents[3].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_4) / 1000f; // Fan 4 current + _currents[4].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_5) / 1000f; // Fan 5 current + _currents[5].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_6) / 1000f; // Fan 6 current + _currents[6].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_7) / 1000f; // Fan 7 current + _currents[7].Value = GetConvertedValue(OctoDataIndexes.FAN_CURRENT_8) / 1000f; // Fan 8 current + + _powers[0].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_1) / 100f; // Fan 1 power + _powers[1].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_2) / 100f; // Fan 2 power + _powers[2].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_3) / 100f; // Fan 3 power + _powers[3].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_4) / 100f; // Fan 4 power + _powers[4].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_5) / 100f; // Fan 5 power + _powers[5].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_6) / 100f; // Fan 6 power + _powers[6].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_7) / 100f; // Fan 7 power + _powers[7].Value = GetConvertedValue(OctoDataIndexes.FAN_POWER_8) / 100f; // Fan 8 power + } + + private sealed class OctoDataIndexes + { + public const int FIRMWARE_VERSION = 13; + + public const int TEMP_1 = 61; + public const int TEMP_2 = 63; + public const int TEMP_3 = 65; + public const int TEMP_4 = 67; + + public const int FAN_SPEED_1 = 133; + public const int FAN_SPEED_2 = 146; + public const int FAN_SPEED_3 = 159; + public const int FAN_SPEED_4 = 172; + public const int FAN_SPEED_5 = 185; + public const int FAN_SPEED_6 = 198; + public const int FAN_SPEED_7 = 211; + public const int FAN_SPEED_8 = 224; + + public const int FAN_POWER_1 = 131; + public const int FAN_POWER_2 = 144; + public const int FAN_POWER_3 = 157; + public const int FAN_POWER_4 = 170; + public const int FAN_POWER_5 = 183; + public const int FAN_POWER_6 = 196; + public const int FAN_POWER_7 = 209; + public const int FAN_POWER_8 = 222; + + public const int VOLTAGE = 117; + public const int FAN_VOLTAGE_1 = 127; + public const int FAN_VOLTAGE_2 = 140; + public const int FAN_VOLTAGE_3 = 153; + public const int FAN_VOLTAGE_4 = 166; + public const int FAN_VOLTAGE_5 = 179; + public const int FAN_VOLTAGE_6 = 192; + public const int FAN_VOLTAGE_7 = 205; + public const int FAN_VOLTAGE_8 = 218; + + public const int FAN_CURRENT_1 = 129; + public const int FAN_CURRENT_2 = 142; + public const int FAN_CURRENT_3 = 155; + public const int FAN_CURRENT_4 = 168; + public const int FAN_CURRENT_5 = 181; + public const int FAN_CURRENT_6 = 194; + public const int FAN_CURRENT_7 = 207; + public const int FAN_CURRENT_8 = 220; + } + + private ushort? GetConvertedValue(int index) + { + if (_rawData[index] == sbyte.MaxValue) + return null; + + return Convert.ToUInt16(_rawData[index + 1] | (_rawData[index] << 8)); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/Heatmaster.cs b/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/Heatmaster.cs index 38da2fe..e4ce0a9 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/Heatmaster.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/Heatmaster.cs @@ -12,280 +12,279 @@ using System.Text; using System.Text.RegularExpressions; using System.Threading; -namespace LibreHardwareMonitor.Hardware.Controller.Heatmaster +namespace LibreHardwareMonitor.Hardware.Controller.Heatmaster; + +internal sealed class Heatmaster : Hardware, IDisposable { - internal sealed class Heatmaster : Hardware, IDisposable + private readonly bool _available; + private readonly StringBuilder _buffer = new(); + private readonly Sensor[] _controls; + private readonly Sensor[] _fans; + private readonly int _firmwareCrc; + private readonly int _firmwareRevision; + private readonly Sensor[] _flows; + private readonly int _hardwareRevision; + private readonly string _portName; + private readonly Sensor[] _relays; + private readonly Sensor[] _temperatures; + private SerialPort _serialPort; + + public Heatmaster(string portName, ISettings settings) : base("Heatmaster", new Identifier("heatmaster", portName.TrimStart('/').ToLowerInvariant()), settings) { - private readonly bool _available; - private readonly StringBuilder _buffer = new(); - private readonly Sensor[] _controls; - private readonly Sensor[] _fans; - private readonly int _firmwareCrc; - private readonly int _firmwareRevision; - private readonly Sensor[] _flows; - private readonly int _hardwareRevision; - private readonly string _portName; - private readonly Sensor[] _relays; - private readonly Sensor[] _temperatures; - private SerialPort _serialPort; - - public Heatmaster(string portName, ISettings settings) : base("Heatmaster", new Identifier("heatmaster", portName.TrimStart('/').ToLowerInvariant()), settings) + _portName = portName; + try { - _portName = portName; - try + _serialPort = new SerialPort(portName, 38400, Parity.None, 8, StopBits.One); + _serialPort.Open(); + _serialPort.NewLine = ((char)0x0D).ToString(); + + _hardwareRevision = ReadInteger(0, 'H'); + _firmwareRevision = ReadInteger(0, 'V'); + _firmwareCrc = ReadInteger(0, 'C'); + + int fanCount = Math.Min(ReadInteger(32, '?'), 4); + int temperatureCount = Math.Min(ReadInteger(48, '?'), 6); + int flowCount = Math.Min(ReadInteger(64, '?'), 1); + int relayCount = Math.Min(ReadInteger(80, '?'), 1); + + _fans = new Sensor[fanCount]; + _controls = new Sensor[fanCount]; + for (int i = 0; i < fanCount; i++) { - _serialPort = new SerialPort(portName, 38400, Parity.None, 8, StopBits.One); - _serialPort.Open(); - _serialPort.NewLine = ((char)0x0D).ToString(); - - _hardwareRevision = ReadInteger(0, 'H'); - _firmwareRevision = ReadInteger(0, 'V'); - _firmwareCrc = ReadInteger(0, 'C'); - - int fanCount = Math.Min(ReadInteger(32, '?'), 4); - int temperatureCount = Math.Min(ReadInteger(48, '?'), 6); - int flowCount = Math.Min(ReadInteger(64, '?'), 1); - int relayCount = Math.Min(ReadInteger(80, '?'), 1); - - _fans = new Sensor[fanCount]; - _controls = new Sensor[fanCount]; - for (int i = 0; i < fanCount; i++) - { - int device = 33 + i; - string name = ReadString(device, 'C'); - _fans[i] = new Sensor(name, device, SensorType.Fan, this, settings) { Value = ReadInteger(device, 'R') }; - ActivateSensor(_fans[i]); - _controls[i] = new Sensor(name, device, SensorType.Control, this, settings) { Value = (100 / 255.0f) * ReadInteger(device, 'P') }; - ActivateSensor(_controls[i]); - } - - _temperatures = new Sensor[temperatureCount]; - for (int i = 0; i < temperatureCount; i++) - { - int device = 49 + i; - string name = ReadString(device, 'C'); - _temperatures[i] = new Sensor(name, device, SensorType.Temperature, this, settings); - int value = ReadInteger(device, 'T'); - _temperatures[i].Value = 0.1f * value; - if (value != -32768) - ActivateSensor(_temperatures[i]); - } - - _flows = new Sensor[flowCount]; - for (int i = 0; i < flowCount; i++) - { - int device = 65 + i; - string name = ReadString(device, 'C'); - _flows[i] = new Sensor(name, device, SensorType.Flow, this, settings) { Value = 0.1f * ReadInteger(device, 'L') }; - ActivateSensor(_flows[i]); - } - - _relays = new Sensor[relayCount]; - for (int i = 0; i < relayCount; i++) - { - int device = 81 + i; - string name = ReadString(device, 'C'); - _relays[i] = new Sensor(name, device, SensorType.Control, this, settings) - { - Value = 100 * ReadInteger(device, 'S') - }; - ActivateSensor(_relays[i]); - } - - // set the update rate to 2 Hz - WriteInteger(0, 'L', 2); - _available = true; - } - catch (IOException) - { } - catch (TimeoutException) - { } - } - - public override HardwareType HardwareType - { - get { return HardwareType.Cooler; } - } - - public void Dispose() - { - if (_serialPort != null) - { - _serialPort.Dispose(); - _serialPort = null; - } - } - - private string ReadLine(int timeout) - { - int i = 0; - StringBuilder builder = new(); - while (i <= timeout) - { - while (_serialPort.BytesToRead > 0) - { - byte b = (byte)_serialPort.ReadByte(); - switch (b) - { - case 0xAA: return ((char)b).ToString(); - case 0x0D: return builder.ToString(); - default: - builder.Append((char)b); - break; - } - } - - i++; - Thread.Sleep(1); + int device = 33 + i; + string name = ReadString(device, 'C'); + _fans[i] = new Sensor(name, device, SensorType.Fan, this, settings) { Value = ReadInteger(device, 'R') }; + ActivateSensor(_fans[i]); + _controls[i] = new Sensor(name, device, SensorType.Control, this, settings) { Value = (100 / 255.0f) * ReadInteger(device, 'P') }; + ActivateSensor(_controls[i]); } - throw new TimeoutException(); - } - - private string ReadField(int device, char field) - { - _serialPort.WriteLine("[0:" + device + "]R" + field); - for (int i = 0; i < 5; i++) + _temperatures = new Sensor[temperatureCount]; + for (int i = 0; i < temperatureCount; i++) { - string s = ReadLine(200); - Match match = Regex.Match(s, @"-\[0:" + device.ToString(CultureInfo.InvariantCulture) + @"\]R" + Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) + ":(.*)"); - if (match.Success) - return match.Groups[1].Value; + int device = 49 + i; + string name = ReadString(device, 'C'); + _temperatures[i] = new Sensor(name, device, SensorType.Temperature, this, settings); + int value = ReadInteger(device, 'T'); + _temperatures[i].Value = 0.1f * value; + if (value != -32768) + ActivateSensor(_temperatures[i]); } - return null; - } - - private string ReadString(int device, char field) - { - string s = ReadField(device, field); - if (s?[0] == '"' && s[s.Length - 1] == '"') - return s.Substring(1, s.Length - 2); - - return null; - } - - private int ReadInteger(int device, char field) - { - string s = ReadField(device, field); - if (int.TryParse(s, out int i)) - return i; - - return 0; - } - - private void WriteField(int device, char field, string value) - { - _serialPort.WriteLine("[0:" + device + "]W" + field + ":" + value); - for (int i = 0; i < 5; i++) + _flows = new Sensor[flowCount]; + for (int i = 0; i < flowCount; i++) { - string s = ReadLine(200); - Match match = Regex.Match(s, @"-\[0:" + device.ToString(CultureInfo.InvariantCulture) + @"\]W" + Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) + ":" + value); - if (match.Success) - return; + int device = 65 + i; + string name = ReadString(device, 'C'); + _flows[i] = new Sensor(name, device, SensorType.Flow, this, settings) { Value = 0.1f * ReadInteger(device, 'L') }; + ActivateSensor(_flows[i]); } - } - private void WriteInteger(int device, char field, int value) - { - WriteField(device, field, value.ToString(CultureInfo.InvariantCulture)); - } - - private void ProcessUpdateLine(string line) - { - Match match = Regex.Match(line, @">\[0:(\d+)\]([0-9:\|-]+)"); - if (match.Success && int.TryParse(match.Groups[1].Value, out int device)) + _relays = new Sensor[relayCount]; + for (int i = 0; i < relayCount; i++) { - foreach (string s in match.Groups[2].Value.Split('|')) + int device = 81 + i; + string name = ReadString(device, 'C'); + _relays[i] = new Sensor(name, device, SensorType.Control, this, settings) { - string[] strings = s.Split(':'); - int[] ints = new int[strings.Length]; - bool valid = true; - for (int i = 0; i < ints.Length; i++) - { - if (!int.TryParse(strings[i], out ints[i])) - { - valid = false; - break; - } - } - - if (!valid) - continue; - - switch (device) - { - case 32: - if (ints.Length == 3 && ints[0] <= _fans.Length) - { - _fans[ints[0] - 1].Value = ints[1]; - _controls[ints[0] - 1].Value = (100 / 255.0f) * ints[2]; - } - - break; - case 48: - if (ints.Length == 2 && ints[0] <= _temperatures.Length) - _temperatures[ints[0] - 1].Value = 0.1f * ints[1]; - - break; - case 64: - if (ints.Length == 3 && ints[0] <= _flows.Length) - _flows[ints[0] - 1].Value = 0.1f * ints[1]; - - break; - case 80: - if (ints.Length == 2 && ints[0] <= _relays.Length) - _relays[ints[0] - 1].Value = 100 * ints[1]; - - break; - } - } + Value = 100 * ReadInteger(device, 'S') + }; + ActivateSensor(_relays[i]); } + + // set the update rate to 2 Hz + WriteInteger(0, 'L', 2); + _available = true; } + catch (IOException) + { } + catch (TimeoutException) + { } + } - public override void Update() + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + public void Dispose() + { + if (_serialPort != null) { - if (!_available) - return; - - while (_serialPort.IsOpen && _serialPort.BytesToRead > 0) - { - byte b = (byte)_serialPort.ReadByte(); - if (b == 0x0D) - { - ProcessUpdateLine(_buffer.ToString()); - _buffer.Length = 0; - } - else - { - _buffer.Append((char)b); - } - } - } - - public override string GetReport() - { - StringBuilder r = new(); - r.AppendLine("Heatmaster"); - r.AppendLine(); - r.Append("Port: "); - r.AppendLine(_portName); - r.Append("Hardware Revision: "); - r.AppendLine(_hardwareRevision.ToString(CultureInfo.InvariantCulture)); - r.Append("Firmware Revision: "); - r.AppendLine(_firmwareRevision.ToString(CultureInfo.InvariantCulture)); - r.Append("Firmware CRC: "); - r.AppendLine(_firmwareCrc.ToString(CultureInfo.InvariantCulture)); - r.AppendLine(); - return r.ToString(); - } - - public override void Close() - { - _serialPort.Close(); _serialPort.Dispose(); _serialPort = null; - base.Close(); } } + + private string ReadLine(int timeout) + { + int i = 0; + StringBuilder builder = new(); + while (i <= timeout) + { + while (_serialPort.BytesToRead > 0) + { + byte b = (byte)_serialPort.ReadByte(); + switch (b) + { + case 0xAA: return ((char)b).ToString(); + case 0x0D: return builder.ToString(); + default: + builder.Append((char)b); + break; + } + } + + i++; + Thread.Sleep(1); + } + + throw new TimeoutException(); + } + + private string ReadField(int device, char field) + { + _serialPort.WriteLine("[0:" + device + "]R" + field); + for (int i = 0; i < 5; i++) + { + string s = ReadLine(200); + Match match = Regex.Match(s, @"-\[0:" + device.ToString(CultureInfo.InvariantCulture) + @"\]R" + Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) + ":(.*)"); + if (match.Success) + return match.Groups[1].Value; + } + + return null; + } + + private string ReadString(int device, char field) + { + string s = ReadField(device, field); + if (s?[0] == '"' && s[s.Length - 1] == '"') + return s.Substring(1, s.Length - 2); + + return null; + } + + private int ReadInteger(int device, char field) + { + string s = ReadField(device, field); + if (int.TryParse(s, out int i)) + return i; + + return 0; + } + + private void WriteField(int device, char field, string value) + { + _serialPort.WriteLine("[0:" + device + "]W" + field + ":" + value); + for (int i = 0; i < 5; i++) + { + string s = ReadLine(200); + Match match = Regex.Match(s, @"-\[0:" + device.ToString(CultureInfo.InvariantCulture) + @"\]W" + Regex.Escape(field.ToString(CultureInfo.InvariantCulture)) + ":" + value); + if (match.Success) + return; + } + } + + private void WriteInteger(int device, char field, int value) + { + WriteField(device, field, value.ToString(CultureInfo.InvariantCulture)); + } + + private void ProcessUpdateLine(string line) + { + Match match = Regex.Match(line, @">\[0:(\d+)\]([0-9:\|-]+)"); + if (match.Success && int.TryParse(match.Groups[1].Value, out int device)) + { + foreach (string s in match.Groups[2].Value.Split('|')) + { + string[] strings = s.Split(':'); + int[] ints = new int[strings.Length]; + bool valid = true; + for (int i = 0; i < ints.Length; i++) + { + if (!int.TryParse(strings[i], out ints[i])) + { + valid = false; + break; + } + } + + if (!valid) + continue; + + switch (device) + { + case 32: + if (ints.Length == 3 && ints[0] <= _fans.Length) + { + _fans[ints[0] - 1].Value = ints[1]; + _controls[ints[0] - 1].Value = (100 / 255.0f) * ints[2]; + } + + break; + case 48: + if (ints.Length == 2 && ints[0] <= _temperatures.Length) + _temperatures[ints[0] - 1].Value = 0.1f * ints[1]; + + break; + case 64: + if (ints.Length == 3 && ints[0] <= _flows.Length) + _flows[ints[0] - 1].Value = 0.1f * ints[1]; + + break; + case 80: + if (ints.Length == 2 && ints[0] <= _relays.Length) + _relays[ints[0] - 1].Value = 100 * ints[1]; + + break; + } + } + } + } + + public override void Update() + { + if (!_available) + return; + + while (_serialPort.IsOpen && _serialPort.BytesToRead > 0) + { + byte b = (byte)_serialPort.ReadByte(); + if (b == 0x0D) + { + ProcessUpdateLine(_buffer.ToString()); + _buffer.Length = 0; + } + else + { + _buffer.Append((char)b); + } + } + } + + public override string GetReport() + { + StringBuilder r = new(); + r.AppendLine("Heatmaster"); + r.AppendLine(); + r.Append("Port: "); + r.AppendLine(_portName); + r.Append("Hardware Revision: "); + r.AppendLine(_hardwareRevision.ToString(CultureInfo.InvariantCulture)); + r.Append("Firmware Revision: "); + r.AppendLine(_firmwareRevision.ToString(CultureInfo.InvariantCulture)); + r.Append("Firmware CRC: "); + r.AppendLine(_firmwareCrc.ToString(CultureInfo.InvariantCulture)); + r.AppendLine(); + return r.ToString(); + } + + public override void Close() + { + _serialPort.Close(); + _serialPort.Dispose(); + _serialPort = null; + base.Close(); + } } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs index 1447e46..0ba119d 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/Heatmaster/HeatmasterGroup.cs @@ -13,194 +13,193 @@ using System.Text; using System.Threading; using Microsoft.Win32; -namespace LibreHardwareMonitor.Hardware.Controller.Heatmaster +namespace LibreHardwareMonitor.Hardware.Controller.Heatmaster; + +internal class HeatmasterGroup : IGroup { - internal class HeatmasterGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public HeatmasterGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); + // No implementation for Heatmaster on Unix systems + if (Software.OperatingSystem.IsUnix) + return; - public HeatmasterGroup(ISettings settings) + string[] portNames = GetRegistryPortNames(); + for (int i = 0; i < portNames.Length; i++) { - // No implementation for Heatmaster on Unix systems - if (Software.OperatingSystem.IsUnix) - return; - - string[] portNames = GetRegistryPortNames(); - for (int i = 0; i < portNames.Length; i++) + bool isValid = false; + try { - bool isValid = false; + using SerialPort serialPort = new(portNames[i], 38400, Parity.None, 8, StopBits.One); + serialPort.NewLine = ((char)0x0D).ToString(); + _report.Append("Port Name: "); + _report.AppendLine(portNames[i]); try { - using SerialPort serialPort = new(portNames[i], 38400, Parity.None, 8, StopBits.One); - serialPort.NewLine = ((char)0x0D).ToString(); - _report.Append("Port Name: "); - _report.AppendLine(portNames[i]); - try + serialPort.Open(); + } + catch (UnauthorizedAccessException) + { + _report.AppendLine("Exception: Access Denied"); + } + + if (serialPort.IsOpen) + { + serialPort.DiscardInBuffer(); + serialPort.DiscardOutBuffer(); + serialPort.Write(new byte[] { 0xAA }, 0, 1); + + int j = 0; + while (serialPort.BytesToRead == 0 && j < 10) { - serialPort.Open(); - } - catch (UnauthorizedAccessException) - { - _report.AppendLine("Exception: Access Denied"); + Thread.Sleep(20); + j++; } - if (serialPort.IsOpen) + if (serialPort.BytesToRead > 0) { - serialPort.DiscardInBuffer(); - serialPort.DiscardOutBuffer(); - serialPort.Write(new byte[] { 0xAA }, 0, 1); - - int j = 0; - while (serialPort.BytesToRead == 0 && j < 10) + bool flag = false; + while (serialPort.BytesToRead > 0 && !flag) { - Thread.Sleep(20); - j++; + flag |= serialPort.ReadByte() == 0xAA; } - if (serialPort.BytesToRead > 0) + if (flag) { - bool flag = false; - while (serialPort.BytesToRead > 0 && !flag) + serialPort.WriteLine("[0:0]RH"); + try { - flag |= serialPort.ReadByte() == 0xAA; - } - - if (flag) - { - serialPort.WriteLine("[0:0]RH"); - try + int k = 0; + int revision = 0; + while (k < 5) { - int k = 0; - int revision = 0; - while (k < 5) + string line = ReadLine(serialPort, 100); + if (line.StartsWith("-[0:0]RH:", StringComparison.Ordinal)) { - string line = ReadLine(serialPort, 100); - if (line.StartsWith("-[0:0]RH:", StringComparison.Ordinal)) - { - revision = int.Parse(line.Substring(9), CultureInfo.InvariantCulture); - break; - } - - k++; + revision = int.Parse(line.Substring(9), CultureInfo.InvariantCulture); + break; } - isValid = revision == 770; - if (!isValid) - { - _report.Append("Status: Wrong Hardware Revision " + revision.ToString(CultureInfo.InvariantCulture)); - } + k++; } - catch (TimeoutException) + + isValid = revision == 770; + if (!isValid) { - _report.AppendLine("Status: Timeout Reading Revision"); + _report.Append("Status: Wrong Hardware Revision " + revision.ToString(CultureInfo.InvariantCulture)); } } - else + catch (TimeoutException) { - _report.AppendLine("Status: Wrong Startflag"); + _report.AppendLine("Status: Timeout Reading Revision"); } } else { - _report.AppendLine("Status: No Response"); + _report.AppendLine("Status: Wrong Startflag"); } - - serialPort.DiscardInBuffer(); } else { - _report.AppendLine("Status: Port not Open"); + _report.AppendLine("Status: No Response"); } - } - catch (Exception e) - { - _report.AppendLine(e.ToString()); - } - if (isValid) - { - _report.AppendLine("Status: OK"); - _hardware.Add(new Heatmaster(portNames[i], settings)); + serialPort.DiscardInBuffer(); + } + else + { + _report.AppendLine("Status: Port not Open"); } - - _report.AppendLine(); } - } - - public IReadOnlyList Hardware => _hardware; - - public string GetReport() - { - if (_report.Length > 0) + catch (Exception e) { - StringBuilder r = new(); - r.AppendLine("Serial Port Heatmaster"); - r.AppendLine(); - r.Append(_report); - r.AppendLine(); - return r.ToString(); + _report.AppendLine(e.ToString()); } - return null; - } - - public void Close() - { - foreach (Heatmaster heatmaster in _hardware) - heatmaster.Close(); - } - - private static string ReadLine(SerialPort port, int timeout) - { - int i = 0; - StringBuilder builder = new(); - while (i < timeout) + if (isValid) { - while (port.BytesToRead > 0) - { - byte b = (byte)port.ReadByte(); - switch (b) - { - case 0xAA: return ((char)b).ToString(); - case 0x0D: return builder.ToString(); - default: - builder.Append((char)b); - break; - } - } - - i++; - Thread.Sleep(1); + _report.AppendLine("Status: OK"); + _hardware.Add(new Heatmaster(portNames[i], settings)); } - throw new TimeoutException(); - } - - private static string[] GetRegistryPortNames() - { - List result = new(); - string[] paths = { string.Empty, "&MI_00" }; - try - { - foreach (string path in paths) - { - RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\USB\VID_10C4&PID_EA60" + path); - if (key != null) - { - foreach (string subKeyName in key.GetSubKeyNames()) - { - RegistryKey subKey = key.OpenSubKey(subKeyName + "\\" + "Device Parameters"); - if (subKey?.GetValue("PortName") is string name && !result.Contains(name)) - result.Add(name); - } - } - } - } - catch (SecurityException) - { } - - return result.ToArray(); + _report.AppendLine(); } } + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + if (_report.Length > 0) + { + StringBuilder r = new(); + r.AppendLine("Serial Port Heatmaster"); + r.AppendLine(); + r.Append(_report); + r.AppendLine(); + return r.ToString(); + } + + return null; + } + + public void Close() + { + foreach (Heatmaster heatmaster in _hardware) + heatmaster.Close(); + } + + private static string ReadLine(SerialPort port, int timeout) + { + int i = 0; + StringBuilder builder = new(); + while (i < timeout) + { + while (port.BytesToRead > 0) + { + byte b = (byte)port.ReadByte(); + switch (b) + { + case 0xAA: return ((char)b).ToString(); + case 0x0D: return builder.ToString(); + default: + builder.Append((char)b); + break; + } + } + + i++; + Thread.Sleep(1); + } + + throw new TimeoutException(); + } + + private static string[] GetRegistryPortNames() + { + List result = new(); + string[] paths = { string.Empty, "&MI_00" }; + try + { + foreach (string path in paths) + { + RegistryKey key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\CurrentControlSet\Enum\USB\VID_10C4&PID_EA60" + path); + if (key != null) + { + foreach (string subKeyName in key.GetSubKeyNames()) + { + RegistryKey subKey = key.OpenSubKey(subKeyName + "\\" + "Device Parameters"); + if (subKey?.GetValue("PortName") is string name && !result.Contains(name)) + result.Add(name); + } + } + } + } + catch (SecurityException) + { } + + return result.ToArray(); + } } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/GridV3.cs b/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/GridV3.cs index 7281322..127a944 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/GridV3.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/GridV3.cs @@ -8,177 +8,176 @@ using System.Collections.Generic; using System.Threading; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.Nzxt +namespace LibreHardwareMonitor.Hardware.Controller.Nzxt; + +/// +/// Support for the NZXT GRID+ V3 devices. +/// +internal sealed class GridV3 : Hardware { - /// - /// Support for the NZXT GRID+ V3 devices. - /// - internal sealed class GridV3 : Hardware + // Some initialization messages to send to the controller. No visible effects but NZXT CAM send them. + private static readonly byte[] _initialize1 = { 0x01, 0x5c }; + private static readonly byte[] _initialize2 = { 0x01, 0x5d }; + private static readonly byte[] _initialize3 = { 0x01, 0x59 }; + + private const int FANS_COUNT = 6; + + private readonly byte[] _setFanSpeedMsg; + private readonly HidStream _stream; + private readonly Dictionary _rawData = new(); + + private readonly Sensor _noise; + private readonly Sensor[] _currents = new Sensor[FANS_COUNT]; + private readonly Sensor[] _powers = new Sensor[FANS_COUNT]; + private readonly Sensor[] _pwmControls = new Sensor[FANS_COUNT]; + private readonly Sensor[] _rpmSensors = new Sensor[FANS_COUNT]; + private readonly Sensor[] _voltages = new Sensor[FANS_COUNT]; + + private readonly Control[] _fanControls = new Control[FANS_COUNT]; + + public GridV3(HidDevice dev, ISettings settings) : base("NZXT GRID+ V3", new Identifier("nzxt", "gridv3", dev.GetSerialNumber().TrimStart('0')), settings) { - // Some initialization messages to send to the controller. No visible effects but NZXT CAM send them. - private static readonly byte[] _initialize1 = { 0x01, 0x5c }; - private static readonly byte[] _initialize2 = { 0x01, 0x5d }; - private static readonly byte[] _initialize3 = { 0x01, 0x59 }; - - private const int FANS_COUNT = 6; - - private readonly byte[] _setFanSpeedMsg; - private readonly HidStream _stream; - private readonly Dictionary _rawData = new(); - - private readonly Sensor _noise; - private readonly Sensor[] _currents = new Sensor[FANS_COUNT]; - private readonly Sensor[] _powers = new Sensor[FANS_COUNT]; - private readonly Sensor[] _pwmControls = new Sensor[FANS_COUNT]; - private readonly Sensor[] _rpmSensors = new Sensor[FANS_COUNT]; - private readonly Sensor[] _voltages = new Sensor[FANS_COUNT]; - - private readonly Control[] _fanControls = new Control[FANS_COUNT]; - - public GridV3(HidDevice dev, ISettings settings) : base("NZXT GRID+ V3", new Identifier("nzxt", "gridv3", dev.GetSerialNumber().TrimStart('0')), settings) + if (dev.TryOpen(out _stream)) { - if (dev.TryOpen(out _stream)) + for (int fanID = 0; fanID < FANS_COUNT; fanID++) { - for (int fanID = 0; fanID < FANS_COUNT; fanID++) + _rawData[fanID] = new byte[21]; + } + + _setFanSpeedMsg = new byte[65]; + _setFanSpeedMsg[0] = 0x02; + _setFanSpeedMsg[1] = 0x4d; + _setFanSpeedMsg[3] = 0x00; + + _stream.Write(_initialize1); + _stream.Write(_initialize2); + _stream.Write(_initialize3); + + do + { + _stream.Read(_rawData[0]); + if (_rawData[0][0] == 0x04) { - _rawData[fanID] = new byte[21]; + FirmwareVersion = $"{_rawData[0][11]}.{_rawData[0][14]}"; } + } + while (FirmwareVersion == null); - _setFanSpeedMsg = new byte[65]; - _setFanSpeedMsg[0] = 0x02; - _setFanSpeedMsg[1] = 0x4d; - _setFanSpeedMsg[3] = 0x00; + Name = "NZXT GRID+ V3"; - _stream.Write(_initialize1); - _stream.Write(_initialize2); - _stream.Write(_initialize3); + // Initialize all sensors and controls for all fans + for (int i = 0; i < FANS_COUNT; i++) + { + _rpmSensors[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Fan, this, Array.Empty(), settings); + _voltages[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Voltage, this, Array.Empty(), settings); + _currents[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Current, this, Array.Empty(), settings); + _powers[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Power, this, Array.Empty(), settings); + _pwmControls[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Control, this, Array.Empty(), settings); - do + _fanControls[i] = new Control(_pwmControls[i], settings, 0, 100); + + _pwmControls[i].Control = _fanControls[i]; + _fanControls[i].ControlModeChanged += SoftwareControlValueChanged; + _fanControls[i].SoftwareControlValueChanged += SoftwareControlValueChanged; + SoftwareControlValueChanged(_fanControls[i]); + + ActivateSensor(_rpmSensors[i]); + ActivateSensor(_voltages[i]); + ActivateSensor(_currents[i]); + ActivateSensor(_powers[i]); + ActivateSensor(_pwmControls[i]); + + // NZXT GRID does not report current PWM value. So we need to initialize it with some value to keep GUI and device values in sync. + _fanControls[i].SetDefault(); + } + _noise = new Sensor("GRID Noise", 0, SensorType.Noise, this, Array.Empty(), settings); + ActivateSensor(_noise); + + Thread readGridReports = new(ContinuousRead) { IsBackground = true }; + readGridReports.Start(_rawData); + } + } + + public string FirmwareVersion { get; } + + public override HardwareType HardwareType => HardwareType.Cooler; + + private void SoftwareControlValueChanged(Control control) + { + if (control.ControlMode == ControlMode.Software) + { + float value = control.SoftwareValue; + byte fanSpeed = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail + + //_controlling = true; + _setFanSpeedMsg[2] = (byte)control.Sensor.Index; + _setFanSpeedMsg[4] = fanSpeed; + + _stream.Write(_setFanSpeedMsg); + + _pwmControls[control.Sensor.Index].Value = value; + } + else if (control.ControlMode == ControlMode.Default) + { + // There isn't a "default" mode, but let's say a safe setting is 40% + _setFanSpeedMsg[2] = (byte)control.Sensor.Index; + _setFanSpeedMsg[4] = 40; + + _stream.Write(_setFanSpeedMsg); + + _pwmControls[control.Sensor.Index].Value = 40; + } + } + + public override void Close() + { + _stream?.Close(); + base.Close(); + } + + private void ContinuousRead(object state) + { + byte[] buffer = new byte[_rawData[0].Length]; + while (_stream.CanRead) + { + try + { + _stream.Read(buffer); // This is a blocking call, will wait for bytes to become available + if (buffer[0] == 0x04) { - _stream.Read(_rawData[0]); - if (_rawData[0][0] == 0x04) + lock (_rawData) { - FirmwareVersion = $"{_rawData[0][11]}.{_rawData[0][14]}"; + int fanID = (buffer[15] >> 4) & 0x0f; + Array.Copy(buffer, _rawData[fanID], buffer.Length); } } - while (FirmwareVersion == null); - - Name = "NZXT GRID+ V3"; - - // Initialize all sensors and controls for all fans - for (int i = 0; i < FANS_COUNT; i++) - { - _rpmSensors[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Fan, this, Array.Empty(), settings); - _voltages[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Voltage, this, Array.Empty(), settings); - _currents[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Current, this, Array.Empty(), settings); - _powers[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Power, this, Array.Empty(), settings); - _pwmControls[i] = new Sensor($"GRID Fan #{i + 1}", i, SensorType.Control, this, Array.Empty(), settings); - - _fanControls[i] = new Control(_pwmControls[i], settings, 0, 100); - - _pwmControls[i].Control = _fanControls[i]; - _fanControls[i].ControlModeChanged += SoftwareControlValueChanged; - _fanControls[i].SoftwareControlValueChanged += SoftwareControlValueChanged; - SoftwareControlValueChanged(_fanControls[i]); - - ActivateSensor(_rpmSensors[i]); - ActivateSensor(_voltages[i]); - ActivateSensor(_currents[i]); - ActivateSensor(_powers[i]); - ActivateSensor(_pwmControls[i]); - - // NZXT GRID does not report current PWM value. So we need to initialize it with some value to keep GUI and device values in sync. - _fanControls[i].SetDefault(); - } - _noise = new Sensor("GRID Noise", 0, SensorType.Noise, this, Array.Empty(), settings); - ActivateSensor(_noise); - - Thread readGridReports = new(ContinuousRead) { IsBackground = true }; - readGridReports.Start(_rawData); } - } - - public string FirmwareVersion { get; } - - public override HardwareType HardwareType => HardwareType.Cooler; - - private void SoftwareControlValueChanged(Control control) - { - if (control.ControlMode == ControlMode.Software) + catch (TimeoutException) { - float value = control.SoftwareValue; - byte fanSpeed = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail - - //_controlling = true; - _setFanSpeedMsg[2] = (byte)control.Sensor.Index; - _setFanSpeedMsg[4] = fanSpeed; - - _stream.Write(_setFanSpeedMsg); - - _pwmControls[control.Sensor.Index].Value = value; + // Don't care, just make sure the stream is still open + Thread.Sleep(500); } - else if (control.ControlMode == ControlMode.Default) + catch (ObjectDisposedException) { - // There isn't a "default" mode, but let's say a safe setting is 40% - _setFanSpeedMsg[2] = (byte)control.Sensor.Index; - _setFanSpeedMsg[4] = 40; - - _stream.Write(_setFanSpeedMsg); - - _pwmControls[control.Sensor.Index].Value = 40; - } - } - - public override void Close() - { - _stream?.Close(); - base.Close(); - } - - private void ContinuousRead(object state) - { - byte[] buffer = new byte[_rawData[0].Length]; - while (_stream.CanRead) - { - try - { - _stream.Read(buffer); // This is a blocking call, will wait for bytes to become available - if (buffer[0] == 0x04) - { - lock (_rawData) - { - int fanID = (buffer[15] >> 4) & 0x0f; - Array.Copy(buffer, _rawData[fanID], buffer.Length); - } - } - } - catch (TimeoutException) - { - // Don't care, just make sure the stream is still open - Thread.Sleep(500); - } - catch (ObjectDisposedException) - { - // Could be unplugged, or the app is stopping... - return; - } - } - } - - public override void Update() - { - // The NZXT GRID+ V3 series sends updates periodically. We have to read it in a seperate thread, this call just reads that data. - lock (_rawData) - { - for (int fanID = 0; fanID < FANS_COUNT; fanID++) - { - _rpmSensors[fanID].Value = (_rawData[fanID][3] << 8) | _rawData[fanID][4]; - _voltages[fanID].Value = _rawData[fanID][7] + _rawData[fanID][8] / 100.0f; - _currents[fanID].Value = _rawData[fanID][9] + _rawData[fanID][10] / 100.0f; - _powers[fanID].Value = _currents[fanID].Value * _voltages[fanID].Value; - } - _noise.Value = _rawData[2][1]; + // Could be unplugged, or the app is stopping... + return; } } } + + public override void Update() + { + // The NZXT GRID+ V3 series sends updates periodically. We have to read it in a seperate thread, this call just reads that data. + lock (_rawData) + { + for (int fanID = 0; fanID < FANS_COUNT; fanID++) + { + _rpmSensors[fanID].Value = (_rawData[fanID][3] << 8) | _rawData[fanID][4]; + _voltages[fanID].Value = _rawData[fanID][7] + _rawData[fanID][8] / 100.0f; + _currents[fanID].Value = _rawData[fanID][9] + _rawData[fanID][10] / 100.0f; + _powers[fanID].Value = _currents[fanID].Value * _voltages[fanID].Value; + } + _noise.Value = _rawData[2][1]; + } + } } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/KrakenX3.cs b/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/KrakenX3.cs index aae8647..8b5e32e 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/KrakenX3.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/KrakenX3.cs @@ -8,156 +8,155 @@ using System.Linq; using System.Threading; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.Nzxt -{ - /** +namespace LibreHardwareMonitor.Hardware.Controller.Nzxt; + +/** * Support for the Kraken X3 devices from NZXT */ - internal sealed class KrakenX3 : Hardware +internal sealed class KrakenX3 : Hardware +{ + // Some fixed messages to send to the pump for basic monitoring and control + private static readonly byte[] _getFirmwareInfo = { 0x10, 0x01 }; + private static readonly byte[] _initialize1 = { 0x70, 0x02, 0x01, 0xb8, 0x0b }; + private static readonly byte[] _initialize2 = { 0x70, 0x01 }; + private static readonly byte[][] _setPumpTargetMap = new byte[101][]; // Sacrifice memory to speed this up with a lookup instead of a copy operation + + private readonly Sensor _pump; + private readonly Sensor _pumpRpm; + private readonly byte[] _rawData = new byte[64]; + private readonly HidStream _stream; + private readonly Sensor _temperature; + + private volatile bool _controlling; + + static KrakenX3() { - // Some fixed messages to send to the pump for basic monitoring and control - private static readonly byte[] _getFirmwareInfo = { 0x10, 0x01 }; - private static readonly byte[] _initialize1 = { 0x70, 0x02, 0x01, 0xb8, 0x0b }; - private static readonly byte[] _initialize2 = { 0x70, 0x01 }; - private static readonly byte[][] _setPumpTargetMap = new byte[101][]; // Sacrifice memory to speed this up with a lookup instead of a copy operation + byte[] setPumpSpeedHeader = { 0x72, 0x01, 0x00, 0x00 }; - private readonly Sensor _pump; - private readonly Sensor _pumpRpm; - private readonly byte[] _rawData = new byte[64]; - private readonly HidStream _stream; - private readonly Sensor _temperature; + for (byte speed = 0; speed < _setPumpTargetMap.Length; speed++) + _setPumpTargetMap[speed] = setPumpSpeedHeader.Concat(Enumerable.Repeat(speed, 40).Concat(new byte[20])).ToArray(); + } - private volatile bool _controlling; - - static KrakenX3() + public KrakenX3(HidDevice dev, ISettings settings) : base("Nzxt Kraken X3", new Identifier("nzxt", "krakenx3", dev.GetSerialNumber().TrimStart('0')), settings) + { + if (dev.TryOpen(out _stream)) { - byte[] setPumpSpeedHeader = { 0x72, 0x01, 0x00, 0x00 }; + _stream.ReadTimeout = 5000; // The NZXT device returns with data that we need periodically without writing... + _stream.Write(_initialize1); + _stream.Write(_initialize2); - for (byte speed = 0; speed < _setPumpTargetMap.Length; speed++) - _setPumpTargetMap[speed] = setPumpSpeedHeader.Concat(Enumerable.Repeat(speed, 40).Concat(new byte[20])).ToArray(); - } - - public KrakenX3(HidDevice dev, ISettings settings) : base("Nzxt Kraken X3", new Identifier("nzxt", "krakenx3", dev.GetSerialNumber().TrimStart('0')), settings) - { - if (dev.TryOpen(out _stream)) + _stream.Write(_getFirmwareInfo); + do { - _stream.ReadTimeout = 5000; // The NZXT device returns with data that we need periodically without writing... - _stream.Write(_initialize1); - _stream.Write(_initialize2); - - _stream.Write(_getFirmwareInfo); - do + _stream.Read(_rawData); + if (_rawData[0] == 0x11 && _rawData[1] == 0x01) { - _stream.Read(_rawData); - if (_rawData[0] == 0x11 && _rawData[1] == 0x01) - { - FirmwareVersion = $"{_rawData[0x11]}.{_rawData[0x12]}.{_rawData[0x13]}"; - } - } - while (FirmwareVersion == null); - - Name = "Nzxt Kraken X3"; - - _pump = new Sensor("Pump Control", 0, SensorType.Control, this, Array.Empty(), settings); - Control pumpControl = new(_pump, settings, 0, 100); - _pump.Control = pumpControl; - pumpControl.ControlModeChanged += SoftwareControlValueChanged; - pumpControl.SoftwareControlValueChanged += SoftwareControlValueChanged; - SoftwareControlValueChanged(pumpControl); - ActivateSensor(_pump); - - _pumpRpm = new Sensor("Pump", 0, SensorType.Fan, this, Array.Empty(), settings); - ActivateSensor(_pumpRpm); - - _temperature = new Sensor("Internal Water", 0, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperature); - - ThreadPool.UnsafeQueueUserWorkItem(ContinuousRead, _rawData); - } - } - - public string FirmwareVersion { get; } - - public override HardwareType HardwareType => HardwareType.Cooler; - - public string Status => FirmwareVersion != "2.1.0" ? $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 2.1.0" : "Status: OK"; - - private void SoftwareControlValueChanged(Control control) - { - if (control.ControlMode == ControlMode.Software) - { - float value = control.SoftwareValue; - byte pumpSpeedIndex = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail - - _controlling = true; - _stream.Write(_setPumpTargetMap[pumpSpeedIndex]); - _pump.Value = value; - } - else if (control.ControlMode == ControlMode.Default) - { - // There isn't a "default" mode with this pump, but a safe setting is 40% - _stream.Write(_setPumpTargetMap[40]); - } - } - - public override void Close() - { - base.Close(); - _stream?.Close(); - } - - private void ContinuousRead(object state) - { - byte[] buffer = new byte[_rawData.Length]; - while (_stream.CanRead) - { - try - { - _stream.Read(buffer); // This is a blocking call, will wait for bytes to become available - - lock (_rawData) - { - Array.Copy(buffer, _rawData, buffer.Length); - } - } - catch (TimeoutException) - { - // Don't care, just make sure the stream is still open - Thread.Sleep(500); - } - catch (ObjectDisposedException) - { - // Could be unplugged, or the app is stopping... - return; + FirmwareVersion = $"{_rawData[0x11]}.{_rawData[0x12]}.{_rawData[0x13]}"; } } + while (FirmwareVersion == null); + + Name = "Nzxt Kraken X3"; + + _pump = new Sensor("Pump Control", 0, SensorType.Control, this, Array.Empty(), settings); + Control pumpControl = new(_pump, settings, 0, 100); + _pump.Control = pumpControl; + pumpControl.ControlModeChanged += SoftwareControlValueChanged; + pumpControl.SoftwareControlValueChanged += SoftwareControlValueChanged; + SoftwareControlValueChanged(pumpControl); + ActivateSensor(_pump); + + _pumpRpm = new Sensor("Pump", 0, SensorType.Fan, this, Array.Empty(), settings); + ActivateSensor(_pumpRpm); + + _temperature = new Sensor("Internal Water", 0, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperature); + + ThreadPool.UnsafeQueueUserWorkItem(ContinuousRead, _rawData); } + } - public override void Update() + public string FirmwareVersion { get; } + + public override HardwareType HardwareType => HardwareType.Cooler; + + public string Status => FirmwareVersion != "2.1.0" ? $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 2.1.0" : "Status: OK"; + + private void SoftwareControlValueChanged(Control control) + { + if (control.ControlMode == ControlMode.Software) { - // The NZXT Kraken X3 series sends updates periodically. We have to read it in a seperate thread, this call just reads that data. - lock (_rawData) - { - if (_rawData[0] == 0x75 && _rawData[1] == 0x02) - { - _temperature.Value = _rawData[15] + (_rawData[16] / 10.0f); - _pumpRpm.Value = (_rawData[18] << 8) | _rawData[17]; + float value = control.SoftwareValue; + byte pumpSpeedIndex = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail - // The following logic makes sure the pump is set to the controlling value. This pump sometimes sets itself to 0% when instructed to a value. - if (!_controlling) - { - _pump.Value = _rawData[19]; - } - else if (_pump.Value != _rawData[19]) - { - float value = _pump.Value.GetValueOrDefault(); - byte pumpSpeedIndex = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail - _stream.Write(_setPumpTargetMap[pumpSpeedIndex]); - } - else - { - _controlling = false; - } + _controlling = true; + _stream.Write(_setPumpTargetMap[pumpSpeedIndex]); + _pump.Value = value; + } + else if (control.ControlMode == ControlMode.Default) + { + // There isn't a "default" mode with this pump, but a safe setting is 40% + _stream.Write(_setPumpTargetMap[40]); + } + } + + public override void Close() + { + base.Close(); + _stream?.Close(); + } + + private void ContinuousRead(object state) + { + byte[] buffer = new byte[_rawData.Length]; + while (_stream.CanRead) + { + try + { + _stream.Read(buffer); // This is a blocking call, will wait for bytes to become available + + lock (_rawData) + { + Array.Copy(buffer, _rawData, buffer.Length); + } + } + catch (TimeoutException) + { + // Don't care, just make sure the stream is still open + Thread.Sleep(500); + } + catch (ObjectDisposedException) + { + // Could be unplugged, or the app is stopping... + return; + } + } + } + + public override void Update() + { + // The NZXT Kraken X3 series sends updates periodically. We have to read it in a seperate thread, this call just reads that data. + lock (_rawData) + { + if (_rawData[0] == 0x75 && _rawData[1] == 0x02) + { + _temperature.Value = _rawData[15] + (_rawData[16] / 10.0f); + _pumpRpm.Value = (_rawData[18] << 8) | _rawData[17]; + + // The following logic makes sure the pump is set to the controlling value. This pump sometimes sets itself to 0% when instructed to a value. + if (!_controlling) + { + _pump.Value = _rawData[19]; + } + else if (_pump.Value != _rawData[19]) + { + float value = _pump.Value.GetValueOrDefault(); + byte pumpSpeedIndex = (byte)(value > 100 ? 100 : value < 0 ? 0 : value); // Clamp the value, anything out of range will fail + _stream.Write(_setPumpTargetMap[pumpSpeedIndex]); + } + else + { + _controlling = false; } } } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/NzxtGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/NzxtGroup.cs index 1341aa2..749f55b 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/NzxtGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/Nzxt/NzxtGroup.cs @@ -7,68 +7,67 @@ using System.Collections.Generic; using System.Text; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Controller.Nzxt +namespace LibreHardwareMonitor.Hardware.Controller.Nzxt; + +internal class NzxtGroup : IGroup { - internal class NzxtGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public NzxtGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); + _report.AppendLine("Nzxt Hardware"); + _report.AppendLine(); - public NzxtGroup(ISettings settings) + foreach (HidDevice dev in DeviceList.Local.GetHidDevices(0x1e71)) { - _report.AppendLine("Nzxt Hardware"); + string productName = dev.GetProductName(); + + switch (dev.ProductID) + { + case 0x2007: + var device = new KrakenX3(dev, settings); + _report.AppendLine($"Device name: {productName}"); + _report.AppendLine($"Firmware version: {device.FirmwareVersion}"); + _report.AppendLine($"{device.Status}"); + _report.AppendLine(); + _hardware.Add(device); + break; + case 0x1711: + var gridv3 = new GridV3(dev, settings); + _report.AppendLine($"Device name: {productName}"); + _report.AppendLine($"Firmware version: {gridv3.FirmwareVersion}"); + _report.AppendLine(); + _hardware.Add(gridv3); + break; + + default: + _report.AppendLine($"Unknown Hardware PID: {dev.ProductID} Name: {productName}"); + _report.AppendLine(); + break; + } + } + + if (_hardware.Count == 0) + { + _report.AppendLine("No Nzxt Hardware found."); _report.AppendLine(); - - foreach (HidDevice dev in DeviceList.Local.GetHidDevices(0x1e71)) - { - string productName = dev.GetProductName(); - - switch (dev.ProductID) - { - case 0x2007: - var device = new KrakenX3(dev, settings); - _report.AppendLine($"Device name: {productName}"); - _report.AppendLine($"Firmware version: {device.FirmwareVersion}"); - _report.AppendLine($"{device.Status}"); - _report.AppendLine(); - _hardware.Add(device); - break; - case 0x1711: - var gridv3 = new GridV3(dev, settings); - _report.AppendLine($"Device name: {productName}"); - _report.AppendLine($"Firmware version: {gridv3.FirmwareVersion}"); - _report.AppendLine(); - _hardware.Add(gridv3); - break; - - default: - _report.AppendLine($"Unknown Hardware PID: {dev.ProductID} Name: {productName}"); - _report.AppendLine(); - break; - } - } - - if (_hardware.Count == 0) - { - _report.AppendLine("No Nzxt Hardware found."); - _report.AppendLine(); - } - } - - public IReadOnlyList Hardware => _hardware; - - public void Close() - { - foreach (IHardware iHardware in _hardware) - { - if (iHardware is Hardware hardware) - hardware.Close(); - } - } - - public string GetReport() - { - return _report.ToString(); } } -} + + public IReadOnlyList Hardware => _hardware; + + public void Close() + { + foreach (IHardware iHardware in _hardware) + { + if (iHardware is Hardware hardware) + hardware.Close(); + } + } + + public string GetReport() + { + return _report.ToString(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancer.cs b/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancer.cs index fd8ee7c..8e1c40a 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancer.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancer.cs @@ -12,276 +12,302 @@ using LibreHardwareMonitor.Interop; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Hardware.Controller.TBalancer +namespace LibreHardwareMonitor.Hardware.Controller.TBalancer; + +internal class TBalancer : Hardware { - internal class TBalancer : Hardware + internal const byte EndFlag = 254; + internal const byte StartFlag = 100; + + private readonly MethodDelegate _alternativeRequest; + private readonly Sensor[] _analogTemperatures = new Sensor[4]; + private readonly Sensor[] _controls = new Sensor[4]; + private readonly List _deactivating = new(); + private readonly Sensor[] _digitalTemperatures = new Sensor[8]; + private readonly Sensor[] _fans = new Sensor[4]; + private readonly Sensor[] _miniNgControls = new Sensor[4]; + private readonly Sensor[] _miniNgFans = new Sensor[4]; + private readonly Sensor[] _miniNgTemperatures = new Sensor[4]; + private readonly int _portIndex; + private readonly byte _protocolVersion; + private readonly Sensor[] _sensorHubFlows = new Sensor[2]; + private readonly Sensor[] _sensorHubTemperatures = new Sensor[6]; + private byte[] _alternativeData = Array.Empty(); + private readonly byte[] _data = new byte[285]; + private Ftd2xx.FT_HANDLE _handle; + private byte[] _primaryData = Array.Empty(); + + public TBalancer(int portIndex, byte protocolVersion, ISettings settings) : + base("T-Balancer bigNG", new Identifier("bigng", portIndex.ToString(CultureInfo.InvariantCulture)), settings) { - internal const byte EndFlag = 254; - internal const byte StartFlag = 100; + _portIndex = portIndex; + _protocolVersion = protocolVersion; - private readonly MethodDelegate _alternativeRequest; - private readonly Sensor[] _analogTemperatures = new Sensor[4]; - private readonly Sensor[] _controls = new Sensor[4]; - private readonly List _deactivating = new(); - private readonly Sensor[] _digitalTemperatures = new Sensor[8]; - private readonly Sensor[] _fans = new Sensor[4]; - private readonly Sensor[] _miniNgControls = new Sensor[4]; - private readonly Sensor[] _miniNgFans = new Sensor[4]; - private readonly Sensor[] _miniNgTemperatures = new Sensor[4]; - private readonly int _portIndex; - private readonly byte _protocolVersion; - private readonly Sensor[] _sensorHubFlows = new Sensor[2]; - private readonly Sensor[] _sensorHubTemperatures = new Sensor[6]; - private byte[] _alternativeData = Array.Empty(); - private readonly byte[] _data = new byte[285]; - private Ftd2xx.FT_HANDLE _handle; - private byte[] _primaryData = Array.Empty(); + ParameterDescription[] parameter = { new("Offset [°C]", "Temperature offset.", 0) }; + int offset = 0; + for (int i = 0; i < _digitalTemperatures.Length; i++) + _digitalTemperatures[i] = new Sensor("Digital Sensor " + i, offset + i, SensorType.Temperature, this, parameter, settings); - public TBalancer(int portIndex, byte protocolVersion, ISettings settings) : - base("T-Balancer bigNG", new Identifier("bigng", portIndex.ToString(CultureInfo.InvariantCulture)), settings) + offset += _digitalTemperatures.Length; + + for (int i = 0; i < _analogTemperatures.Length; i++) + _analogTemperatures[i] = new Sensor("Analog Sensor " + (i + 1), offset + i, SensorType.Temperature, this, parameter, settings); + + offset += _analogTemperatures.Length; + + for (int i = 0; i < _sensorHubTemperatures.Length; i++) + _sensorHubTemperatures[i] = new Sensor("Sensorhub Sensor " + i, offset + i, SensorType.Temperature, this, parameter, settings); + + offset += _sensorHubTemperatures.Length; + + for (int i = 0; i < _miniNgTemperatures.Length; i++) + _miniNgTemperatures[i] = new Sensor("miniNG #" + ((i / 2) + 1) + " Sensor " + ((i % 2) + 1), offset + i, SensorType.Temperature, this, parameter, settings); + + for (int i = 0; i < _sensorHubFlows.Length; i++) { - _portIndex = portIndex; - _protocolVersion = protocolVersion; - - ParameterDescription[] parameter = { new("Offset [°C]", "Temperature offset.", 0) }; - int offset = 0; - for (int i = 0; i < _digitalTemperatures.Length; i++) - _digitalTemperatures[i] = new Sensor("Digital Sensor " + i, offset + i, SensorType.Temperature, this, parameter, settings); - - offset += _digitalTemperatures.Length; - - for (int i = 0; i < _analogTemperatures.Length; i++) - _analogTemperatures[i] = new Sensor("Analog Sensor " + (i + 1), offset + i, SensorType.Temperature, this, parameter, settings); - - offset += _analogTemperatures.Length; - - for (int i = 0; i < _sensorHubTemperatures.Length; i++) - _sensorHubTemperatures[i] = new Sensor("Sensorhub Sensor " + i, offset + i, SensorType.Temperature, this, parameter, settings); - - offset += _sensorHubTemperatures.Length; - - for (int i = 0; i < _miniNgTemperatures.Length; i++) - _miniNgTemperatures[i] = new Sensor("miniNG #" + ((i / 2) + 1) + " Sensor " + ((i % 2) + 1), offset + i, SensorType.Temperature, this, parameter, settings); - - for (int i = 0; i < _sensorHubFlows.Length; i++) - { - _sensorHubFlows[i] = new Sensor("Flowmeter " + (i + 1), - i, - SensorType.Flow, - this, - new[] { new ParameterDescription("Impulse Rate", "The impulse rate of the flowmeter in pulses/L", 509) }, - settings); - } - - for (int i = 0; i < _controls.Length; i++) - { - _controls[i] = new Sensor("Fan Channel " + i, i, SensorType.Control, this, settings); - } - - for (int i = 0; i < _miniNgControls.Length; i++) - { - _miniNgControls[i] = new Sensor("miniNG #" + ((i / 2) + 1) + " Fan Channel " + ((i % 2) + 1), 4 + i, SensorType.Control, this, settings); - } - - _alternativeRequest = DelayedAlternativeRequest; - - Open(); - Update(); + _sensorHubFlows[i] = new Sensor("Flowmeter " + (i + 1), + i, + SensorType.Flow, + this, + new[] { new ParameterDescription("Impulse Rate", "The impulse rate of the flowmeter in pulses/L", 509) }, + settings); } - public override HardwareType HardwareType + for (int i = 0; i < _controls.Length; i++) { - get { return HardwareType.Cooler; } + _controls[i] = new Sensor("Fan Channel " + i, i, SensorType.Control, this, settings); } - protected override void ActivateSensor(ISensor sensor) + for (int i = 0; i < _miniNgControls.Length; i++) + { + _miniNgControls[i] = new Sensor("miniNG #" + ((i / 2) + 1) + " Fan Channel " + ((i % 2) + 1), 4 + i, SensorType.Control, this, settings); + } + + _alternativeRequest = DelayedAlternativeRequest; + + Open(); + Update(); + } + + public override HardwareType HardwareType + { + get { return HardwareType.Cooler; } + } + + protected override void ActivateSensor(ISensor sensor) + { + _deactivating.Remove(sensor); + base.ActivateSensor(sensor); + } + + protected override void DeactivateSensor(ISensor sensor) + { + if (_deactivating.Contains(sensor)) { _deactivating.Remove(sensor); - base.ActivateSensor(sensor); + base.DeactivateSensor(sensor); } - - protected override void DeactivateSensor(ISensor sensor) + else if (_active.Contains(sensor)) { - if (_deactivating.Contains(sensor)) + _deactivating.Add(sensor); + } + } + + private void ReadMiniNg(int number) + { + int offset = 1 + (number * 65); + + if (_data[offset + 61] != EndFlag) + return; + + for (int i = 0; i < 2; i++) + { + Sensor sensor = _miniNgTemperatures[(number * 2) + i]; + if (_data[offset + 7 + i] > 0) { - _deactivating.Remove(sensor); - base.DeactivateSensor(sensor); + sensor.Value = (0.5f * _data[offset + 7 + i]) + + sensor.Parameters[0].Value; + + ActivateSensor(sensor); } - else if (_active.Contains(sensor)) + else { - _deactivating.Add(sensor); + DeactivateSensor(sensor); } } - private void ReadMiniNg(int number) + for (int i = 0; i < 2; i++) { - int offset = 1 + (number * 65); + _miniNgFans[(number * 2) + i] ??= new Sensor("miniNG #" + (number + 1) + " Fan Channel " + (i + 1), 4 + (number * 2) + i, SensorType.Fan, this, _settings); - if (_data[offset + 61] != EndFlag) + Sensor sensor = _miniNgFans[(number * 2) + i]; + sensor.Value = 20.0f * _data[offset + 43 + (2 * i)]; + ActivateSensor(sensor); + } + + for (int i = 0; i < 2; i++) + { + Sensor sensor = _miniNgControls[(number * 2) + i]; + sensor.Value = _data[offset + 15 + i]; + ActivateSensor(sensor); + } + } + + private void ReadData() + { + Ftd2xx.Read(_handle, _data); + if (_data[0] != StartFlag) + { + Ftd2xx.FT_Purge(_handle, Ftd2xx.FT_PURGE.FT_PURGE_RX); + return; + } + + if (_data[1] is 255 or 88) + { + // bigNG + + if (_data[274] != _protocolVersion) return; - for (int i = 0; i < 2; i++) - { - Sensor sensor = _miniNgTemperatures[(number * 2) + i]; - if (_data[offset + 7 + i] > 0) - { - sensor.Value = (0.5f * _data[offset + 7 + i]) + - sensor.Parameters[0].Value; + if (_primaryData.Length == 0) + _primaryData = new byte[_data.Length]; - ActivateSensor(sensor); + _data.CopyTo(_primaryData, 0); + + for (int i = 0; i < _digitalTemperatures.Length; i++) + { + if (_data[238 + i] > 0) + { + _digitalTemperatures[i].Value = (0.5f * _data[238 + i]) + _digitalTemperatures[i].Parameters[0].Value; + ActivateSensor(_digitalTemperatures[i]); } else { - DeactivateSensor(sensor); + DeactivateSensor(_digitalTemperatures[i]); } } - for (int i = 0; i < 2; i++) + for (int i = 0; i < _analogTemperatures.Length; i++) { - _miniNgFans[(number * 2) + i] ??= new Sensor("miniNG #" + (number + 1) + " Fan Channel " + (i + 1), 4 + (number * 2) + i, SensorType.Fan, this, _settings); - - Sensor sensor = _miniNgFans[(number * 2) + i]; - sensor.Value = 20.0f * _data[offset + 43 + (2 * i)]; - ActivateSensor(sensor); + if (_data[260 + i] > 0) + { + _analogTemperatures[i].Value = (0.5f * _data[260 + i]) + _analogTemperatures[i].Parameters[0].Value; + ActivateSensor(_analogTemperatures[i]); + } + else + { + DeactivateSensor(_analogTemperatures[i]); + } } - for (int i = 0; i < 2; i++) + for (int i = 0; i < _sensorHubTemperatures.Length; i++) { - Sensor sensor = _miniNgControls[(number * 2) + i]; - sensor.Value = _data[offset + 15 + i]; - ActivateSensor(sensor); + if (_data[246 + i] > 0) + { + _sensorHubTemperatures[i].Value = (0.5f * _data[246 + i]) + _sensorHubTemperatures[i].Parameters[0].Value; + ActivateSensor(_sensorHubTemperatures[i]); + } + else + { + DeactivateSensor(_sensorHubTemperatures[i]); + } + } + + for (int i = 0; i < _sensorHubFlows.Length; i++) + { + if (_data[231 + i] > 0 && _data[234] > 0) + { + float pulsesPerSecond = (_data[231 + i] * 4.0f) / _data[234]; + float pulsesPerLiter = _sensorHubFlows[i].Parameters[0].Value; + _sensorHubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter; + ActivateSensor(_sensorHubFlows[i]); + } + else + { + DeactivateSensor(_sensorHubFlows[i]); + } + } + + for (int i = 0; i < _fans.Length; i++) + { + float maxRpm = 11.5f * ((_data[149 + (2 * i)] << 8) | _data[148 + (2 * i)]); + + _fans[i] ??= new Sensor("Fan Channel " + i, + i, + SensorType.Fan, + this, + new[] + { + new ParameterDescription("MaxRPM", + "Maximum revolutions per minute (RPM) of the fan.", + maxRpm) + }, + _settings); + + float value; + if ((_data[136] & (1 << i)) == 0) // pwm mode + value = 0.02f * _data[137 + i]; + else // analog mode + value = 0.01f * _data[141 + i]; + + _fans[i].Value = _fans[i].Parameters[0].Value * value; + ActivateSensor(_fans[i]); + + _controls[i].Value = 100 * value; + ActivateSensor(_controls[i]); } } - - private void ReadData() + else if (_data[1] == 253) { - Ftd2xx.Read(_handle, _data); - if (_data[0] != StartFlag) + // miniNG #1 + if (_alternativeData.Length == 0) + _alternativeData = new byte[_data.Length]; + + _data.CopyTo(_alternativeData, 0); + + ReadMiniNg(0); + if (_data[66] == 253) // miniNG #2 + ReadMiniNg(1); + } + } + + public override string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("T-Balancer bigNG"); + r.AppendLine(); + r.Append("Port Index: "); + r.AppendLine(_portIndex.ToString(CultureInfo.InvariantCulture)); + r.AppendLine(); + + r.AppendLine("Primary System Information Answer"); + r.AppendLine(); + r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); + r.AppendLine(); + for (int i = 0; i <= 0x11; i++) + { + r.Append(" "); + r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); + r.Append(" "); + for (int j = 0; j <= 0xF; j++) { - Ftd2xx.FT_Purge(_handle, Ftd2xx.FT_PURGE.FT_PURGE_RX); - return; + int index = (i << 4) | j; + if (index < _primaryData.Length) + { + r.Append(" "); + r.Append(_primaryData[index].ToString("X2", CultureInfo.InvariantCulture)); + } } - if (_data[1] is 255 or 88) - { - // bigNG - - if (_data[274] != _protocolVersion) - return; - - if (_primaryData.Length == 0) - _primaryData = new byte[_data.Length]; - - _data.CopyTo(_primaryData, 0); - - for (int i = 0; i < _digitalTemperatures.Length; i++) - { - if (_data[238 + i] > 0) - { - _digitalTemperatures[i].Value = (0.5f * _data[238 + i]) + _digitalTemperatures[i].Parameters[0].Value; - ActivateSensor(_digitalTemperatures[i]); - } - else - { - DeactivateSensor(_digitalTemperatures[i]); - } - } - - for (int i = 0; i < _analogTemperatures.Length; i++) - { - if (_data[260 + i] > 0) - { - _analogTemperatures[i].Value = (0.5f * _data[260 + i]) + _analogTemperatures[i].Parameters[0].Value; - ActivateSensor(_analogTemperatures[i]); - } - else - { - DeactivateSensor(_analogTemperatures[i]); - } - } - - for (int i = 0; i < _sensorHubTemperatures.Length; i++) - { - if (_data[246 + i] > 0) - { - _sensorHubTemperatures[i].Value = (0.5f * _data[246 + i]) + _sensorHubTemperatures[i].Parameters[0].Value; - ActivateSensor(_sensorHubTemperatures[i]); - } - else - { - DeactivateSensor(_sensorHubTemperatures[i]); - } - } - - for (int i = 0; i < _sensorHubFlows.Length; i++) - { - if (_data[231 + i] > 0 && _data[234] > 0) - { - float pulsesPerSecond = (_data[231 + i] * 4.0f) / _data[234]; - float pulsesPerLiter = _sensorHubFlows[i].Parameters[0].Value; - _sensorHubFlows[i].Value = pulsesPerSecond * 3600 / pulsesPerLiter; - ActivateSensor(_sensorHubFlows[i]); - } - else - { - DeactivateSensor(_sensorHubFlows[i]); - } - } - - for (int i = 0; i < _fans.Length; i++) - { - float maxRpm = 11.5f * ((_data[149 + (2 * i)] << 8) | _data[148 + (2 * i)]); - - _fans[i] ??= new Sensor("Fan Channel " + i, - i, - SensorType.Fan, - this, - new[] - { - new ParameterDescription("MaxRPM", - "Maximum revolutions per minute (RPM) of the fan.", - maxRpm) - }, - _settings); - - float value; - if ((_data[136] & (1 << i)) == 0) // pwm mode - value = 0.02f * _data[137 + i]; - else // analog mode - value = 0.01f * _data[141 + i]; - - _fans[i].Value = _fans[i].Parameters[0].Value * value; - ActivateSensor(_fans[i]); - - _controls[i].Value = 100 * value; - ActivateSensor(_controls[i]); - } - } - else if (_data[1] == 253) - { - // miniNG #1 - if (_alternativeData.Length == 0) - _alternativeData = new byte[_data.Length]; - - _data.CopyTo(_alternativeData, 0); - - ReadMiniNg(0); - if (_data[66] == 253) // miniNG #2 - ReadMiniNg(1); - } + r.AppendLine(); } - public override string GetReport() + r.AppendLine(); + + if (_alternativeData.Length > 0) { - StringBuilder r = new(); - - r.AppendLine("T-Balancer bigNG"); - r.AppendLine(); - r.Append("Port Index: "); - r.AppendLine(_portIndex.ToString(CultureInfo.InvariantCulture)); - r.AppendLine(); - - r.AppendLine("Primary System Information Answer"); + r.AppendLine("Alternative System Information Answer"); r.AppendLine(); r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); r.AppendLine(); @@ -293,10 +319,10 @@ namespace LibreHardwareMonitor.Hardware.Controller.TBalancer for (int j = 0; j <= 0xF; j++) { int index = (i << 4) | j; - if (index < _primaryData.Length) + if (index < _alternativeData.Length) { r.Append(" "); - r.Append(_primaryData[index].ToString("X2", CultureInfo.InvariantCulture)); + r.Append(_alternativeData[index].ToString("X2", CultureInfo.InvariantCulture)); } } @@ -304,71 +330,44 @@ namespace LibreHardwareMonitor.Hardware.Controller.TBalancer } r.AppendLine(); - - if (_alternativeData.Length > 0) - { - r.AppendLine("Alternative System Information Answer"); - r.AppendLine(); - r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - r.AppendLine(); - for (int i = 0; i <= 0x11; i++) - { - r.Append(" "); - r.Append((i << 4).ToString("X3", CultureInfo.InvariantCulture)); - r.Append(" "); - for (int j = 0; j <= 0xF; j++) - { - int index = (i << 4) | j; - if (index < _alternativeData.Length) - { - r.Append(" "); - r.Append(_alternativeData[index].ToString("X2", CultureInfo.InvariantCulture)); - } - } - - r.AppendLine(); - } - - r.AppendLine(); - } - - return r.ToString(); } - private void DelayedAlternativeRequest() - { - System.Threading.Thread.Sleep(500); - Ftd2xx.Write(_handle, new byte[] { 0x37 }); - } - - public void Open() - { - Ftd2xx.FT_Open(_portIndex, out _handle); - Ftd2xx.FT_SetBaudRate(_handle, 19200); - Ftd2xx.FT_SetDataCharacteristics(_handle, 8, 1, 0); - Ftd2xx.FT_SetFlowControl(_handle, Ftd2xx.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13); - Ftd2xx.FT_SetTimeouts(_handle, 1000, 1000); - Ftd2xx.FT_Purge(_handle, Ftd2xx.FT_PURGE.FT_PURGE_ALL); - } - - public sealed override void Update() - { - while (Ftd2xx.BytesToRead(_handle) >= 285) - ReadData(); - - if (Ftd2xx.BytesToRead(_handle) == 1) - Ftd2xx.ReadByte(_handle); - - Ftd2xx.Write(_handle, new byte[] { 0x38 }); - _alternativeRequest.BeginInvoke(null, null); - } - - public override void Close() - { - Ftd2xx.FT_Close(_handle); - base.Close(); - } - - private delegate void MethodDelegate(); + return r.ToString(); } + + private void DelayedAlternativeRequest() + { + System.Threading.Thread.Sleep(500); + Ftd2xx.Write(_handle, new byte[] { 0x37 }); + } + + public void Open() + { + Ftd2xx.FT_Open(_portIndex, out _handle); + Ftd2xx.FT_SetBaudRate(_handle, 19200); + Ftd2xx.FT_SetDataCharacteristics(_handle, 8, 1, 0); + Ftd2xx.FT_SetFlowControl(_handle, Ftd2xx.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13); + Ftd2xx.FT_SetTimeouts(_handle, 1000, 1000); + Ftd2xx.FT_Purge(_handle, Ftd2xx.FT_PURGE.FT_PURGE_ALL); + } + + public sealed override void Update() + { + while (Ftd2xx.BytesToRead(_handle) >= 285) + ReadData(); + + if (Ftd2xx.BytesToRead(_handle) == 1) + Ftd2xx.ReadByte(_handle); + + Ftd2xx.Write(_handle, new byte[] { 0x38 }); + _alternativeRequest.BeginInvoke(null, null); + } + + public override void Close() + { + Ftd2xx.FT_Close(_handle); + base.Close(); + } + + private delegate void MethodDelegate(); } diff --git a/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancerGroup.cs b/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancerGroup.cs index 236b26b..37dfae6 100644 --- a/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancerGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Controller/TBalancer/TBalancerGroup.cs @@ -13,169 +13,168 @@ using LibreHardwareMonitor.Interop; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Hardware.Controller.TBalancer +namespace LibreHardwareMonitor.Hardware.Controller.TBalancer; + +internal class TBalancerGroup : IGroup { - internal class TBalancerGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public TBalancerGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); + uint numDevices; - public TBalancerGroup(ISettings settings) + try { - uint numDevices; - - try - { - if (!Ftd2xx.DllExists()) - { - _report.AppendLine("Status: missing DLL"); - return; - } - - if (Ftd2xx.FT_CreateDeviceInfoList(out numDevices) != Ftd2xx.FT_STATUS.FT_OK) - { - _report.AppendLine("Status: FT_CreateDeviceInfoList failed"); - return; - } - } - catch (Exception e) when (e is DllNotFoundException or ArgumentNullException or EntryPointNotFoundException or BadImageFormatException) + if (!Ftd2xx.DllExists()) { + _report.AppendLine("Status: missing DLL"); return; } - Ftd2xx.FT_DEVICE_INFO_NODE[] info = new Ftd2xx.FT_DEVICE_INFO_NODE[numDevices]; - if (Ftd2xx.FT_GetDeviceInfoList(info, ref numDevices) != Ftd2xx.FT_STATUS.FT_OK) + if (Ftd2xx.FT_CreateDeviceInfoList(out numDevices) != Ftd2xx.FT_STATUS.FT_OK) { - _report.AppendLine("Status: FT_GetDeviceInfoList failed"); + _report.AppendLine("Status: FT_CreateDeviceInfoList failed"); return; } + } + catch (Exception e) when (e is DllNotFoundException or ArgumentNullException or EntryPointNotFoundException or BadImageFormatException) + { + return; + } - // make sure numDevices is not larger than the info array - if (numDevices > info.Length) - numDevices = (uint)info.Length; + Ftd2xx.FT_DEVICE_INFO_NODE[] info = new Ftd2xx.FT_DEVICE_INFO_NODE[numDevices]; + if (Ftd2xx.FT_GetDeviceInfoList(info, ref numDevices) != Ftd2xx.FT_STATUS.FT_OK) + { + _report.AppendLine("Status: FT_GetDeviceInfoList failed"); + return; + } - for (int i = 0; i < numDevices; i++) + // make sure numDevices is not larger than the info array + if (numDevices > info.Length) + numDevices = (uint)info.Length; + + for (int i = 0; i < numDevices; i++) + { + _report.Append("Device Index: "); + _report.AppendLine(i.ToString(CultureInfo.InvariantCulture)); + _report.Append("Device Type: "); + _report.AppendLine(info[i].Type.ToString()); + + // the T-Balancer always uses an FT232BM + if (info[i].Type != Ftd2xx.FT_DEVICE.FT_DEVICE_232BM) { - _report.Append("Device Index: "); - _report.AppendLine(i.ToString(CultureInfo.InvariantCulture)); - _report.Append("Device Type: "); - _report.AppendLine(info[i].Type.ToString()); + _report.AppendLine("Status: Wrong device type"); + continue; + } - // the T-Balancer always uses an FT232BM - if (info[i].Type != Ftd2xx.FT_DEVICE.FT_DEVICE_232BM) + Ftd2xx.FT_STATUS status = Ftd2xx.FT_Open(i, out Ftd2xx.FT_HANDLE handle); + if (status != Ftd2xx.FT_STATUS.FT_OK) + { + _report.AppendLine("Open Status: " + status); + continue; + } + + Ftd2xx.FT_SetBaudRate(handle, 19200); + Ftd2xx.FT_SetDataCharacteristics(handle, 8, 1, 0); + Ftd2xx.FT_SetFlowControl(handle, Ftd2xx.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13); + Ftd2xx.FT_SetTimeouts(handle, 1000, 1000); + Ftd2xx.FT_Purge(handle, Ftd2xx.FT_PURGE.FT_PURGE_ALL); + + status = Ftd2xx.Write(handle, new byte[] { 0x38 }); + if (status != Ftd2xx.FT_STATUS.FT_OK) + { + _report.AppendLine("Write Status: " + status); + Ftd2xx.FT_Close(handle); + continue; + } + + bool isValid = false; + byte protocolVersion = 0; + + int j = 0; + while (Ftd2xx.BytesToRead(handle) == 0 && j < 2) + { + Thread.Sleep(100); + j++; + } + + if (Ftd2xx.BytesToRead(handle) > 0) + { + if (Ftd2xx.ReadByte(handle) == TBalancer.StartFlag) { - _report.AppendLine("Status: Wrong device type"); - continue; - } - - Ftd2xx.FT_STATUS status = Ftd2xx.FT_Open(i, out Ftd2xx.FT_HANDLE handle); - if (status != Ftd2xx.FT_STATUS.FT_OK) - { - _report.AppendLine("Open Status: " + status); - continue; - } - - Ftd2xx.FT_SetBaudRate(handle, 19200); - Ftd2xx.FT_SetDataCharacteristics(handle, 8, 1, 0); - Ftd2xx.FT_SetFlowControl(handle, Ftd2xx.FT_FLOW_CONTROL.FT_FLOW_RTS_CTS, 0x11, 0x13); - Ftd2xx.FT_SetTimeouts(handle, 1000, 1000); - Ftd2xx.FT_Purge(handle, Ftd2xx.FT_PURGE.FT_PURGE_ALL); - - status = Ftd2xx.Write(handle, new byte[] { 0x38 }); - if (status != Ftd2xx.FT_STATUS.FT_OK) - { - _report.AppendLine("Write Status: " + status); - Ftd2xx.FT_Close(handle); - continue; - } - - bool isValid = false; - byte protocolVersion = 0; - - int j = 0; - while (Ftd2xx.BytesToRead(handle) == 0 && j < 2) - { - Thread.Sleep(100); - j++; - } - - if (Ftd2xx.BytesToRead(handle) > 0) - { - if (Ftd2xx.ReadByte(handle) == TBalancer.StartFlag) + while (Ftd2xx.BytesToRead(handle) < 284 && j < 5) { - while (Ftd2xx.BytesToRead(handle) < 284 && j < 5) - { - Thread.Sleep(100); - j++; - } + Thread.Sleep(100); + j++; + } - int length = Ftd2xx.BytesToRead(handle); - if (length >= 284) - { - byte[] data = new byte[285]; - data[0] = TBalancer.StartFlag; - for (int k = 1; k < data.Length; k++) - data[k] = Ftd2xx.ReadByte(handle); + int length = Ftd2xx.BytesToRead(handle); + if (length >= 284) + { + byte[] data = new byte[285]; + data[0] = TBalancer.StartFlag; + for (int k = 1; k < data.Length; k++) + data[k] = Ftd2xx.ReadByte(handle); - // check protocol version 2X (protocols seen: 2C, 2A, 28) - isValid = (data[274] & 0xF0) == 0x20; - protocolVersion = data[274]; - if (!isValid) - { - _report.Append("Status: Wrong Protocol Version: 0x"); - _report.AppendLine(protocolVersion.ToString("X", CultureInfo.InvariantCulture)); - } - } - else + // check protocol version 2X (protocols seen: 2C, 2A, 28) + isValid = (data[274] & 0xF0) == 0x20; + protocolVersion = data[274]; + if (!isValid) { - _report.AppendLine("Status: Wrong Message Length: " + length); + _report.Append("Status: Wrong Protocol Version: 0x"); + _report.AppendLine(protocolVersion.ToString("X", CultureInfo.InvariantCulture)); } } else { - _report.AppendLine("Status: Wrong Startflag"); + _report.AppendLine("Status: Wrong Message Length: " + length); } } else { - _report.AppendLine("Status: No Response"); + _report.AppendLine("Status: Wrong Startflag"); } - - Ftd2xx.FT_Purge(handle, Ftd2xx.FT_PURGE.FT_PURGE_ALL); - Ftd2xx.FT_Close(handle); - - if (isValid) - { - _report.AppendLine("Status: OK"); - _hardware.Add(new TBalancer(i, protocolVersion, settings)); - } - - if (i < numDevices - 1) - _report.AppendLine(); } - } - - public IReadOnlyList Hardware => _hardware; - - public string GetReport() - { - if (_report.Length > 0) + else { - StringBuilder r = new(); - r.AppendLine("FTD2XX"); - r.AppendLine(); - r.Append(_report); - r.AppendLine(); - return r.ToString(); + _report.AppendLine("Status: No Response"); } - return null; - } + Ftd2xx.FT_Purge(handle, Ftd2xx.FT_PURGE.FT_PURGE_ALL); + Ftd2xx.FT_Close(handle); - public void Close() - { - foreach (TBalancer balancer in _hardware) - balancer.Close(); + if (isValid) + { + _report.AppendLine("Status: OK"); + _hardware.Add(new TBalancer(i, protocolVersion, settings)); + } + + if (i < numDevices - 1) + _report.AppendLine(); } } -} + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + if (_report.Length > 0) + { + StringBuilder r = new(); + r.AppendLine("FTD2XX"); + r.AppendLine(); + r.Append(_report); + r.AppendLine(); + return r.ToString(); + } + + return null; + } + + public void Close() + { + foreach (TBalancer balancer in _hardware) + balancer.Close(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs index b074bab..153d38b 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/Amd0FCpu.cs @@ -9,154 +9,153 @@ using System.Globalization; using System.Text; using System.Threading; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +internal sealed class Amd0FCpu : AmdCpu { - internal sealed class Amd0FCpu : AmdCpu + private readonly Sensor _busClock; + private readonly Sensor[] _coreClocks; + private readonly Sensor[] _coreTemperatures; + private readonly uint _miscellaneousControlAddress; + + private readonly byte _thermSenseCoreSelCPU0; + private readonly byte _thermSenseCoreSelCPU1; + + public Amd0FCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) { - private readonly Sensor _busClock; - private readonly Sensor[] _coreClocks; - private readonly Sensor[] _coreTemperatures; - private readonly uint _miscellaneousControlAddress; + float offset = -49.0f; - private readonly byte _thermSenseCoreSelCPU0; - private readonly byte _thermSenseCoreSelCPU1; + // AM2+ 65nm +21 offset + uint model = cpuId[0][0].Model; + if (model is >= 0x69 and not 0xc1 and not 0x6c and not 0x7c) + offset += 21; - public Amd0FCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) + if (model < 40) { - float offset = -49.0f; + // AMD Athlon 64 Processors + _thermSenseCoreSelCPU0 = 0x0; + _thermSenseCoreSelCPU1 = 0x4; + } + else + { + // AMD NPT Family 0Fh Revision F, G have the core selection swapped + _thermSenseCoreSelCPU0 = 0x4; + _thermSenseCoreSelCPU1 = 0x0; + } - // AM2+ 65nm +21 offset - uint model = cpuId[0][0].Model; - if (model is >= 0x69 and not 0xc1 and not 0x6c and not 0x7c) - offset += 21; - - if (model < 40) + // check if processor supports a digital thermal sensor + if (cpuId[0][0].ExtData.GetLength(0) > 7 && (cpuId[0][0].ExtData[7, 3] & 1) != 0) + { + _coreTemperatures = new Sensor[_coreCount]; + for (int i = 0; i < _coreCount; i++) { - // AMD Athlon 64 Processors - _thermSenseCoreSelCPU0 = 0x0; - _thermSenseCoreSelCPU1 = 0x4; - } - else - { - // AMD NPT Family 0Fh Revision F, G have the core selection swapped - _thermSenseCoreSelCPU0 = 0x4; - _thermSenseCoreSelCPU1 = 0x0; + _coreTemperatures[i] = new Sensor("Core #" + (i + 1), + i, + SensorType.Temperature, + this, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", offset) }, + settings); } + } + else + { + _coreTemperatures = Array.Empty(); + } - // check if processor supports a digital thermal sensor - if (cpuId[0][0].ExtData.GetLength(0) > 7 && (cpuId[0][0].ExtData[7, 3] & 1) != 0) + _miscellaneousControlAddress = GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, MISCELLANEOUS_CONTROL_DEVICE_ID); + _busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings); + _coreClocks = new Sensor[_coreCount]; + for (int i = 0; i < _coreClocks.Length; i++) + { + _coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); + if (HasTimeStampCounter) + ActivateSensor(_coreClocks[i]); + } + + Update(); + } + + protected override uint[] GetMsrs() + { + return new[] { FIDVID_STATUS }; + } + + public override string GetReport() + { + StringBuilder r = new(); + r.Append(base.GetReport()); + r.Append("Miscellaneous Control Address: 0x"); + r.AppendLine(_miscellaneousControlAddress.ToString("X", CultureInfo.InvariantCulture)); + r.AppendLine(); + return r.ToString(); + } + + public override void Update() + { + base.Update(); + + if (Ring0.WaitPciBusMutex(10)) + { + if (_miscellaneousControlAddress != Interop.Ring0.INVALID_PCI_ADDRESS) { - _coreTemperatures = new Sensor[_coreCount]; - for (int i = 0; i < _coreCount; i++) + for (uint i = 0; i < _coreTemperatures.Length; i++) { - _coreTemperatures[i] = new Sensor("Core #" + (i + 1), - i, - SensorType.Temperature, - this, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", offset) }, - settings); - } - } - else - { - _coreTemperatures = Array.Empty(); - } - - _miscellaneousControlAddress = GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, MISCELLANEOUS_CONTROL_DEVICE_ID); - _busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings); - _coreClocks = new Sensor[_coreCount]; - for (int i = 0; i < _coreClocks.Length; i++) - { - _coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); - if (HasTimeStampCounter) - ActivateSensor(_coreClocks[i]); - } - - Update(); - } - - protected override uint[] GetMsrs() - { - return new[] { FIDVID_STATUS }; - } - - public override string GetReport() - { - StringBuilder r = new(); - r.Append(base.GetReport()); - r.Append("Miscellaneous Control Address: 0x"); - r.AppendLine(_miscellaneousControlAddress.ToString("X", CultureInfo.InvariantCulture)); - r.AppendLine(); - return r.ToString(); - } - - public override void Update() - { - base.Update(); - - if (Ring0.WaitPciBusMutex(10)) - { - if (_miscellaneousControlAddress != Interop.Ring0.INVALID_PCI_ADDRESS) - { - for (uint i = 0; i < _coreTemperatures.Length; i++) + if (Ring0.WritePciConfig(_miscellaneousControlAddress, + THERMTRIP_STATUS_REGISTER, + i > 0 ? _thermSenseCoreSelCPU1 : _thermSenseCoreSelCPU0)) { - if (Ring0.WritePciConfig(_miscellaneousControlAddress, - THERMTRIP_STATUS_REGISTER, - i > 0 ? _thermSenseCoreSelCPU1 : _thermSenseCoreSelCPU0)) + if (Ring0.ReadPciConfig(_miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER, out uint value)) { - if (Ring0.ReadPciConfig(_miscellaneousControlAddress, THERMTRIP_STATUS_REGISTER, out uint value)) - { - _coreTemperatures[i].Value = ((value >> 16) & 0xFF) + _coreTemperatures[i].Parameters[0].Value; - ActivateSensor(_coreTemperatures[i]); - } - else - { - DeactivateSensor(_coreTemperatures[i]); - } + _coreTemperatures[i].Value = ((value >> 16) & 0xFF) + _coreTemperatures[i].Parameters[0].Value; + ActivateSensor(_coreTemperatures[i]); + } + else + { + DeactivateSensor(_coreTemperatures[i]); } } } - - Ring0.ReleasePciBusMutex(); } - if (HasTimeStampCounter) - { - double newBusClock = 0; - - for (int i = 0; i < _coreClocks.Length; i++) - { - Thread.Sleep(1); - - if (Ring0.ReadMsr(FIDVID_STATUS, out uint eax, out uint _, _cpuId[i][0].Affinity)) - { - // CurrFID can be found in eax bits 0-5, MaxFID in 16-21 - // 8-13 hold StartFID, we don't use that here. - double curMp = 0.5 * ((eax & 0x3F) + 8); - double maxMp = 0.5 * ((eax >> 16 & 0x3F) + 8); - _coreClocks[i].Value = (float)(curMp * TimeStampCounterFrequency / maxMp); - newBusClock = (float)(TimeStampCounterFrequency / maxMp); - } - else - { - // Fail-safe value - if the code above fails, we'll use this instead - _coreClocks[i].Value = (float)TimeStampCounterFrequency; - } - } - - if (newBusClock > 0) - { - _busClock.Value = (float)newBusClock; - ActivateSensor(_busClock); - } - } + Ring0.ReleasePciBusMutex(); } - // ReSharper disable InconsistentNaming - private const uint FIDVID_STATUS = 0xC0010042; - private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1103; - private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3; - private const uint THERMTRIP_STATUS_REGISTER = 0xE4; - // ReSharper restore InconsistentNaming + if (HasTimeStampCounter) + { + double newBusClock = 0; + + for (int i = 0; i < _coreClocks.Length; i++) + { + Thread.Sleep(1); + + if (Ring0.ReadMsr(FIDVID_STATUS, out uint eax, out uint _, _cpuId[i][0].Affinity)) + { + // CurrFID can be found in eax bits 0-5, MaxFID in 16-21 + // 8-13 hold StartFID, we don't use that here. + double curMp = 0.5 * ((eax & 0x3F) + 8); + double maxMp = 0.5 * ((eax >> 16 & 0x3F) + 8); + _coreClocks[i].Value = (float)(curMp * TimeStampCounterFrequency / maxMp); + newBusClock = (float)(TimeStampCounterFrequency / maxMp); + } + else + { + // Fail-safe value - if the code above fails, we'll use this instead + _coreClocks[i].Value = (float)TimeStampCounterFrequency; + } + } + + if (newBusClock > 0) + { + _busClock.Value = (float)newBusClock; + ActivateSensor(_busClock); + } + } } -} + + // ReSharper disable InconsistentNaming + private const uint FIDVID_STATUS = 0xC0010042; + private const ushort MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1103; + private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3; + private const uint THERMTRIP_STATUS_REGISTER = 0xE4; + // ReSharper restore InconsistentNaming +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs index 8995fa9..6483d14 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/Amd10Cpu.cs @@ -12,358 +12,353 @@ using System.IO; using System.Text; using System.Threading; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +internal sealed class Amd10Cpu : AmdCpu { - internal sealed class Amd10Cpu : AmdCpu + private readonly Sensor _busClock; + private readonly Sensor[] _coreClocks; + private readonly Sensor _coreTemperature; + private readonly Sensor _coreVoltage; + private readonly byte _cStatesIoOffset; + private readonly Sensor[] _cStatesResidency; + private readonly bool _hasSmuTemperatureRegister; + private readonly bool _isSvi2; + private readonly uint _miscellaneousControlAddress; + private readonly Sensor _northbridgeVoltage; + private readonly FileStream _temperatureStream; + private readonly double _timeStampCounterMultiplier; + + public Amd10Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) { - private readonly Sensor _busClock; - private readonly Sensor[] _coreClocks; - private readonly Sensor _coreTemperature; - private readonly Sensor _coreVoltage; - private readonly byte _cStatesIoOffset; - private readonly Sensor[] _cStatesResidency; - private readonly bool _hasSmuTemperatureRegister; - private readonly bool _isSvi2; - private readonly uint _miscellaneousControlAddress; - private readonly Sensor _northbridgeVoltage; - private readonly FileStream _temperatureStream; - private readonly double _timeStampCounterMultiplier; + // AMD family 1Xh processors support only one temperature sensor + ushort miscellaneousControlDeviceId; + _coreTemperature = new Sensor("CPU Cores", 0, SensorType.Temperature, this, new[] { new ParameterDescription("Offset [°C]", "Temperature offset.", 0) }, settings); + _coreVoltage = new Sensor("CPU Cores", 0, SensorType.Voltage, this, settings); + ActivateSensor(_coreVoltage); + _northbridgeVoltage = new Sensor("Northbridge", 0, SensorType.Voltage, this, settings); + ActivateSensor(_northbridgeVoltage); - public Amd10Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) + _isSvi2 = (_family == 0x15 && _model >= 0x10) || _family == 0x16; + + switch (_family) { - // AMD family 1Xh processors support only one temperature sensor - ushort miscellaneousControlDeviceId; - _coreTemperature = new Sensor("CPU Cores", 0, SensorType.Temperature, this, new[] { new ParameterDescription("Offset [°C]", "Temperature offset.", 0) }, settings); - _coreVoltage = new Sensor("CPU Cores", 0, SensorType.Voltage, this, settings); - ActivateSensor(_coreVoltage); - _northbridgeVoltage = new Sensor("Northbridge", 0, SensorType.Voltage, this, settings); - ActivateSensor(_northbridgeVoltage); - - _isSvi2 = (_family == 0x15 && _model >= 0x10) || _family == 0x16; - - switch (_family) - { - case 0x10: - miscellaneousControlDeviceId = FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID; - break; - case 0x11: - miscellaneousControlDeviceId = FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID; - break; - case 0x12: - miscellaneousControlDeviceId = FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID; - break; - case 0x14: - miscellaneousControlDeviceId = FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID; - break; - case 0x15: - switch (_model & 0xF0) - { - case 0x00: - miscellaneousControlDeviceId = FAMILY_15H_MODEL_00_MISC_CONTROL_DEVICE_ID; - break; - case 0x10: - miscellaneousControlDeviceId = FAMILY_15H_MODEL_10_MISC_CONTROL_DEVICE_ID; - break; - case 0x30: - miscellaneousControlDeviceId = FAMILY_15H_MODEL_30_MISC_CONTROL_DEVICE_ID; - break; - case 0x70: - miscellaneousControlDeviceId = FAMILY_15H_MODEL_70_MISC_CONTROL_DEVICE_ID; - _hasSmuTemperatureRegister = true; - break; - case 0x60: - miscellaneousControlDeviceId = FAMILY_15H_MODEL_60_MISC_CONTROL_DEVICE_ID; - _hasSmuTemperatureRegister = true; - break; - default: - miscellaneousControlDeviceId = 0; - break; - } - - break; - case 0x16: - miscellaneousControlDeviceId = (_model & 0xF0) switch - { - 0x00 => FAMILY_16H_MODEL_00_MISC_CONTROL_DEVICE_ID, - 0x30 => FAMILY_16H_MODEL_30_MISC_CONTROL_DEVICE_ID, - _ => 0 - }; - break; - default: - miscellaneousControlDeviceId = 0; - break; - } - - // get the pci address for the Miscellaneous Control registers - _miscellaneousControlAddress = GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, miscellaneousControlDeviceId); - _busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings); - _coreClocks = new Sensor[_coreCount]; - for (int i = 0; i < _coreClocks.Length; i++) - { - _coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); - if (HasTimeStampCounter) - ActivateSensor(_coreClocks[i]); - } - - bool corePerformanceBoostSupport = (cpuId[0][0].ExtData[7, 3] & (1 << 9)) > 0; - - // set affinity to the first thread for all frequency estimations - GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId[0][0].Affinity); - - // disable core performance boost - Ring0.ReadMsr(HWCR, out uint hwcrEax, out uint hwcrEdx); - if (corePerformanceBoostSupport) - Ring0.WriteMsr(HWCR, hwcrEax | (1 << 25), hwcrEdx); - - Ring0.ReadMsr(PERF_CTL_0, out uint ctlEax, out uint ctlEdx); - Ring0.ReadMsr(PERF_CTR_0, out uint ctrEax, out uint ctrEdx); - - _timeStampCounterMultiplier = EstimateTimeStampCounterMultiplier(); - - // restore the performance counter registers - Ring0.WriteMsr(PERF_CTL_0, ctlEax, ctlEdx); - Ring0.WriteMsr(PERF_CTR_0, ctrEax, ctrEdx); - - // restore core performance boost - if (corePerformanceBoostSupport) - Ring0.WriteMsr(HWCR, hwcrEax, hwcrEdx); - - // restore the thread affinity. - ThreadAffinity.Set(previousAffinity); - - // the file reader for lm-sensors support on Linux - _temperatureStream = null; - - if (Software.OperatingSystem.IsUnix) - { - foreach (string path in Directory.GetDirectories("/sys/class/hwmon/")) + case 0x10: + miscellaneousControlDeviceId = FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID; + break; + case 0x11: + miscellaneousControlDeviceId = FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID; + break; + case 0x12: + miscellaneousControlDeviceId = FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID; + break; + case 0x14: + miscellaneousControlDeviceId = FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID; + break; + case 0x15: + switch (_model & 0xF0) { - string name = null; - try - { - using StreamReader reader = new(path + "/device/name"); - - name = reader.ReadLine(); - } - catch (IOException) - { } - - _temperatureStream = name switch - { - "k10temp" => new FileStream(path + "/device/temp1_input", FileMode.Open, FileAccess.Read, FileShare.ReadWrite), - _ => _temperatureStream - }; + case 0x00: + miscellaneousControlDeviceId = FAMILY_15H_MODEL_00_MISC_CONTROL_DEVICE_ID; + break; + case 0x10: + miscellaneousControlDeviceId = FAMILY_15H_MODEL_10_MISC_CONTROL_DEVICE_ID; + break; + case 0x30: + miscellaneousControlDeviceId = FAMILY_15H_MODEL_30_MISC_CONTROL_DEVICE_ID; + break; + case 0x70: + miscellaneousControlDeviceId = FAMILY_15H_MODEL_70_MISC_CONTROL_DEVICE_ID; + _hasSmuTemperatureRegister = true; + break; + case 0x60: + miscellaneousControlDeviceId = FAMILY_15H_MODEL_60_MISC_CONTROL_DEVICE_ID; + _hasSmuTemperatureRegister = true; + break; + default: + miscellaneousControlDeviceId = 0; + break; } - } - uint addr = Ring0.GetPciAddress(0, 20, 0); - if (Ring0.ReadPciConfig(addr, 0, out uint dev)) - { - Ring0.ReadPciConfig(addr, 8, out uint rev); - - _cStatesIoOffset = dev switch + break; + case 0x16: + miscellaneousControlDeviceId = (_model & 0xF0) switch { - 0x43851002 => (byte)((rev & 0xFF) < 0x40 ? 0xB3 : 0x9C), - 0x780B1022 or 0x790B1022 => 0x9C, - _ => _cStatesIoOffset + 0x00 => FAMILY_16H_MODEL_00_MISC_CONTROL_DEVICE_ID, + 0x30 => FAMILY_16H_MODEL_30_MISC_CONTROL_DEVICE_ID, + _ => 0 + }; + break; + default: + miscellaneousControlDeviceId = 0; + break; + } + + // get the pci address for the Miscellaneous Control registers + _miscellaneousControlAddress = GetPciAddress(MISCELLANEOUS_CONTROL_FUNCTION, miscellaneousControlDeviceId); + _busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings); + _coreClocks = new Sensor[_coreCount]; + for (int i = 0; i < _coreClocks.Length; i++) + { + _coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); + if (HasTimeStampCounter) + ActivateSensor(_coreClocks[i]); + } + + bool corePerformanceBoostSupport = (cpuId[0][0].ExtData[7, 3] & (1 << 9)) > 0; + + // set affinity to the first thread for all frequency estimations + GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId[0][0].Affinity); + + // disable core performance boost + Ring0.ReadMsr(HWCR, out uint hwcrEax, out uint hwcrEdx); + if (corePerformanceBoostSupport) + Ring0.WriteMsr(HWCR, hwcrEax | (1 << 25), hwcrEdx); + + Ring0.ReadMsr(PERF_CTL_0, out uint ctlEax, out uint ctlEdx); + Ring0.ReadMsr(PERF_CTR_0, out uint ctrEax, out uint ctrEdx); + + _timeStampCounterMultiplier = EstimateTimeStampCounterMultiplier(); + + // restore the performance counter registers + Ring0.WriteMsr(PERF_CTL_0, ctlEax, ctlEdx); + Ring0.WriteMsr(PERF_CTR_0, ctrEax, ctrEdx); + + // restore core performance boost + if (corePerformanceBoostSupport) + Ring0.WriteMsr(HWCR, hwcrEax, hwcrEdx); + + // restore the thread affinity. + ThreadAffinity.Set(previousAffinity); + + // the file reader for lm-sensors support on Linux + _temperatureStream = null; + + if (Software.OperatingSystem.IsUnix) + { + foreach (string path in Directory.GetDirectories("/sys/class/hwmon/")) + { + string name = null; + try + { + using StreamReader reader = new(path + "/device/name"); + + name = reader.ReadLine(); + } + catch (IOException) + { } + + _temperatureStream = name switch + { + "k10temp" => new FileStream(path + "/device/temp1_input", FileMode.Open, FileAccess.Read, FileShare.ReadWrite), + _ => _temperatureStream }; } + } - if (_cStatesIoOffset != 0) + uint addr = Ring0.GetPciAddress(0, 20, 0); + if (Ring0.ReadPciConfig(addr, 0, out uint dev)) + { + Ring0.ReadPciConfig(addr, 8, out uint rev); + + _cStatesIoOffset = dev switch { - _cStatesResidency = new[] { new Sensor("CPU Package C2", 0, SensorType.Level, this, settings), new Sensor("CPU Package C3", 1, SensorType.Level, this, settings) }; - ActivateSensor(_cStatesResidency[0]); - ActivateSensor(_cStatesResidency[1]); - } - - Update(); + 0x43851002 => (byte)((rev & 0xFF) < 0x40 ? 0xB3 : 0x9C), + 0x780B1022 or 0x790B1022 => 0x9C, + _ => _cStatesIoOffset + }; } - private double EstimateTimeStampCounterMultiplier() + if (_cStatesIoOffset != 0) { - // preload the function - EstimateTimeStampCounterMultiplier(0); - EstimateTimeStampCounterMultiplier(0); - - // estimate the multiplier - List estimate = new(3); - for (int i = 0; i < 3; i++) - estimate.Add(EstimateTimeStampCounterMultiplier(0.025)); - - estimate.Sort(); - return estimate[1]; + _cStatesResidency = new[] { new Sensor("CPU Package C2", 0, SensorType.Level, this, settings), new Sensor("CPU Package C3", 1, SensorType.Level, this, settings) }; + ActivateSensor(_cStatesResidency[0]); + ActivateSensor(_cStatesResidency[1]); } - private double EstimateTimeStampCounterMultiplier(double timeWindow) + Update(); + } + + private double EstimateTimeStampCounterMultiplier() + { + // preload the function + EstimateTimeStampCounterMultiplier(0); + EstimateTimeStampCounterMultiplier(0); + + // estimate the multiplier + List estimate = new(3); + for (int i = 0; i < 3; i++) + estimate.Add(EstimateTimeStampCounterMultiplier(0.025)); + + estimate.Sort(); + return estimate[1]; + } + + private double EstimateTimeStampCounterMultiplier(double timeWindow) + { + // select event "076h CPU Clocks not Halted" and enable the counter + Ring0.WriteMsr(PERF_CTL_0, + (1 << 22) | // enable performance counter + (1 << 17) | // count events in user mode + (1 << 16) | // count events in operating-system mode + 0x76, + 0x00000000); + + // set the counter to 0 + Ring0.WriteMsr(PERF_CTR_0, 0, 0); + + long ticks = (long)(timeWindow * Stopwatch.Frequency); + + long timeBegin = Stopwatch.GetTimestamp() + + (long)Math.Ceiling(0.001 * ticks); + + long timeEnd = timeBegin + ticks; + while (Stopwatch.GetTimestamp() < timeBegin) + { } + + Ring0.ReadMsr(PERF_CTR_0, out uint lsbBegin, out uint msbBegin); + + while (Stopwatch.GetTimestamp() < timeEnd) + { } + + Ring0.ReadMsr(PERF_CTR_0, out uint lsbEnd, out uint msbEnd); + Ring0.ReadMsr(COFVID_STATUS, out uint eax, out uint _); + double coreMultiplier = GetCoreMultiplier(eax); + + ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin; + ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd; + + double coreFrequency = 1e-6 * ((double)(countEnd - countBegin) * Stopwatch.Frequency) / (timeEnd - timeBegin); + double busFrequency = coreFrequency / coreMultiplier; + return 0.25 * Math.Round(4 * TimeStampCounterFrequency / busFrequency); + } + + protected override uint[] GetMsrs() + { + return new[] { PERF_CTL_0, PERF_CTR_0, HWCR, P_STATE_0, COFVID_STATUS }; + } + + public override string GetReport() + { + StringBuilder r = new(); + r.Append(base.GetReport()); + r.Append("Miscellaneous Control Address: 0x"); + r.AppendLine(_miscellaneousControlAddress.ToString("X", CultureInfo.InvariantCulture)); + r.Append("Time Stamp Counter Multiplier: "); + r.AppendLine(_timeStampCounterMultiplier.ToString(CultureInfo.InvariantCulture)); + if (_family == 0x14) { - // select event "076h CPU Clocks not Halted" and enable the counter - Ring0.WriteMsr(PERF_CTL_0, - (1 << 22) | // enable performance counter - (1 << 17) | // count events in user mode - (1 << 16) | // count events in operating-system mode - 0x76, - 0x00000000); - - // set the counter to 0 - Ring0.WriteMsr(PERF_CTR_0, 0, 0); - - long ticks = (long)(timeWindow * Stopwatch.Frequency); - - long timeBegin = Stopwatch.GetTimestamp() + - (long)Math.Ceiling(0.001 * ticks); - - long timeEnd = timeBegin + ticks; - while (Stopwatch.GetTimestamp() < timeBegin) - { } - - Ring0.ReadMsr(PERF_CTR_0, out uint lsbBegin, out uint msbBegin); - - while (Stopwatch.GetTimestamp() < timeEnd) - { } - - Ring0.ReadMsr(PERF_CTR_0, out uint lsbEnd, out uint msbEnd); - Ring0.ReadMsr(COFVID_STATUS, out uint eax, out uint _); - double coreMultiplier = GetCoreMultiplier(eax); - - ulong countBegin = ((ulong)msbBegin << 32) | lsbBegin; - ulong countEnd = ((ulong)msbEnd << 32) | lsbEnd; - - double coreFrequency = 1e-6 * ((double)(countEnd - countBegin) * Stopwatch.Frequency) / (timeEnd - timeBegin); - double busFrequency = coreFrequency / coreMultiplier; - return 0.25 * Math.Round(4 * TimeStampCounterFrequency / busFrequency); + Ring0.ReadPciConfig(_miscellaneousControlAddress, CLOCK_POWER_TIMING_CONTROL_0_REGISTER, out uint value); + r.Append("PCI Register D18F3xD4: "); + r.AppendLine(value.ToString("X8", CultureInfo.InvariantCulture)); } - protected override uint[] GetMsrs() - { - return new[] { PERF_CTL_0, PERF_CTR_0, HWCR, P_STATE_0, COFVID_STATUS }; - } + r.AppendLine(); + return r.ToString(); + } - public override string GetReport() + private double GetCoreMultiplier(uint cofVidEax) + { + uint cpuDid; + uint cpuFid; + + switch (_family) { - StringBuilder r = new(); - r.Append(base.GetReport()); - r.Append("Miscellaneous Control Address: 0x"); - r.AppendLine(_miscellaneousControlAddress.ToString("X", CultureInfo.InvariantCulture)); - r.Append("Time Stamp Counter Multiplier: "); - r.AppendLine(_timeStampCounterMultiplier.ToString(CultureInfo.InvariantCulture)); - if (_family == 0x14) - { + case 0x10: + case 0x11: + case 0x15: + case 0x16: + // 8:6 CpuDid: current core divisor ID + // 5:0 CpuFid: current core frequency ID + cpuDid = (cofVidEax >> 6) & 7; + cpuFid = cofVidEax & 0x1F; + return 0.5 * (cpuFid + 0x10) / (1 << (int)cpuDid); + + case 0x12: + // 8:4 CpuFid: current CPU core frequency ID + // 3:0 CpuDid: current CPU core divisor ID + cpuFid = (cofVidEax >> 4) & 0x1F; + cpuDid = cofVidEax & 0xF; + double divisor = cpuDid switch + { + 0 => 1, + 1 => 1.5, + 2 => 2, + 3 => 3, + 4 => 4, + 5 => 6, + 6 => 8, + 7 => 12, + 8 => 16, + _ => 1 + }; + return (cpuFid + 0x10) / divisor; + + case 0x14: + // 8:4: current CPU core divisor ID most significant digit + // 3:0: current CPU core divisor ID least significant digit + uint divisorIdMsd = (cofVidEax >> 4) & 0x1F; + uint divisorIdLsd = cofVidEax & 0xF; Ring0.ReadPciConfig(_miscellaneousControlAddress, CLOCK_POWER_TIMING_CONTROL_0_REGISTER, out uint value); - r.Append("PCI Register D18F3xD4: "); - r.AppendLine(value.ToString("X8", CultureInfo.InvariantCulture)); - } + uint frequencyId = value & 0x1F; + return (frequencyId + 0x10) / (divisorIdMsd + (divisorIdLsd * 0.25) + 1); - r.AppendLine(); - return r.ToString(); + default: + return 1; } + } - private double GetCoreMultiplier(uint cofVidEax) + private static string ReadFirstLine(Stream stream) + { + StringBuilder stringBuilder = new(); + + try { - uint cpuDid; - uint cpuFid; - - switch (_family) + stream.Seek(0, SeekOrigin.Begin); + int b = stream.ReadByte(); + while (b is not -1 and not 10) { - case 0x10: - case 0x11: - case 0x15: - case 0x16: - // 8:6 CpuDid: current core divisor ID - // 5:0 CpuFid: current core frequency ID - cpuDid = (cofVidEax >> 6) & 7; - cpuFid = cofVidEax & 0x1F; - return 0.5 * (cpuFid + 0x10) / (1 << (int)cpuDid); - - case 0x12: - // 8:4 CpuFid: current CPU core frequency ID - // 3:0 CpuDid: current CPU core divisor ID - cpuFid = (cofVidEax >> 4) & 0x1F; - cpuDid = cofVidEax & 0xF; - double divisor = cpuDid switch - { - 0 => 1, - 1 => 1.5, - 2 => 2, - 3 => 3, - 4 => 4, - 5 => 6, - 6 => 8, - 7 => 12, - 8 => 16, - _ => 1 - }; - return (cpuFid + 0x10) / divisor; - - case 0x14: - // 8:4: current CPU core divisor ID most significant digit - // 3:0: current CPU core divisor ID least significant digit - uint divisorIdMsd = (cofVidEax >> 4) & 0x1F; - uint divisorIdLsd = cofVidEax & 0xF; - Ring0.ReadPciConfig(_miscellaneousControlAddress, CLOCK_POWER_TIMING_CONTROL_0_REGISTER, out uint value); - uint frequencyId = value & 0x1F; - return (frequencyId + 0x10) / (divisorIdMsd + (divisorIdLsd * 0.25) + 1); - - default: - return 1; + stringBuilder.Append((char)b); + b = stream.ReadByte(); } } + catch + { } - private static string ReadFirstLine(Stream stream) + return stringBuilder.ToString(); + } + + public override void Update() + { + base.Update(); + + if (_temperatureStream == null) { - StringBuilder stringBuilder = new(); - - try + if (_miscellaneousControlAddress != Interop.Ring0.INVALID_PCI_ADDRESS) { - stream.Seek(0, SeekOrigin.Begin); - int b = stream.ReadByte(); - while (b is not -1 and not 10) + bool isValueValid = _hasSmuTemperatureRegister + ? ReadSmuRegister(SMU_REPORTED_TEMP_CTRL_OFFSET, out uint value) + : Ring0.ReadPciConfig(_miscellaneousControlAddress, REPORTED_TEMPERATURE_CONTROL_REGISTER, out value); + + if (isValueValid) { - stringBuilder.Append((char)b); - b = stream.ReadByte(); - } - } - catch - { } - - return stringBuilder.ToString(); - } - - public override void Update() - { - base.Update(); - - if (_temperatureStream == null) - { - if (_miscellaneousControlAddress != Interop.Ring0.INVALID_PCI_ADDRESS) - { - bool isValueValid = _hasSmuTemperatureRegister - ? ReadSmuRegister(SMU_REPORTED_TEMP_CTRL_OFFSET, out uint value) - : Ring0.ReadPciConfig(_miscellaneousControlAddress, REPORTED_TEMPERATURE_CONTROL_REGISTER, out value); - - if (isValueValid) + if ((_family == 0x15 || _family == 0x16) && (value & 0x30000) == 0x3000) { - if ((_family == 0x15 || _family == 0x16) && (value & 0x30000) == 0x3000) + if (_family == 0x15 && (_model & 0xF0) == 0x00) { - if (_family == 0x15 && (_model & 0xF0) == 0x00) - { - _coreTemperature.Value = (((value >> 21) & 0x7FC) / 8.0f) + _coreTemperature.Parameters[0].Value - 49; - } - else - { - _coreTemperature.Value = (((value >> 21) & 0x7FF) / 8.0f) + _coreTemperature.Parameters[0].Value - 49; - } + _coreTemperature.Value = (((value >> 21) & 0x7FC) / 8.0f) + _coreTemperature.Parameters[0].Value - 49; } else { - _coreTemperature.Value = (((value >> 21) & 0x7FF) / 8.0f) + _coreTemperature.Parameters[0].Value; + _coreTemperature.Value = (((value >> 21) & 0x7FF) / 8.0f) + _coreTemperature.Parameters[0].Value - 49; } - - ActivateSensor(_coreTemperature); } else { - DeactivateSensor(_coreTemperature); + _coreTemperature.Value = (((value >> 21) & 0x7FF) / 8.0f) + _coreTemperature.Parameters[0].Value; } + + ActivateSensor(_coreTemperature); } else { @@ -372,134 +367,138 @@ namespace LibreHardwareMonitor.Hardware.CPU } else { - string s = ReadFirstLine(_temperatureStream); - try - { - _coreTemperature.Value = 0.001f * long.Parse(s, CultureInfo.InvariantCulture); - ActivateSensor(_coreTemperature); - } - catch - { - DeactivateSensor(_coreTemperature); - } + DeactivateSensor(_coreTemperature); } - - if (HasTimeStampCounter) + } + else + { + string s = ReadFirstLine(_temperatureStream); + try { - double newBusClock = 0; - float maxCoreVoltage = 0, maxNbVoltage = 0; - - for (int i = 0; i < _coreClocks.Length; i++) - { - Thread.Sleep(1); - - if (Ring0.ReadMsr(COFVID_STATUS, out uint curEax, out uint _, _cpuId[i][0].Affinity)) - { - double multiplier = GetCoreMultiplier(curEax); - - _coreClocks[i].Value = (float)(multiplier * TimeStampCounterFrequency / _timeStampCounterMultiplier); - newBusClock = (float)(TimeStampCounterFrequency / _timeStampCounterMultiplier); - } - else - { - _coreClocks[i].Value = (float)TimeStampCounterFrequency; - } - - float SVI2Volt(uint vid) => vid < 0b1111_1000 ? 1.5500f - (0.00625f * vid) : 0; - - float SVI1Volt(uint vid) => vid < 0x7C ? 1.550f - (0.0125f * vid) : 0; - - float newCoreVoltage, newNbVoltage; - uint coreVid60 = (curEax >> 9) & 0x7F; - if (_isSvi2) - { - newCoreVoltage = SVI2Volt((curEax >> 13 & 0x80) | coreVid60); - newNbVoltage = SVI2Volt(curEax >> 24); - } - else - { - newCoreVoltage = SVI1Volt(coreVid60); - newNbVoltage = SVI1Volt(curEax >> 25); - } - - if (newCoreVoltage > maxCoreVoltage) - maxCoreVoltage = newCoreVoltage; - - if (newNbVoltage > maxNbVoltage) - maxNbVoltage = newNbVoltage; - } - - _coreVoltage.Value = maxCoreVoltage; - _northbridgeVoltage.Value = maxNbVoltage; - - if (newBusClock > 0) - { - _busClock.Value = (float)newBusClock; - ActivateSensor(_busClock); - } + _coreTemperature.Value = 0.001f * long.Parse(s, CultureInfo.InvariantCulture); + ActivateSensor(_coreTemperature); } - - if (_cStatesResidency != null) + catch { - for (int i = 0; i < _cStatesResidency.Length; i++) - { - Ring0.WriteIoPort(CSTATES_IO_PORT, (byte)(_cStatesIoOffset + i)); - _cStatesResidency[i].Value = Ring0.ReadIoPort(CSTATES_IO_PORT + 1) / 256f * 100; - } + DeactivateSensor(_coreTemperature); } } - private static bool ReadSmuRegister(uint address, out uint value) + if (HasTimeStampCounter) { - if (Ring0.WaitPciBusMutex(10)) - { - if (!Ring0.WritePciConfig(0, 0xB8, address)) - { - value = 0; + double newBusClock = 0; + float maxCoreVoltage = 0, maxNbVoltage = 0; - Ring0.ReleasePciBusMutex(); - return false; + for (int i = 0; i < _coreClocks.Length; i++) + { + Thread.Sleep(1); + + if (Ring0.ReadMsr(COFVID_STATUS, out uint curEax, out uint _, _cpuId[i][0].Affinity)) + { + double multiplier = GetCoreMultiplier(curEax); + + _coreClocks[i].Value = (float)(multiplier * TimeStampCounterFrequency / _timeStampCounterMultiplier); + newBusClock = (float)(TimeStampCounterFrequency / _timeStampCounterMultiplier); + } + else + { + _coreClocks[i].Value = (float)TimeStampCounterFrequency; } - bool result = Ring0.ReadPciConfig(0, 0xBC, out value); + float SVI2Volt(uint vid) => vid < 0b1111_1000 ? 1.5500f - (0.00625f * vid) : 0; + + float SVI1Volt(uint vid) => vid < 0x7C ? 1.550f - (0.0125f * vid) : 0; + + float newCoreVoltage, newNbVoltage; + uint coreVid60 = (curEax >> 9) & 0x7F; + if (_isSvi2) + { + newCoreVoltage = SVI2Volt((curEax >> 13 & 0x80) | coreVid60); + newNbVoltage = SVI2Volt(curEax >> 24); + } + else + { + newCoreVoltage = SVI1Volt(coreVid60); + newNbVoltage = SVI1Volt(curEax >> 25); + } + + if (newCoreVoltage > maxCoreVoltage) + maxCoreVoltage = newCoreVoltage; + + if (newNbVoltage > maxNbVoltage) + maxNbVoltage = newNbVoltage; + } + + _coreVoltage.Value = maxCoreVoltage; + _northbridgeVoltage.Value = maxNbVoltage; + + if (newBusClock > 0) + { + _busClock.Value = (float)newBusClock; + ActivateSensor(_busClock); + } + } + + if (_cStatesResidency != null) + { + for (int i = 0; i < _cStatesResidency.Length; i++) + { + Ring0.WriteIoPort(CSTATES_IO_PORT, (byte)(_cStatesIoOffset + i)); + _cStatesResidency[i].Value = Ring0.ReadIoPort(CSTATES_IO_PORT + 1) / 256f * 100; + } + } + } + + private static bool ReadSmuRegister(uint address, out uint value) + { + if (Ring0.WaitPciBusMutex(10)) + { + if (!Ring0.WritePciConfig(0, 0xB8, address)) + { + value = 0; Ring0.ReleasePciBusMutex(); - return result; + return false; } - value = 0; - return false; + bool result = Ring0.ReadPciConfig(0, 0xBC, out value); + + Ring0.ReleasePciBusMutex(); + return result; } - public override void Close() - { - _temperatureStream?.Close(); - base.Close(); - } - - // ReSharper disable InconsistentNaming - private const uint CLOCK_POWER_TIMING_CONTROL_0_REGISTER = 0xD4; - private const uint COFVID_STATUS = 0xC0010071; - private const uint CSTATES_IO_PORT = 0xCD6; - private const uint SMU_REPORTED_TEMP_CTRL_OFFSET = 0xD8200CA4; - private const uint HWCR = 0xC0010015; - private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3; - private const uint P_STATE_0 = 0xC0010064; - private const uint PERF_CTL_0 = 0xC0010000; - private const uint PERF_CTR_0 = 0xC0010004; - private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4; - - private const ushort FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203; - private const ushort FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1303; - private const ushort FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703; - private const ushort FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703; - private const ushort FAMILY_15H_MODEL_00_MISC_CONTROL_DEVICE_ID = 0x1603; - private const ushort FAMILY_15H_MODEL_10_MISC_CONTROL_DEVICE_ID = 0x1403; - private const ushort FAMILY_15H_MODEL_30_MISC_CONTROL_DEVICE_ID = 0x141D; - private const ushort FAMILY_15H_MODEL_60_MISC_CONTROL_DEVICE_ID = 0x1573; - private const ushort FAMILY_15H_MODEL_70_MISC_CONTROL_DEVICE_ID = 0x15B3; - private const ushort FAMILY_16H_MODEL_00_MISC_CONTROL_DEVICE_ID = 0x1533; - private const ushort FAMILY_16H_MODEL_30_MISC_CONTROL_DEVICE_ID = 0x1583; - // ReSharper restore InconsistentNaming + value = 0; + return false; } + + public override void Close() + { + _temperatureStream?.Close(); + base.Close(); + } + + // ReSharper disable InconsistentNaming + private const uint CLOCK_POWER_TIMING_CONTROL_0_REGISTER = 0xD4; + private const uint COFVID_STATUS = 0xC0010071; + private const uint CSTATES_IO_PORT = 0xCD6; + private const uint SMU_REPORTED_TEMP_CTRL_OFFSET = 0xD8200CA4; + private const uint HWCR = 0xC0010015; + private const byte MISCELLANEOUS_CONTROL_FUNCTION = 3; + private const uint P_STATE_0 = 0xC0010064; + private const uint PERF_CTL_0 = 0xC0010000; + private const uint PERF_CTR_0 = 0xC0010004; + private const uint REPORTED_TEMPERATURE_CONTROL_REGISTER = 0xA4; + + private const ushort FAMILY_10H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1203; + private const ushort FAMILY_11H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1303; + private const ushort FAMILY_12H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703; + private const ushort FAMILY_14H_MISCELLANEOUS_CONTROL_DEVICE_ID = 0x1703; + private const ushort FAMILY_15H_MODEL_00_MISC_CONTROL_DEVICE_ID = 0x1603; + private const ushort FAMILY_15H_MODEL_10_MISC_CONTROL_DEVICE_ID = 0x1403; + private const ushort FAMILY_15H_MODEL_30_MISC_CONTROL_DEVICE_ID = 0x141D; + private const ushort FAMILY_15H_MODEL_60_MISC_CONTROL_DEVICE_ID = 0x1573; + private const ushort FAMILY_15H_MODEL_70_MISC_CONTROL_DEVICE_ID = 0x15B3; + private const ushort FAMILY_16H_MODEL_00_MISC_CONTROL_DEVICE_ID = 0x1533; + private const ushort FAMILY_16H_MODEL_30_MISC_CONTROL_DEVICE_ID = 0x1583; + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs index 2c847d7..4cb37fb 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/Amd17Cpu.cs @@ -8,540 +8,213 @@ using System.Collections.Generic; using System.Linq; using System.Text; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +internal sealed class Amd17Cpu : AmdCpu { - internal sealed class Amd17Cpu : AmdCpu + private readonly Processor _processor; + private readonly Dictionary _sensorTypeIndex; + private readonly RyzenSMU _smu; + + public Amd17Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) { - private readonly Processor _processor; - private readonly Dictionary _sensorTypeIndex; - private readonly RyzenSMU _smu; - - public Amd17Cpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) + _sensorTypeIndex = new Dictionary(); + foreach (SensorType type in Enum.GetValues(typeof(SensorType))) { - _sensorTypeIndex = new Dictionary(); - foreach (SensorType type in Enum.GetValues(typeof(SensorType))) + _sensorTypeIndex.Add(type, 0); + } + + _sensorTypeIndex[SensorType.Load] = _active.Count(x => x.SensorType == SensorType.Load); + + _smu = new RyzenSMU(_family, _model, _packageType); + + // Add all numa nodes. + // Register ..1E_2, [10:8] + 1 + _processor = new Processor(this); + + // Add all numa nodes. + int coreId = 0; + int lastCoreId = -1; // Invalid id. + + // Ryzen 3000's skip some core ids. + // So start at 1 and count upwards when the read core changes. + foreach (CpuId[] cpu in cpuId.OrderBy(x => x[0].ExtData[0x1e, 1] & 0xFF)) + { + CpuId thread = cpu[0]; + + // CPUID_Fn8000001E_EBX, Register ..1E_1, [7:0] + // threads per core = CPUID_Fn8000001E_EBX[15:8] + 1 + // CoreId: core ID = CPUID_Fn8000001E_EBX[7:0] + int coreIdRead = (int)(thread.ExtData[0x1e, 1] & 0xff); + + // CPUID_Fn8000001E_ECX, Node Identifiers, Register ..1E_2 + // NodesPerProcessor = CPUID_Fn8000001E_ECX[10:8] + // nodeID = CPUID_Fn8000001E_ECX[7:0] + int nodeId = (int)(thread.ExtData[0x1e, 2] & 0xff); + + if (coreIdRead != lastCoreId) { - _sensorTypeIndex.Add(type, 0); + coreId++; } - _sensorTypeIndex[SensorType.Load] = _active.Count(x => x.SensorType == SensorType.Load); + lastCoreId = coreIdRead; - _smu = new RyzenSMU(_family, _model, _packageType); + _processor.AppendThread(thread, nodeId, coreId); + } - // Add all numa nodes. - // Register ..1E_2, [10:8] + 1 - _processor = new Processor(this); + Update(); + } - // Add all numa nodes. - int coreId = 0; - int lastCoreId = -1; // Invalid id. + protected override uint[] GetMsrs() + { + return new[] { PERF_CTL_0, PERF_CTR_0, HWCR, MSR_PSTATE_0, COFVID_STATUS }; + } - // Ryzen 3000's skip some core ids. - // So start at 1 and count upwards when the read core changes. - foreach (CpuId[] cpu in cpuId.OrderBy(x => x[0].ExtData[0x1e, 1] & 0xFF)) + public override string GetReport() + { + StringBuilder r = new(); + r.Append(base.GetReport()); + r.Append(_smu.GetReport()); + return r.ToString(); + } + + public override void Update() + { + base.Update(); + + _processor.UpdateSensors(); + + foreach (NumaNode node in _processor.Nodes) + { + NumaNode.UpdateSensors(); + + foreach (Core c in node.Cores) { - CpuId thread = cpu[0]; - - // CPUID_Fn8000001E_EBX, Register ..1E_1, [7:0] - // threads per core = CPUID_Fn8000001E_EBX[15:8] + 1 - // CoreId: core ID = CPUID_Fn8000001E_EBX[7:0] - int coreIdRead = (int)(thread.ExtData[0x1e, 1] & 0xff); - - // CPUID_Fn8000001E_ECX, Node Identifiers, Register ..1E_2 - // NodesPerProcessor = CPUID_Fn8000001E_ECX[10:8] - // nodeID = CPUID_Fn8000001E_ECX[7:0] - int nodeId = (int)(thread.ExtData[0x1e, 2] & 0xff); - - if (coreIdRead != lastCoreId) - { - coreId++; - } - - lastCoreId = coreIdRead; - - _processor.AppendThread(thread, nodeId, coreId); + c.UpdateSensors(); } - - Update(); } + } - protected override uint[] GetMsrs() + private class Processor + { + private readonly Sensor _busClock; + private readonly Sensor[] _ccdTemperatures; + private readonly Sensor _coreTemperatureTctl; + private readonly Sensor _coreTemperatureTctlTdie; + private readonly Sensor _coreTemperatureTdie; + private readonly Sensor _coreVoltage; + private readonly Amd17Cpu _cpu; + private readonly Sensor _packagePower; + private readonly Dictionary, Sensor> _smuSensors = new(); + private readonly Sensor _socVoltage; + + private Sensor _ccdsAverageTemperature; + private Sensor _ccdsMaxTemperature; + private DateTime _lastPwrTime = new(0); + private uint _lastPwrValue; + + public Processor(Hardware hardware) { - return new[] { PERF_CTL_0, PERF_CTR_0, HWCR, MSR_PSTATE_0, COFVID_STATUS }; - } + _cpu = (Amd17Cpu)hardware; - public override string GetReport() - { - StringBuilder r = new(); - r.Append(base.GetReport()); - r.Append(_smu.GetReport()); - return r.ToString(); - } + _packagePower = new Sensor("Package", _cpu._sensorTypeIndex[SensorType.Power]++, SensorType.Power, _cpu, _cpu._settings); + _coreTemperatureTctl = new Sensor("Core (Tctl)", _cpu._sensorTypeIndex[SensorType.Temperature]++, SensorType.Temperature, _cpu, _cpu._settings); + _coreTemperatureTdie = new Sensor("Core (Tdie)", _cpu._sensorTypeIndex[SensorType.Temperature]++, SensorType.Temperature, _cpu, _cpu._settings); + _coreTemperatureTctlTdie = new Sensor("Core (Tctl/Tdie)", _cpu._sensorTypeIndex[SensorType.Temperature]++, SensorType.Temperature, _cpu, _cpu._settings); + _ccdTemperatures = new Sensor[8]; // Hardcoded until there's a way to get max CCDs. + _coreVoltage = new Sensor("Core (SVI2 TFN)", _cpu._sensorTypeIndex[SensorType.Voltage]++, SensorType.Voltage, _cpu, _cpu._settings); + _socVoltage = new Sensor("SoC (SVI2 TFN)", _cpu._sensorTypeIndex[SensorType.Voltage]++, SensorType.Voltage, _cpu, _cpu._settings); + _busClock = new Sensor("Bus Speed", _cpu._sensorTypeIndex[SensorType.Clock]++, SensorType.Clock, _cpu, _cpu._settings); - public override void Update() - { - base.Update(); + _cpu.ActivateSensor(_packagePower); - _processor.UpdateSensors(); - - foreach (NumaNode node in _processor.Nodes) + foreach (KeyValuePair sensor in _cpu._smu.GetPmTableStructure()) { - NumaNode.UpdateSensors(); - - foreach (Core c in node.Cores) - { - c.UpdateSensors(); - } + _smuSensors.Add(sensor, new Sensor(sensor.Value.Name, _cpu._sensorTypeIndex[sensor.Value.Type]++, sensor.Value.Type, _cpu, _cpu._settings)); } } - private class Processor + public List Nodes { get; } = new(); + + public void UpdateSensors() { - private readonly Sensor _busClock; - private readonly Sensor[] _ccdTemperatures; - private readonly Sensor _coreTemperatureTctl; - private readonly Sensor _coreTemperatureTctlTdie; - private readonly Sensor _coreTemperatureTdie; - private readonly Sensor _coreVoltage; - private readonly Amd17Cpu _cpu; - private readonly Sensor _packagePower; - private readonly Dictionary, Sensor> _smuSensors = new(); - private readonly Sensor _socVoltage; + NumaNode node = Nodes[0]; + Core core = node?.Cores[0]; + CpuId cpuId = core?.Threads[0]; - private Sensor _ccdsAverageTemperature; - private Sensor _ccdsMaxTemperature; - private DateTime _lastPwrTime = new(0); - private uint _lastPwrValue; + if (cpuId == null) + return; - public Processor(Hardware hardware) + GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId.Affinity); + + // MSRC001_0299 + // TU [19:16] + // ESU [12:8] -> Unit 15.3 micro Joule per increment + // PU [3:0] + Ring0.ReadMsr(MSR_PWR_UNIT, out uint _, out uint _); + + // MSRC001_029B + // total_energy [31:0] + DateTime sampleTime = DateTime.Now; + Ring0.ReadMsr(MSR_PKG_ENERGY_STAT, out uint eax, out _); + + uint totalEnergy = eax; + + uint smuSvi0Tfn = 0; + uint smuSvi0TelPlane0 = 0; + uint smuSvi0TelPlane1 = 0; + + if (Ring0.WaitPciBusMutex(10)) { - _cpu = (Amd17Cpu)hardware; + // THM_TCON_CUR_TMP + // CUR_TEMP [31:21] + Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_THM_TCON_CUR_TMP); + Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint temperature); - _packagePower = new Sensor("Package", _cpu._sensorTypeIndex[SensorType.Power]++, SensorType.Power, _cpu, _cpu._settings); - _coreTemperatureTctl = new Sensor("Core (Tctl)", _cpu._sensorTypeIndex[SensorType.Temperature]++, SensorType.Temperature, _cpu, _cpu._settings); - _coreTemperatureTdie = new Sensor("Core (Tdie)", _cpu._sensorTypeIndex[SensorType.Temperature]++, SensorType.Temperature, _cpu, _cpu._settings); - _coreTemperatureTctlTdie = new Sensor("Core (Tctl/Tdie)", _cpu._sensorTypeIndex[SensorType.Temperature]++, SensorType.Temperature, _cpu, _cpu._settings); - _ccdTemperatures = new Sensor[8]; // Hardcoded until there's a way to get max CCDs. - _coreVoltage = new Sensor("Core (SVI2 TFN)", _cpu._sensorTypeIndex[SensorType.Voltage]++, SensorType.Voltage, _cpu, _cpu._settings); - _socVoltage = new Sensor("SoC (SVI2 TFN)", _cpu._sensorTypeIndex[SensorType.Voltage]++, SensorType.Voltage, _cpu, _cpu._settings); - _busClock = new Sensor("Bus Speed", _cpu._sensorTypeIndex[SensorType.Clock]++, SensorType.Clock, _cpu, _cpu._settings); + // SVI0_TFN_PLANE0 [0] + // SVI0_TFN_PLANE1 [1] + Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x8); + Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0Tfn); - _cpu.ActivateSensor(_packagePower); + bool supportsPerCcdTemperatures = false; - foreach (KeyValuePair sensor in _cpu._smu.GetPmTableStructure()) + // TODO: find a better way because these will probably keep changing in the future. + + uint sviPlane0Offset; + uint sviPlane1Offset; + switch (cpuId.Model) { - _smuSensors.Add(sensor, new Sensor(sensor.Value.Name, _cpu._sensorTypeIndex[sensor.Value.Type]++, sensor.Value.Type, _cpu, _cpu._settings)); - } - } - - public List Nodes { get; } = new(); - - public void UpdateSensors() - { - NumaNode node = Nodes[0]; - Core core = node?.Cores[0]; - CpuId cpuId = core?.Threads[0]; - - if (cpuId == null) - return; - - GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId.Affinity); - - // MSRC001_0299 - // TU [19:16] - // ESU [12:8] -> Unit 15.3 micro Joule per increment - // PU [3:0] - Ring0.ReadMsr(MSR_PWR_UNIT, out uint _, out uint _); - - // MSRC001_029B - // total_energy [31:0] - DateTime sampleTime = DateTime.Now; - Ring0.ReadMsr(MSR_PKG_ENERGY_STAT, out uint eax, out _); - - uint totalEnergy = eax; - - uint smuSvi0Tfn = 0; - uint smuSvi0TelPlane0 = 0; - uint smuSvi0TelPlane1 = 0; - - if (Ring0.WaitPciBusMutex(10)) - { - // THM_TCON_CUR_TMP - // CUR_TEMP [31:21] - Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_THM_TCON_CUR_TMP); - Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint temperature); - - // SVI0_TFN_PLANE0 [0] - // SVI0_TFN_PLANE1 [1] - Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M01H_SVI + 0x8); - Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0Tfn); - - bool supportsPerCcdTemperatures = false; - - // TODO: find a better way because these will probably keep changing in the future. - - uint sviPlane0Offset; - uint sviPlane1Offset; - switch (cpuId.Model) - { - case 0x31: // Threadripper 3000. - sviPlane0Offset = F17H_M01H_SVI + 0x14; - sviPlane1Offset = F17H_M01H_SVI + 0x10; - supportsPerCcdTemperatures = true; - break; - - case 0x71: // Zen 2. - case 0x21: // Zen 3. - sviPlane0Offset = F17H_M01H_SVI + 0x10; - sviPlane1Offset = F17H_M01H_SVI + 0xC; - supportsPerCcdTemperatures = true; - break; - - default: // Zen and Zen+. - sviPlane0Offset = F17H_M01H_SVI + 0xC; - sviPlane1Offset = F17H_M01H_SVI + 0x10; - break; - } - - // SVI0_PLANE0_VDDCOR [24:16] - // SVI0_PLANE0_IDDCOR [7:0] - Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane0Offset); - Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane0); - - // SVI0_PLANE1_VDDCOR [24:16] - // SVI0_PLANE1_IDDCOR [7:0] - Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane1Offset); - Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane1); - - ThreadAffinity.Set(previousAffinity); - - // power consumption - // power.Value = (float) ((double)pu * 0.125); - // esu = 15.3 micro Joule per increment - if (_lastPwrTime.Ticks == 0) - { - _lastPwrTime = sampleTime; - _lastPwrValue = totalEnergy; - } - - // ticks diff - TimeSpan time = sampleTime - _lastPwrTime; - long pwr; - if (_lastPwrValue <= totalEnergy) - pwr = totalEnergy - _lastPwrValue; - else - pwr = (0xffffffff - _lastPwrValue) + totalEnergy; - - // update for next sample - _lastPwrTime = sampleTime; - _lastPwrValue = totalEnergy; - - double energy = 15.3e-6 * pwr; - energy /= time.TotalSeconds; - - if (!double.IsNaN(energy)) - _packagePower.Value = (float)energy; - - // current temp Bit [31:21] - // If bit 19 of the Temperature Control register is set, there is an additional offset of 49 degrees C. - bool tempOffsetFlag = (temperature & F17H_TEMP_OFFSET_FLAG) != 0; - temperature = (temperature >> 21) * 125; - - float offset = 0.0f; - - // Offset table: https://github.com/torvalds/linux/blob/master/drivers/hwmon/k10temp.c#L78 - if (string.IsNullOrWhiteSpace(cpuId.Name)) - offset = 0; - else if (cpuId.Name.Contains("1600X") || cpuId.Name.Contains("1700X") || cpuId.Name.Contains("1800X")) - offset = -20.0f; - else if (cpuId.Name.Contains("Threadripper 19") || cpuId.Name.Contains("Threadripper 29")) - offset = -27.0f; - else if (cpuId.Name.Contains("2700X")) - offset = -10.0f; - - float t = temperature * 0.001f; - if (tempOffsetFlag) - t += -49.0f; - - if (offset < 0) - { - _coreTemperatureTctl.Value = t; - _coreTemperatureTdie.Value = t + offset; - - _cpu.ActivateSensor(_coreTemperatureTctl); - _cpu.ActivateSensor(_coreTemperatureTdie); - } - else - { - // Zen 2 doesn't have an offset so Tdie and Tctl are the same. - _coreTemperatureTctlTdie.Value = t; - _cpu.ActivateSensor(_coreTemperatureTctlTdie); - } - - // Tested only on R5 3600 & Threadripper 3960X. - if (supportsPerCcdTemperatures) - { - for (uint i = 0; i < _ccdTemperatures.Length; i++) - { - Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M70H_CCD1_TEMP + (i * 0x4)); - Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint ccdRawTemp); - - ccdRawTemp &= 0xFFF; - float ccdTemp = ((ccdRawTemp * 125) - 305000) * 0.001f; - if (ccdRawTemp > 0 && ccdTemp < 125) // Zen 2 reports 95 degrees C max, but it might exceed that. - { - if (_ccdTemperatures[i] == null) - { - _cpu.ActivateSensor(_ccdTemperatures[i] = new Sensor($"CCD{i + 1} (Tdie)", - _cpu._sensorTypeIndex[SensorType.Temperature]++, - SensorType.Temperature, - _cpu, - _cpu._settings)); - } - - _ccdTemperatures[i].Value = ccdTemp; - } - } - - Sensor[] activeCcds = _ccdTemperatures.Where(x => x != null).ToArray(); - if (activeCcds.Length > 1) - { - // No need to get the max / average ccds temp if there is only one CCD. - - if (_ccdsMaxTemperature == null) - { - _cpu.ActivateSensor(_ccdsMaxTemperature = new Sensor("CCDs Max (Tdie)", - _cpu._sensorTypeIndex[SensorType.Temperature]++, - SensorType.Temperature, - _cpu, - _cpu._settings)); - } - - if (_ccdsAverageTemperature == null) - { - _cpu.ActivateSensor(_ccdsAverageTemperature = new Sensor("CCDs Average (Tdie)", - _cpu._sensorTypeIndex[SensorType.Temperature]++, - SensorType.Temperature, - _cpu, - _cpu._settings)); - } - - _ccdsMaxTemperature.Value = activeCcds.Max(x => x.Value); - _ccdsAverageTemperature.Value = activeCcds.Average(x => x.Value); - } - } - - Ring0.ReleasePciBusMutex(); - } - - // voltage - const double vidStep = 0.00625; - double vcc; - uint svi0PlaneXVddCor; - - // Core (0x01). - if ((smuSvi0Tfn & 0x01) == 0) - { - svi0PlaneXVddCor = (smuSvi0TelPlane0 >> 16) & 0xff; - vcc = 1.550 - (vidStep * svi0PlaneXVddCor); - _coreVoltage.Value = (float)vcc; - - _cpu.ActivateSensor(_coreVoltage); - } - - // SoC (0x02), not every Zen cpu has this voltage. - if (cpuId.Model is 0x11 or 0x21 or 0x71 or 0x31 || (smuSvi0Tfn & 0x02) == 0) - { - svi0PlaneXVddCor = (smuSvi0TelPlane1 >> 16) & 0xff; - vcc = 1.550 - (vidStep * svi0PlaneXVddCor); - _socVoltage.Value = (float)vcc; - - _cpu.ActivateSensor(_socVoltage); - } - - double timeStampCounterMultiplier = GetTimeStampCounterMultiplier(); - if (timeStampCounterMultiplier > 0) - { - _busClock.Value = (float)(_cpu.TimeStampCounterFrequency / timeStampCounterMultiplier); - _cpu.ActivateSensor(_busClock); - } - - if (_cpu._smu.IsPmTableLayoutDefined()) - { - float[] smuData = _cpu._smu.GetPmTable(); - - foreach (KeyValuePair, Sensor> sensor in _smuSensors) - { - if (smuData.Length > sensor.Key.Key) - { - sensor.Value.Value = smuData[sensor.Key.Key] * sensor.Key.Value.Scale; - if (sensor.Value.Value != 0) - _cpu.ActivateSensor(sensor.Value); - } - } - } - } - - private double GetTimeStampCounterMultiplier() - { - Ring0.ReadMsr(MSR_PSTATE_0, out uint eax, out _); - uint cpuDfsId = (eax >> 8) & 0x3f; - uint cpuFid = eax & 0xff; - return 2.0 * cpuFid / cpuDfsId; - } - - public void AppendThread(CpuId thread, int numaId, int coreId) - { - NumaNode node = null; - foreach (NumaNode n in Nodes) - { - if (n.NodeId == numaId) - { - node = n; + case 0x31: // Threadripper 3000. + sviPlane0Offset = F17H_M01H_SVI + 0x14; + sviPlane1Offset = F17H_M01H_SVI + 0x10; + supportsPerCcdTemperatures = true; + break; + + case 0x71: // Zen 2. + case 0x21: // Zen 3. + sviPlane0Offset = F17H_M01H_SVI + 0x10; + sviPlane1Offset = F17H_M01H_SVI + 0xC; + supportsPerCcdTemperatures = true; + break; + + default: // Zen and Zen+. + sviPlane0Offset = F17H_M01H_SVI + 0xC; + sviPlane1Offset = F17H_M01H_SVI + 0x10; break; - } } - if (node == null) - { - node = new NumaNode(_cpu, numaId); - Nodes.Add(node); - } + // SVI0_PLANE0_VDDCOR [24:16] + // SVI0_PLANE0_IDDCOR [7:0] + Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane0Offset); + Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane0); - if (thread != null) - node.AppendThread(thread, coreId); - } - } + // SVI0_PLANE1_VDDCOR [24:16] + // SVI0_PLANE1_IDDCOR [7:0] + Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, sviPlane1Offset); + Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out smuSvi0TelPlane1); - private class NumaNode - { - private readonly Amd17Cpu _cpu; - - public NumaNode(Amd17Cpu cpu, int id) - { - Cores = new List(); - NodeId = id; - _cpu = cpu; - } - - public List Cores { get; } - - public int NodeId { get; } - - public void AppendThread(CpuId thread, int coreId) - { - Core core = null; - foreach (Core c in Cores) - { - if (c.CoreId == coreId) - core = c; - } - - if (core == null) - { - core = new Core(_cpu, coreId); - Cores.Add(core); - } - - if (thread != null) - core.Threads.Add(thread); - } - - public static void UpdateSensors() - { } - } - - private class Core - { - private readonly Sensor _clock; - private readonly Amd17Cpu _cpu; - private readonly Sensor _multiplier; - private readonly Sensor _power; - private readonly Sensor _vcore; - private ISensor _busSpeed; - private DateTime _lastPwrTime = new(0); - private uint _lastPwrValue; - - public Core(Amd17Cpu cpu, int id) - { - _cpu = cpu; - Threads = new List(); - CoreId = id; - _clock = new Sensor("Core #" + CoreId, _cpu._sensorTypeIndex[SensorType.Clock]++, SensorType.Clock, cpu, cpu._settings); - _multiplier = new Sensor("Core #" + CoreId, cpu._sensorTypeIndex[SensorType.Factor]++, SensorType.Factor, cpu, cpu._settings); - _power = new Sensor("Core #" + CoreId + " (SMU)", cpu._sensorTypeIndex[SensorType.Power]++, SensorType.Power, cpu, cpu._settings); - _vcore = new Sensor("Core #" + CoreId + " VID", cpu._sensorTypeIndex[SensorType.Voltage]++, SensorType.Voltage, cpu, cpu._settings); - - cpu.ActivateSensor(_clock); - cpu.ActivateSensor(_multiplier); - cpu.ActivateSensor(_power); - cpu.ActivateSensor(_vcore); - } - - public int CoreId { get; } - - public List Threads { get; } - - public void UpdateSensors() - { - // CPUID cpu = threads.FirstOrDefault(); - CpuId cpu = Threads[0]; - if (cpu == null) - return; - - GroupAffinity previousAffinity = ThreadAffinity.Set(cpu.Affinity); - - // MSRC001_0299 - // TU [19:16] - // ESU [12:8] -> Unit 15.3 micro Joule per increment - // PU [3:0] - Ring0.ReadMsr(MSR_PWR_UNIT, out _, out _); - - // MSRC001_029A - // total_energy [31:0] - DateTime sampleTime = DateTime.Now; - Ring0.ReadMsr(MSR_CORE_ENERGY_STAT, out uint eax, out _); - uint totalEnergy = eax; - - // MSRC001_0293 - // CurHwPstate [24:22] - // CurCpuVid [21:14] - // CurCpuDfsId [13:8] - // CurCpuFid [7:0] - Ring0.ReadMsr(MSR_HARDWARE_PSTATE_STATUS, out eax, out _); - int curCpuVid = (int)((eax >> 14) & 0xff); - int curCpuDfsId = (int)((eax >> 8) & 0x3f); - int curCpuFid = (int)(eax & 0xff); - - // MSRC001_0064 + x - // IddDiv [31:30] - // IddValue [29:22] - // CpuVid [21:14] - // CpuDfsId [13:8] - // CpuFid [7:0] - // Ring0.ReadMsr(MSR_PSTATE_0 + (uint)CurHwPstate, out eax, out edx); - // int IddDiv = (int)((eax >> 30) & 0x03); - // int IddValue = (int)((eax >> 22) & 0xff); - // int CpuVid = (int)((eax >> 14) & 0xff); ThreadAffinity.Set(previousAffinity); - // clock - // CoreCOF is (Core::X86::Msr::PStateDef[CpuFid[7:0]] / Core::X86::Msr::PStateDef[CpuDfsId]) * 200 - double clock = 200.0; - _busSpeed ??= _cpu.Sensors.FirstOrDefault(x => x.Name == "Bus Speed"); - if (_busSpeed?.Value.HasValue == true && _busSpeed.Value > 0) - clock = (double)(_busSpeed.Value * 2); - - _clock.Value = (float)(curCpuFid / (double)curCpuDfsId * clock); - - // multiplier - _multiplier.Value = (float)(curCpuFid / (double)curCpuDfsId * 2.0); - - // Voltage - const double vidStep = 0.00625; - double vcc = 1.550 - (vidStep * curCpuVid); - _vcore.Value = (float)vcc; - // power consumption // power.Value = (float) ((double)pu * 0.125); // esu = 15.3 micro Joule per increment @@ -567,25 +240,351 @@ namespace LibreHardwareMonitor.Hardware.CPU energy /= time.TotalSeconds; if (!double.IsNaN(energy)) - _power.Value = (float)energy; + _packagePower.Value = (float)energy; + + // current temp Bit [31:21] + // If bit 19 of the Temperature Control register is set, there is an additional offset of 49 degrees C. + bool tempOffsetFlag = (temperature & F17H_TEMP_OFFSET_FLAG) != 0; + temperature = (temperature >> 21) * 125; + + float offset = 0.0f; + + // Offset table: https://github.com/torvalds/linux/blob/master/drivers/hwmon/k10temp.c#L78 + if (string.IsNullOrWhiteSpace(cpuId.Name)) + offset = 0; + else if (cpuId.Name.Contains("1600X") || cpuId.Name.Contains("1700X") || cpuId.Name.Contains("1800X")) + offset = -20.0f; + else if (cpuId.Name.Contains("Threadripper 19") || cpuId.Name.Contains("Threadripper 29")) + offset = -27.0f; + else if (cpuId.Name.Contains("2700X")) + offset = -10.0f; + + float t = temperature * 0.001f; + if (tempOffsetFlag) + t += -49.0f; + + if (offset < 0) + { + _coreTemperatureTctl.Value = t; + _coreTemperatureTdie.Value = t + offset; + + _cpu.ActivateSensor(_coreTemperatureTctl); + _cpu.ActivateSensor(_coreTemperatureTdie); + } + else + { + // Zen 2 doesn't have an offset so Tdie and Tctl are the same. + _coreTemperatureTctlTdie.Value = t; + _cpu.ActivateSensor(_coreTemperatureTctlTdie); + } + + // Tested only on R5 3600 & Threadripper 3960X. + if (supportsPerCcdTemperatures) + { + for (uint i = 0; i < _ccdTemperatures.Length; i++) + { + Ring0.WritePciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER, F17H_M70H_CCD1_TEMP + (i * 0x4)); + Ring0.ReadPciConfig(0x00, FAMILY_17H_PCI_CONTROL_REGISTER + 4, out uint ccdRawTemp); + + ccdRawTemp &= 0xFFF; + float ccdTemp = ((ccdRawTemp * 125) - 305000) * 0.001f; + if (ccdRawTemp > 0 && ccdTemp < 125) // Zen 2 reports 95 degrees C max, but it might exceed that. + { + if (_ccdTemperatures[i] == null) + { + _cpu.ActivateSensor(_ccdTemperatures[i] = new Sensor($"CCD{i + 1} (Tdie)", + _cpu._sensorTypeIndex[SensorType.Temperature]++, + SensorType.Temperature, + _cpu, + _cpu._settings)); + } + + _ccdTemperatures[i].Value = ccdTemp; + } + } + + Sensor[] activeCcds = _ccdTemperatures.Where(x => x != null).ToArray(); + if (activeCcds.Length > 1) + { + // No need to get the max / average ccds temp if there is only one CCD. + + if (_ccdsMaxTemperature == null) + { + _cpu.ActivateSensor(_ccdsMaxTemperature = new Sensor("CCDs Max (Tdie)", + _cpu._sensorTypeIndex[SensorType.Temperature]++, + SensorType.Temperature, + _cpu, + _cpu._settings)); + } + + if (_ccdsAverageTemperature == null) + { + _cpu.ActivateSensor(_ccdsAverageTemperature = new Sensor("CCDs Average (Tdie)", + _cpu._sensorTypeIndex[SensorType.Temperature]++, + SensorType.Temperature, + _cpu, + _cpu._settings)); + } + + _ccdsMaxTemperature.Value = activeCcds.Max(x => x.Value); + _ccdsAverageTemperature.Value = activeCcds.Average(x => x.Value); + } + } + + Ring0.ReleasePciBusMutex(); + } + + // voltage + const double vidStep = 0.00625; + double vcc; + uint svi0PlaneXVddCor; + + // Core (0x01). + if ((smuSvi0Tfn & 0x01) == 0) + { + svi0PlaneXVddCor = (smuSvi0TelPlane0 >> 16) & 0xff; + vcc = 1.550 - (vidStep * svi0PlaneXVddCor); + _coreVoltage.Value = (float)vcc; + + _cpu.ActivateSensor(_coreVoltage); + } + + // SoC (0x02), not every Zen cpu has this voltage. + if (cpuId.Model is 0x11 or 0x21 or 0x71 or 0x31 || (smuSvi0Tfn & 0x02) == 0) + { + svi0PlaneXVddCor = (smuSvi0TelPlane1 >> 16) & 0xff; + vcc = 1.550 - (vidStep * svi0PlaneXVddCor); + _socVoltage.Value = (float)vcc; + + _cpu.ActivateSensor(_socVoltage); + } + + double timeStampCounterMultiplier = GetTimeStampCounterMultiplier(); + if (timeStampCounterMultiplier > 0) + { + _busClock.Value = (float)(_cpu.TimeStampCounterFrequency / timeStampCounterMultiplier); + _cpu.ActivateSensor(_busClock); + } + + if (_cpu._smu.IsPmTableLayoutDefined()) + { + float[] smuData = _cpu._smu.GetPmTable(); + + foreach (KeyValuePair, Sensor> sensor in _smuSensors) + { + if (smuData.Length > sensor.Key.Key) + { + sensor.Value.Value = smuData[sensor.Key.Key] * sensor.Key.Value.Scale; + if (sensor.Value.Value != 0) + _cpu.ActivateSensor(sensor.Value); + } + } } } - // ReSharper disable InconsistentNaming - private const uint COFVID_STATUS = 0xC0010071; - private const uint F17H_M01H_SVI = 0x0005A000; - private const uint F17H_M01H_THM_TCON_CUR_TMP = 0x00059800; - private const uint F17H_M70H_CCD1_TEMP = 0x00059954; - private const uint F17H_TEMP_OFFSET_FLAG = 0x80000; - private const uint FAMILY_17H_PCI_CONTROL_REGISTER = 0x60; - private const uint HWCR = 0xC0010015; - private const uint MSR_CORE_ENERGY_STAT = 0xC001029A; - private const uint MSR_HARDWARE_PSTATE_STATUS = 0xC0010293; - private const uint MSR_PKG_ENERGY_STAT = 0xC001029B; - private const uint MSR_PSTATE_0 = 0xC0010064; - private const uint MSR_PWR_UNIT = 0xC0010299; - private const uint PERF_CTL_0 = 0xC0010000; - private const uint PERF_CTR_0 = 0xC0010004; - // ReSharper restore InconsistentNaming + private double GetTimeStampCounterMultiplier() + { + Ring0.ReadMsr(MSR_PSTATE_0, out uint eax, out _); + uint cpuDfsId = (eax >> 8) & 0x3f; + uint cpuFid = eax & 0xff; + return 2.0 * cpuFid / cpuDfsId; + } + + public void AppendThread(CpuId thread, int numaId, int coreId) + { + NumaNode node = null; + foreach (NumaNode n in Nodes) + { + if (n.NodeId == numaId) + { + node = n; + break; + } + } + + if (node == null) + { + node = new NumaNode(_cpu, numaId); + Nodes.Add(node); + } + + if (thread != null) + node.AppendThread(thread, coreId); + } } + + private class NumaNode + { + private readonly Amd17Cpu _cpu; + + public NumaNode(Amd17Cpu cpu, int id) + { + Cores = new List(); + NodeId = id; + _cpu = cpu; + } + + public List Cores { get; } + + public int NodeId { get; } + + public void AppendThread(CpuId thread, int coreId) + { + Core core = null; + foreach (Core c in Cores) + { + if (c.CoreId == coreId) + core = c; + } + + if (core == null) + { + core = new Core(_cpu, coreId); + Cores.Add(core); + } + + if (thread != null) + core.Threads.Add(thread); + } + + public static void UpdateSensors() + { } + } + + private class Core + { + private readonly Sensor _clock; + private readonly Amd17Cpu _cpu; + private readonly Sensor _multiplier; + private readonly Sensor _power; + private readonly Sensor _vcore; + private ISensor _busSpeed; + private DateTime _lastPwrTime = new(0); + private uint _lastPwrValue; + + public Core(Amd17Cpu cpu, int id) + { + _cpu = cpu; + Threads = new List(); + CoreId = id; + _clock = new Sensor("Core #" + CoreId, _cpu._sensorTypeIndex[SensorType.Clock]++, SensorType.Clock, cpu, cpu._settings); + _multiplier = new Sensor("Core #" + CoreId, cpu._sensorTypeIndex[SensorType.Factor]++, SensorType.Factor, cpu, cpu._settings); + _power = new Sensor("Core #" + CoreId + " (SMU)", cpu._sensorTypeIndex[SensorType.Power]++, SensorType.Power, cpu, cpu._settings); + _vcore = new Sensor("Core #" + CoreId + " VID", cpu._sensorTypeIndex[SensorType.Voltage]++, SensorType.Voltage, cpu, cpu._settings); + + cpu.ActivateSensor(_clock); + cpu.ActivateSensor(_multiplier); + cpu.ActivateSensor(_power); + cpu.ActivateSensor(_vcore); + } + + public int CoreId { get; } + + public List Threads { get; } + + public void UpdateSensors() + { + // CPUID cpu = threads.FirstOrDefault(); + CpuId cpu = Threads[0]; + if (cpu == null) + return; + + GroupAffinity previousAffinity = ThreadAffinity.Set(cpu.Affinity); + + // MSRC001_0299 + // TU [19:16] + // ESU [12:8] -> Unit 15.3 micro Joule per increment + // PU [3:0] + Ring0.ReadMsr(MSR_PWR_UNIT, out _, out _); + + // MSRC001_029A + // total_energy [31:0] + DateTime sampleTime = DateTime.Now; + Ring0.ReadMsr(MSR_CORE_ENERGY_STAT, out uint eax, out _); + uint totalEnergy = eax; + + // MSRC001_0293 + // CurHwPstate [24:22] + // CurCpuVid [21:14] + // CurCpuDfsId [13:8] + // CurCpuFid [7:0] + Ring0.ReadMsr(MSR_HARDWARE_PSTATE_STATUS, out eax, out _); + int curCpuVid = (int)((eax >> 14) & 0xff); + int curCpuDfsId = (int)((eax >> 8) & 0x3f); + int curCpuFid = (int)(eax & 0xff); + + // MSRC001_0064 + x + // IddDiv [31:30] + // IddValue [29:22] + // CpuVid [21:14] + // CpuDfsId [13:8] + // CpuFid [7:0] + // Ring0.ReadMsr(MSR_PSTATE_0 + (uint)CurHwPstate, out eax, out edx); + // int IddDiv = (int)((eax >> 30) & 0x03); + // int IddValue = (int)((eax >> 22) & 0xff); + // int CpuVid = (int)((eax >> 14) & 0xff); + ThreadAffinity.Set(previousAffinity); + + // clock + // CoreCOF is (Core::X86::Msr::PStateDef[CpuFid[7:0]] / Core::X86::Msr::PStateDef[CpuDfsId]) * 200 + double clock = 200.0; + _busSpeed ??= _cpu.Sensors.FirstOrDefault(x => x.Name == "Bus Speed"); + if (_busSpeed?.Value.HasValue == true && _busSpeed.Value > 0) + clock = (double)(_busSpeed.Value * 2); + + _clock.Value = (float)(curCpuFid / (double)curCpuDfsId * clock); + + // multiplier + _multiplier.Value = (float)(curCpuFid / (double)curCpuDfsId * 2.0); + + // Voltage + const double vidStep = 0.00625; + double vcc = 1.550 - (vidStep * curCpuVid); + _vcore.Value = (float)vcc; + + // power consumption + // power.Value = (float) ((double)pu * 0.125); + // esu = 15.3 micro Joule per increment + if (_lastPwrTime.Ticks == 0) + { + _lastPwrTime = sampleTime; + _lastPwrValue = totalEnergy; + } + + // ticks diff + TimeSpan time = sampleTime - _lastPwrTime; + long pwr; + if (_lastPwrValue <= totalEnergy) + pwr = totalEnergy - _lastPwrValue; + else + pwr = (0xffffffff - _lastPwrValue) + totalEnergy; + + // update for next sample + _lastPwrTime = sampleTime; + _lastPwrValue = totalEnergy; + + double energy = 15.3e-6 * pwr; + energy /= time.TotalSeconds; + + if (!double.IsNaN(energy)) + _power.Value = (float)energy; + } + } + + // ReSharper disable InconsistentNaming + private const uint COFVID_STATUS = 0xC0010071; + private const uint F17H_M01H_SVI = 0x0005A000; + private const uint F17H_M01H_THM_TCON_CUR_TMP = 0x00059800; + private const uint F17H_M70H_CCD1_TEMP = 0x00059954; + private const uint F17H_TEMP_OFFSET_FLAG = 0x80000; + private const uint FAMILY_17H_PCI_CONTROL_REGISTER = 0x60; + private const uint HWCR = 0xC0010015; + private const uint MSR_CORE_ENERGY_STAT = 0xC001029A; + private const uint MSR_HARDWARE_PSTATE_STATUS = 0xC0010293; + private const uint MSR_PKG_ENERGY_STAT = 0xC001029B; + private const uint MSR_PSTATE_0 = 0xC0010064; + private const uint MSR_PWR_UNIT = 0xC0010299; + private const uint PERF_CTL_0 = 0xC0010000; + private const uint PERF_CTR_0 = 0xC0010004; + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/AmdCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/AmdCpu.cs index 4f8609c..e20dc0b 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/AmdCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/AmdCpu.cs @@ -4,34 +4,33 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +internal abstract class AmdCpu : GenericCpu { - internal abstract class AmdCpu : GenericCpu + protected AmdCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) + { } + + protected uint GetPciAddress(byte function, ushort deviceId) { - protected AmdCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) - { } + // assemble the pci address + uint address = Ring0.GetPciAddress(PCI_BUS, (byte)(PCI_BASE_DEVICE + Index), function); - protected uint GetPciAddress(byte function, ushort deviceId) - { - // assemble the pci address - uint address = Ring0.GetPciAddress(PCI_BUS, (byte)(PCI_BASE_DEVICE + Index), function); + // verify that we have the correct bus, device and function + if (!Ring0.ReadPciConfig(address, DEVICE_VENDOR_ID_REGISTER, out uint deviceVendor)) + return Interop.Ring0.INVALID_PCI_ADDRESS; - // verify that we have the correct bus, device and function - if (!Ring0.ReadPciConfig(address, DEVICE_VENDOR_ID_REGISTER, out uint deviceVendor)) - return Interop.Ring0.INVALID_PCI_ADDRESS; + if (deviceVendor != (deviceId << 16 | AMD_VENDOR_ID)) + return Interop.Ring0.INVALID_PCI_ADDRESS; - if (deviceVendor != (deviceId << 16 | AMD_VENDOR_ID)) - return Interop.Ring0.INVALID_PCI_ADDRESS; - - return address; - } - - // ReSharper disable InconsistentNaming - private const ushort AMD_VENDOR_ID = 0x1022; - private const byte DEVICE_VENDOR_ID_REGISTER = 0; - private const byte PCI_BASE_DEVICE = 0x18; - - private const byte PCI_BUS = 0; - // ReSharper restore InconsistentNaming + return address; } -} + + // ReSharper disable InconsistentNaming + private const ushort AMD_VENDOR_ID = 0x1022; + private const byte DEVICE_VENDOR_ID_REGISTER = 0; + private const byte PCI_BASE_DEVICE = 0x18; + + private const byte PCI_BUS = 0; + // ReSharper restore InconsistentNaming +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs b/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs index cf6ee1f..5a4af0d 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/CpuGroup.cs @@ -9,207 +9,206 @@ using System.Collections.Generic; using System.Globalization; using System.Text; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +internal class CpuGroup : IGroup { - internal class CpuGroup : IGroup + private readonly List _hardware = new(); + private readonly CpuId[][][] _threads; + + public CpuGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly CpuId[][][] _threads; + CpuId[][] processorThreads = GetProcessorThreads(); + _threads = new CpuId[processorThreads.Length][][]; - public CpuGroup(ISettings settings) + int index = 0; + foreach (CpuId[] threads in processorThreads) { - CpuId[][] processorThreads = GetProcessorThreads(); - _threads = new CpuId[processorThreads.Length][][]; + if (threads.Length == 0) + continue; - int index = 0; - foreach (CpuId[] threads in processorThreads) + CpuId[][] coreThreads = GroupThreadsByCore(threads); + _threads[index] = coreThreads; + + switch (threads[0].Vendor) { - if (threads.Length == 0) - continue; - - CpuId[][] coreThreads = GroupThreadsByCore(threads); - _threads[index] = coreThreads; - - switch (threads[0].Vendor) - { - case Vendor.Intel: - _hardware.Add(new IntelCpu(index, coreThreads, settings)); - break; - case Vendor.AMD: - switch (threads[0].Family) - { - case 0x0F: - _hardware.Add(new Amd0FCpu(index, coreThreads, settings)); - break; - case 0x10: - case 0x11: - case 0x12: - case 0x14: - case 0x15: - case 0x16: - _hardware.Add(new Amd10Cpu(index, coreThreads, settings)); - break; - case 0x17: - case 0x19: - _hardware.Add(new Amd17Cpu(index, coreThreads, settings)); - break; - default: - _hardware.Add(new GenericCpu(index, coreThreads, settings)); - break; - } - - break; - default: - _hardware.Add(new GenericCpu(index, coreThreads, settings)); - break; - } - - index++; - } - } - - public IReadOnlyList Hardware => _hardware; - - public string GetReport() - { - if (_threads == null) - return null; - - StringBuilder r = new(); - r.AppendLine("CPUID"); - r.AppendLine(); - for (int i = 0; i < _threads.Length; i++) - { - r.AppendLine("Processor " + i); - r.AppendLine(); - r.AppendFormat("Processor Vendor: {0}{1}", _threads[i][0][0].Vendor, Environment.NewLine); - r.AppendFormat("Processor Brand: {0}{1}", _threads[i][0][0].BrandString, Environment.NewLine); - r.AppendFormat("Family: 0x{0}{1}", _threads[i][0][0].Family.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); - r.AppendFormat("Model: 0x{0}{1}", _threads[i][0][0].Model.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); - r.AppendFormat("Stepping: 0x{0}{1}", _threads[i][0][0].Stepping.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); - r.AppendLine(); - - r.AppendLine("CPUID Return Values"); - r.AppendLine(); - for (int j = 0; j < _threads[i].Length; j++) - { - for (int k = 0; k < _threads[i][j].Length; k++) + case Vendor.Intel: + _hardware.Add(new IntelCpu(index, coreThreads, settings)); + break; + case Vendor.AMD: + switch (threads[0].Family) { - r.AppendLine(" CPU Group: " + _threads[i][j][k].Group); - r.AppendLine(" CPU Thread: " + _threads[i][j][k].Thread); - r.AppendLine(" APIC ID: " + _threads[i][j][k].ApicId); - r.AppendLine(" Processor ID: " + _threads[i][j][k].ProcessorId); - r.AppendLine(" Core ID: " + _threads[i][j][k].CoreId); - r.AppendLine(" Thread ID: " + _threads[i][j][k].ThreadId); - r.AppendLine(); - r.AppendLine(" Function EAX EBX ECX EDX"); - AppendCpuidData(r, _threads[i][j][k].Data, CpuId.CPUID_0); - AppendCpuidData(r, _threads[i][j][k].ExtData, CpuId.CPUID_EXT); - r.AppendLine(); + case 0x0F: + _hardware.Add(new Amd0FCpu(index, coreThreads, settings)); + break; + case 0x10: + case 0x11: + case 0x12: + case 0x14: + case 0x15: + case 0x16: + _hardware.Add(new Amd10Cpu(index, coreThreads, settings)); + break; + case 0x17: + case 0x19: + _hardware.Add(new Amd17Cpu(index, coreThreads, settings)); + break; + default: + _hardware.Add(new GenericCpu(index, coreThreads, settings)); + break; } - } + + break; + default: + _hardware.Add(new GenericCpu(index, coreThreads, settings)); + break; } - return r.ToString(); - } - - public void Close() - { - foreach (GenericCpu cpu in _hardware) - { - cpu.Close(); - } - } - - private static CpuId[][] GetProcessorThreads() - { - List threads = new(); - - for (int i = 0; i < ThreadAffinity.ProcessorGroupCount; i++) - { - for (int j = 0; j < 64; j++) - { - try - { - if (!ThreadAffinity.IsValid(GroupAffinity.Single((ushort)i, j))) - continue; - - var cpuid = CpuId.Get(i, j); - if (cpuid != null) - threads.Add(cpuid); - } - catch (ArgumentOutOfRangeException) - { - // All cores found. - break; - } - } - } - - SortedDictionary> processors = new(); - foreach (CpuId thread in threads) - { - processors.TryGetValue(thread.ProcessorId, out List list); - if (list == null) - { - list = new List(); - processors.Add(thread.ProcessorId, list); - } - - list.Add(thread); - } - - CpuId[][] processorThreads = new CpuId[processors.Count][]; - int index = 0; - foreach (List list in processors.Values) - { - processorThreads[index] = list.ToArray(); - index++; - } - - return processorThreads; - } - - private static CpuId[][] GroupThreadsByCore(IEnumerable threads) - { - SortedDictionary> cores = new(); - foreach (CpuId thread in threads) - { - cores.TryGetValue(thread.CoreId, out List coreList); - if (coreList == null) - { - coreList = new List(); - cores.Add(thread.CoreId, coreList); - } - - coreList.Add(thread); - } - - CpuId[][] coreThreads = new CpuId[cores.Count][]; - int index = 0; - foreach (List list in cores.Values) - { - coreThreads[index] = list.ToArray(); - index++; - } - - return coreThreads; - } - - private static void AppendCpuidData(StringBuilder r, uint[,] data, uint offset) - { - for (int i = 0; i < data.GetLength(0); i++) - { - r.Append(" "); - r.Append((i + offset).ToString("X8", CultureInfo.InvariantCulture)); - for (int j = 0; j < 4; j++) - { - r.Append(" "); - r.Append(data[i, j].ToString("X8", CultureInfo.InvariantCulture)); - } - - r.AppendLine(); - } + index++; } } -} + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + if (_threads == null) + return null; + + StringBuilder r = new(); + r.AppendLine("CPUID"); + r.AppendLine(); + for (int i = 0; i < _threads.Length; i++) + { + r.AppendLine("Processor " + i); + r.AppendLine(); + r.AppendFormat("Processor Vendor: {0}{1}", _threads[i][0][0].Vendor, Environment.NewLine); + r.AppendFormat("Processor Brand: {0}{1}", _threads[i][0][0].BrandString, Environment.NewLine); + r.AppendFormat("Family: 0x{0}{1}", _threads[i][0][0].Family.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); + r.AppendFormat("Model: 0x{0}{1}", _threads[i][0][0].Model.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); + r.AppendFormat("Stepping: 0x{0}{1}", _threads[i][0][0].Stepping.ToString("X", CultureInfo.InvariantCulture), Environment.NewLine); + r.AppendLine(); + + r.AppendLine("CPUID Return Values"); + r.AppendLine(); + for (int j = 0; j < _threads[i].Length; j++) + { + for (int k = 0; k < _threads[i][j].Length; k++) + { + r.AppendLine(" CPU Group: " + _threads[i][j][k].Group); + r.AppendLine(" CPU Thread: " + _threads[i][j][k].Thread); + r.AppendLine(" APIC ID: " + _threads[i][j][k].ApicId); + r.AppendLine(" Processor ID: " + _threads[i][j][k].ProcessorId); + r.AppendLine(" Core ID: " + _threads[i][j][k].CoreId); + r.AppendLine(" Thread ID: " + _threads[i][j][k].ThreadId); + r.AppendLine(); + r.AppendLine(" Function EAX EBX ECX EDX"); + AppendCpuidData(r, _threads[i][j][k].Data, CpuId.CPUID_0); + AppendCpuidData(r, _threads[i][j][k].ExtData, CpuId.CPUID_EXT); + r.AppendLine(); + } + } + } + + return r.ToString(); + } + + public void Close() + { + foreach (GenericCpu cpu in _hardware) + { + cpu.Close(); + } + } + + private static CpuId[][] GetProcessorThreads() + { + List threads = new(); + + for (int i = 0; i < ThreadAffinity.ProcessorGroupCount; i++) + { + for (int j = 0; j < 64; j++) + { + try + { + if (!ThreadAffinity.IsValid(GroupAffinity.Single((ushort)i, j))) + continue; + + var cpuid = CpuId.Get(i, j); + if (cpuid != null) + threads.Add(cpuid); + } + catch (ArgumentOutOfRangeException) + { + // All cores found. + break; + } + } + } + + SortedDictionary> processors = new(); + foreach (CpuId thread in threads) + { + processors.TryGetValue(thread.ProcessorId, out List list); + if (list == null) + { + list = new List(); + processors.Add(thread.ProcessorId, list); + } + + list.Add(thread); + } + + CpuId[][] processorThreads = new CpuId[processors.Count][]; + int index = 0; + foreach (List list in processors.Values) + { + processorThreads[index] = list.ToArray(); + index++; + } + + return processorThreads; + } + + private static CpuId[][] GroupThreadsByCore(IEnumerable threads) + { + SortedDictionary> cores = new(); + foreach (CpuId thread in threads) + { + cores.TryGetValue(thread.CoreId, out List coreList); + if (coreList == null) + { + coreList = new List(); + cores.Add(thread.CoreId, coreList); + } + + coreList.Add(thread); + } + + CpuId[][] coreThreads = new CpuId[cores.Count][]; + int index = 0; + foreach (List list in cores.Values) + { + coreThreads[index] = list.ToArray(); + index++; + } + + return coreThreads; + } + + private static void AppendCpuidData(StringBuilder r, uint[,] data, uint offset) + { + for (int i = 0; i < data.GetLength(0); i++) + { + r.Append(" "); + r.Append((i + offset).ToString("X8", CultureInfo.InvariantCulture)); + for (int j = 0; j < 4; j++) + { + r.Append(" "); + r.Append(data[i, j].ToString("X8", CultureInfo.InvariantCulture)); + } + + r.AppendLine(); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs b/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs index a5a642e..cbdf4ea 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/CpuId.cs @@ -7,270 +7,269 @@ using System; using System.Text; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +public enum Vendor { - public enum Vendor - { - Unknown, - Intel, - AMD - } + Unknown, + Intel, + AMD +} - public class CpuId +public class CpuId +{ + /// + /// Initializes a new instance of the class. + /// + /// The group. + /// The thread. + /// The affinity. + private CpuId(int group, int thread, GroupAffinity affinity) { - /// - /// Initializes a new instance of the class. - /// - /// The group. - /// The thread. - /// The affinity. - private CpuId(int group, int thread, GroupAffinity affinity) + Thread = thread; + Group = group; + Affinity = affinity; + + uint threadMaskWith; + uint coreMaskWith; + uint maxCpuidExt; + + if (thread >= 64) + throw new ArgumentOutOfRangeException(nameof(thread)); + + uint maxCpuid; + if (OpCode.CpuId(CPUID_0, 0, out uint eax, out uint ebx, out uint ecx, out uint edx)) { - Thread = thread; - Group = group; - Affinity = affinity; + if (eax > 0) + maxCpuid = eax; + else + return; - uint threadMaskWith; - uint coreMaskWith; - uint maxCpuidExt; - - if (thread >= 64) - throw new ArgumentOutOfRangeException(nameof(thread)); - - uint maxCpuid; - if (OpCode.CpuId(CPUID_0, 0, out uint eax, out uint ebx, out uint ecx, out uint edx)) + StringBuilder vendorBuilder = new(); + AppendRegister(vendorBuilder, ebx); + AppendRegister(vendorBuilder, edx); + AppendRegister(vendorBuilder, ecx); + Vendor = vendorBuilder.ToString() switch { - if (eax > 0) - maxCpuid = eax; + "GenuineIntel" => Vendor.Intel, + "AuthenticAMD" => Vendor.AMD, + _ => Vendor.Unknown + }; + + if (OpCode.CpuId(CPUID_EXT, 0, out eax, out _, out _, out _)) + { + if (eax > CPUID_EXT) + maxCpuidExt = eax - CPUID_EXT; else return; - - StringBuilder vendorBuilder = new(); - AppendRegister(vendorBuilder, ebx); - AppendRegister(vendorBuilder, edx); - AppendRegister(vendorBuilder, ecx); - Vendor = vendorBuilder.ToString() switch - { - "GenuineIntel" => Vendor.Intel, - "AuthenticAMD" => Vendor.AMD, - _ => Vendor.Unknown - }; - - if (OpCode.CpuId(CPUID_EXT, 0, out eax, out _, out _, out _)) - { - if (eax > CPUID_EXT) - maxCpuidExt = eax - CPUID_EXT; - else - return; - } - else - { - throw new ArgumentOutOfRangeException(nameof(thread)); - } } else { throw new ArgumentOutOfRangeException(nameof(thread)); } + } + else + { + throw new ArgumentOutOfRangeException(nameof(thread)); + } - maxCpuid = Math.Min(maxCpuid, 1024); - maxCpuidExt = Math.Min(maxCpuidExt, 1024); + maxCpuid = Math.Min(maxCpuid, 1024); + maxCpuidExt = Math.Min(maxCpuidExt, 1024); - Data = new uint[maxCpuid + 1, 4]; - for (uint i = 0; i < maxCpuid + 1; i++) + Data = new uint[maxCpuid + 1, 4]; + for (uint i = 0; i < maxCpuid + 1; i++) + { + OpCode.CpuId(CPUID_0 + i, 0, out Data[i, 0], out Data[i, 1], out Data[i, 2], out Data[i, 3]); + } + + ExtData = new uint[maxCpuidExt + 1, 4]; + for (uint i = 0; i < maxCpuidExt + 1; i++) + { + OpCode.CpuId(CPUID_EXT + i, 0, out ExtData[i, 0], out ExtData[i, 1], out ExtData[i, 2], out ExtData[i, 3]); + } + + StringBuilder nameBuilder = new(); + for (uint i = 2; i <= 4; i++) + { + if (OpCode.CpuId(CPUID_EXT + i, 0, out eax, out ebx, out ecx, out edx)) { - OpCode.CpuId(CPUID_0 + i, 0, out Data[i, 0], out Data[i, 1], out Data[i, 2], out Data[i, 3]); + AppendRegister(nameBuilder, eax); + AppendRegister(nameBuilder, ebx); + AppendRegister(nameBuilder, ecx); + AppendRegister(nameBuilder, edx); } + } - ExtData = new uint[maxCpuidExt + 1, 4]; - for (uint i = 0; i < maxCpuidExt + 1; i++) - { - OpCode.CpuId(CPUID_EXT + i, 0, out ExtData[i, 0], out ExtData[i, 1], out ExtData[i, 2], out ExtData[i, 3]); - } + nameBuilder.Replace('\0', ' '); + BrandString = nameBuilder.ToString().Trim(); + nameBuilder.Replace("(R)", string.Empty); + nameBuilder.Replace("(TM)", string.Empty); + nameBuilder.Replace("(tm)", string.Empty); + nameBuilder.Replace("CPU", string.Empty); + nameBuilder.Replace("Dual-Core Processor", string.Empty); + nameBuilder.Replace("Triple-Core Processor", string.Empty); + nameBuilder.Replace("Quad-Core Processor", string.Empty); + nameBuilder.Replace("Six-Core Processor", string.Empty); + nameBuilder.Replace("Eight-Core Processor", string.Empty); + nameBuilder.Replace("6-Core Processor", string.Empty); + nameBuilder.Replace("8-Core Processor", string.Empty); + nameBuilder.Replace("12-Core Processor", string.Empty); + nameBuilder.Replace("16-Core Processor", string.Empty); + nameBuilder.Replace("24-Core Processor", string.Empty); + nameBuilder.Replace("32-Core Processor", string.Empty); + nameBuilder.Replace("64-Core Processor", string.Empty); - StringBuilder nameBuilder = new(); - for (uint i = 2; i <= 4; i++) - { - if (OpCode.CpuId(CPUID_EXT + i, 0, out eax, out ebx, out ecx, out edx)) + for (int i = 0; i < 10; i++) + nameBuilder.Replace(" ", " "); + + Name = nameBuilder.ToString(); + if (Name.Contains("@")) + Name = Name.Remove(Name.LastIndexOf('@')); + + Name = Name.Trim(); + Family = ((Data[1, 0] & 0x0FF00000) >> 20) + ((Data[1, 0] & 0x0F00) >> 8); + Model = ((Data[1, 0] & 0x0F0000) >> 12) + ((Data[1, 0] & 0xF0) >> 4); + Stepping = Data[1, 0] & 0x0F; + ApicId = (Data[1, 1] >> 24) & 0xFF; + PkgType = (ExtData[1, 1] >> 28) & 0xFF; + + switch (Vendor) + { + case Vendor.Intel: + uint maxCoreAndThreadIdPerPackage = (Data[1, 1] >> 16) & 0xFF; + uint maxCoreIdPerPackage; + if (maxCpuid >= 4) + maxCoreIdPerPackage = ((Data[4, 0] >> 26) & 0x3F) + 1; + else + maxCoreIdPerPackage = 1; + + threadMaskWith = NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage); + coreMaskWith = NextLog2(maxCoreIdPerPackage); + break; + + case Vendor.AMD: + uint corePerPackage; + if (maxCpuidExt >= 8) + corePerPackage = (ExtData[8, 2] & 0xFF) + 1; + else + corePerPackage = 1; + + threadMaskWith = 0; + coreMaskWith = NextLog2(corePerPackage); + + if (Family is 0x17 or 0x19) { - AppendRegister(nameBuilder, eax); - AppendRegister(nameBuilder, ebx); - AppendRegister(nameBuilder, ecx); - AppendRegister(nameBuilder, edx); - } - } - - nameBuilder.Replace('\0', ' '); - BrandString = nameBuilder.ToString().Trim(); - nameBuilder.Replace("(R)", string.Empty); - nameBuilder.Replace("(TM)", string.Empty); - nameBuilder.Replace("(tm)", string.Empty); - nameBuilder.Replace("CPU", string.Empty); - nameBuilder.Replace("Dual-Core Processor", string.Empty); - nameBuilder.Replace("Triple-Core Processor", string.Empty); - nameBuilder.Replace("Quad-Core Processor", string.Empty); - nameBuilder.Replace("Six-Core Processor", string.Empty); - nameBuilder.Replace("Eight-Core Processor", string.Empty); - nameBuilder.Replace("6-Core Processor", string.Empty); - nameBuilder.Replace("8-Core Processor", string.Empty); - nameBuilder.Replace("12-Core Processor", string.Empty); - nameBuilder.Replace("16-Core Processor", string.Empty); - nameBuilder.Replace("24-Core Processor", string.Empty); - nameBuilder.Replace("32-Core Processor", string.Empty); - nameBuilder.Replace("64-Core Processor", string.Empty); - - for (int i = 0; i < 10; i++) - nameBuilder.Replace(" ", " "); - - Name = nameBuilder.ToString(); - if (Name.Contains("@")) - Name = Name.Remove(Name.LastIndexOf('@')); - - Name = Name.Trim(); - Family = ((Data[1, 0] & 0x0FF00000) >> 20) + ((Data[1, 0] & 0x0F00) >> 8); - Model = ((Data[1, 0] & 0x0F0000) >> 12) + ((Data[1, 0] & 0xF0) >> 4); - Stepping = Data[1, 0] & 0x0F; - ApicId = (Data[1, 1] >> 24) & 0xFF; - PkgType = (ExtData[1, 1] >> 28) & 0xFF; - - switch (Vendor) - { - case Vendor.Intel: - uint maxCoreAndThreadIdPerPackage = (Data[1, 1] >> 16) & 0xFF; - uint maxCoreIdPerPackage; - if (maxCpuid >= 4) - maxCoreIdPerPackage = ((Data[4, 0] >> 26) & 0x3F) + 1; - else - maxCoreIdPerPackage = 1; - - threadMaskWith = NextLog2(maxCoreAndThreadIdPerPackage / maxCoreIdPerPackage); - coreMaskWith = NextLog2(maxCoreIdPerPackage); - break; - - case Vendor.AMD: - uint corePerPackage; - if (maxCpuidExt >= 8) - corePerPackage = (ExtData[8, 2] & 0xFF) + 1; - else - corePerPackage = 1; - - threadMaskWith = 0; - coreMaskWith = NextLog2(corePerPackage); - - if (Family is 0x17 or 0x19) + // ApicIdCoreIdSize: APIC ID size. + // cores per DIE + // we need this for Ryzen 5 (4 cores, 8 threads) ans Ryzen 6 (6 cores, 12 threads) + // Ryzen 5: [core0][core1][dummy][dummy][core2][core3] (Core0 EBX = 00080800, Core2 EBX = 08080800) + coreMaskWith = ((ExtData[8, 2] >> 12) & 0xF) switch { - // ApicIdCoreIdSize: APIC ID size. - // cores per DIE - // we need this for Ryzen 5 (4 cores, 8 threads) ans Ryzen 6 (6 cores, 12 threads) - // Ryzen 5: [core0][core1][dummy][dummy][core2][core3] (Core0 EBX = 00080800, Core2 EBX = 08080800) - coreMaskWith = ((ExtData[8, 2] >> 12) & 0xF) switch - { - 0x04 => NextLog2(16), // Ryzen - 0x05 => NextLog2(32), // Threadripper - 0x06 => NextLog2(64), // Epic - _ => coreMaskWith - }; - } + 0x04 => NextLog2(16), // Ryzen + 0x05 => NextLog2(32), // Threadripper + 0x06 => NextLog2(64), // Epic + _ => coreMaskWith + }; + } - break; + break; - default: - threadMaskWith = 0; - coreMaskWith = 0; - break; - } - - ProcessorId = ApicId >> (int)(coreMaskWith + threadMaskWith); - CoreId = (ApicId >> (int)threadMaskWith) - (ProcessorId << (int)coreMaskWith); - ThreadId = ApicId - (ProcessorId << (int)(coreMaskWith + threadMaskWith)) - (CoreId << (int)threadMaskWith); + default: + threadMaskWith = 0; + coreMaskWith = 0; + break; } - public GroupAffinity Affinity { get; } - - public uint ApicId { get; } - - public string BrandString { get; } = string.Empty; - - public uint CoreId { get; } - - public uint[,] Data { get; } = new uint[0, 0]; - - public uint[,] ExtData { get; } = new uint[0, 0]; - - public uint Family { get; } - - public int Group { get; } - - public uint Model { get; } - - public string Name { get; } = string.Empty; - - public uint PkgType { get; } - - public uint ProcessorId { get; } - - public uint Stepping { get; } - - public int Thread { get; } - - public uint ThreadId { get; } - - public Vendor Vendor { get; } = Vendor.Unknown; - - /// - /// Gets the specified . - /// - /// The group. - /// The thread. - /// . - public static CpuId Get(int group, int thread) - { - if (thread >= 64) - return null; - - var affinity = GroupAffinity.Single((ushort)group, thread); - - GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); - if (previousAffinity == GroupAffinity.Undefined) - return null; - - try - { - return new CpuId(group, thread, affinity); - } - finally - { - ThreadAffinity.Set(previousAffinity); - } - } - - private static void AppendRegister(StringBuilder b, uint value) - { - b.Append((char)(value & 0xff)); - b.Append((char)((value >> 8) & 0xff)); - b.Append((char)((value >> 16) & 0xff)); - b.Append((char)((value >> 24) & 0xff)); - } - - private static uint NextLog2(long x) - { - if (x <= 0) - return 0; - - x--; - uint count = 0; - while (x > 0) - { - x >>= 1; - count++; - } - - return count; - } - - // ReSharper disable InconsistentNaming - public const uint CPUID_0 = 0; - public const uint CPUID_EXT = 0x80000000; - // ReSharper restore InconsistentNaming + ProcessorId = ApicId >> (int)(coreMaskWith + threadMaskWith); + CoreId = (ApicId >> (int)threadMaskWith) - (ProcessorId << (int)coreMaskWith); + ThreadId = ApicId - (ProcessorId << (int)(coreMaskWith + threadMaskWith)) - (CoreId << (int)threadMaskWith); } + + public GroupAffinity Affinity { get; } + + public uint ApicId { get; } + + public string BrandString { get; } = string.Empty; + + public uint CoreId { get; } + + public uint[,] Data { get; } = new uint[0, 0]; + + public uint[,] ExtData { get; } = new uint[0, 0]; + + public uint Family { get; } + + public int Group { get; } + + public uint Model { get; } + + public string Name { get; } = string.Empty; + + public uint PkgType { get; } + + public uint ProcessorId { get; } + + public uint Stepping { get; } + + public int Thread { get; } + + public uint ThreadId { get; } + + public Vendor Vendor { get; } = Vendor.Unknown; + + /// + /// Gets the specified . + /// + /// The group. + /// The thread. + /// . + public static CpuId Get(int group, int thread) + { + if (thread >= 64) + return null; + + var affinity = GroupAffinity.Single((ushort)group, thread); + + GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); + if (previousAffinity == GroupAffinity.Undefined) + return null; + + try + { + return new CpuId(group, thread, affinity); + } + finally + { + ThreadAffinity.Set(previousAffinity); + } + } + + private static void AppendRegister(StringBuilder b, uint value) + { + b.Append((char)(value & 0xff)); + b.Append((char)((value >> 8) & 0xff)); + b.Append((char)((value >> 16) & 0xff)); + b.Append((char)((value >> 24) & 0xff)); + } + + private static uint NextLog2(long x) + { + if (x <= 0) + return 0; + + x--; + uint count = 0; + while (x > 0) + { + x >>= 1; + count++; + } + + return count; + } + + // ReSharper disable InconsistentNaming + public const uint CPUID_0 = 0; + public const uint CPUID_EXT = 0x80000000; + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/CpuLoad.cs b/LibreHardwareMonitorLib/Hardware/Cpu/CpuLoad.cs index c345510..cf481c1 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/CpuLoad.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/CpuLoad.cs @@ -8,113 +8,112 @@ using System; using System.Linq; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +internal class CpuLoad { - internal class CpuLoad + private long[] _idleTimes; + private readonly float[] _threadLoads; + private float _totalLoad; + private long[] _totalTimes; + + public CpuLoad(CpuId[][] cpuid) { - private long[] _idleTimes; - private readonly float[] _threadLoads; - private float _totalLoad; - private long[] _totalTimes; - - public CpuLoad(CpuId[][] cpuid) + _threadLoads = new float[cpuid.Sum(x => x.Length)]; + _totalLoad = 0; + try { - _threadLoads = new float[cpuid.Sum(x => x.Length)]; - _totalLoad = 0; - try - { - GetTimes(out _idleTimes, out _totalTimes); - } - catch (Exception) - { - _idleTimes = null; - _totalTimes = null; - } - - if (_idleTimes != null) - IsAvailable = true; + GetTimes(out _idleTimes, out _totalTimes); + } + catch (Exception) + { + _idleTimes = null; + _totalTimes = null; } - public bool IsAvailable { get; } + if (_idleTimes != null) + IsAvailable = true; + } - private static bool GetTimes(out long[] idle, out long[] total) + public bool IsAvailable { get; } + + private static bool GetTimes(out long[] idle, out long[] total) + { + Interop.NtDll.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] information = new Interop.NtDll.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[64]; + int size = Marshal.SizeOf(typeof(Interop.NtDll.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); + + idle = null; + total = null; + + if (Interop.NtDll.NtQuerySystemInformation(Interop.NtDll.SYSTEM_INFORMATION_CLASS.SystemProcessorPerformanceInformation, + information, + information.Length * size, + out IntPtr returnLength) != 0) { - Interop.NtDll.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] information = new Interop.NtDll.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[64]; - int size = Marshal.SizeOf(typeof(Interop.NtDll.SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)); - - idle = null; - total = null; - - if (Interop.NtDll.NtQuerySystemInformation(Interop.NtDll.SYSTEM_INFORMATION_CLASS.SystemProcessorPerformanceInformation, - information, - information.Length * size, - out IntPtr returnLength) != 0) - { - return false; - } - - idle = new long[(int)returnLength / size]; - total = new long[(int)returnLength / size]; - - for (int i = 0; i < idle.Length; i++) - { - idle[i] = information[i].IdleTime; - total[i] = information[i].KernelTime + information[i].UserTime; - } - - return true; + return false; } - public float GetTotalLoad() + idle = new long[(int)returnLength / size]; + total = new long[(int)returnLength / size]; + + for (int i = 0; i < idle.Length; i++) { - return _totalLoad; + idle[i] = information[i].IdleTime; + total[i] = information[i].KernelTime + information[i].UserTime; } - public float GetThreadLoad(int thread) - { - return _threadLoads[thread]; - } + return true; + } - public void Update() + public float GetTotalLoad() + { + return _totalLoad; + } + + public float GetThreadLoad(int thread) + { + return _threadLoads[thread]; + } + + public void Update() + { + if (_idleTimes == null) + return; + + if (!GetTimes(out long[] newIdleTimes, out long[] newTotalTimes)) + return; + + for (int i = 0; i < Math.Min(newTotalTimes.Length, _totalTimes.Length); i++) { - if (_idleTimes == null) + if (newTotalTimes[i] - _totalTimes[i] < 100000) return; - - if (!GetTimes(out long[] newIdleTimes, out long[] newTotalTimes)) - return; - - for (int i = 0; i < Math.Min(newTotalTimes.Length, _totalTimes.Length); i++) - { - if (newTotalTimes[i] - _totalTimes[i] < 100000) - return; - } - - if (newIdleTimes == null) - return; - - float total = 0; - int count = 0; - for (int i = 0; i < _threadLoads.Length && i < _idleTimes.Length && i < newIdleTimes.Length; i++) - { - float idle = (newIdleTimes[i] - _idleTimes[i]) / (float)(newTotalTimes[i] - _totalTimes[i]); - _threadLoads[i] = 100f * (1.0f - Math.Min(idle, 1.0f)); - total += idle; - count++; - } - - if (count > 0) - { - total = 1.0f - (total / count); - total = total < 0 ? 0 : total; - } - else - { - total = 0; - } - - _totalLoad = total * 100; - _totalTimes = newTotalTimes; - _idleTimes = newIdleTimes; } + + if (newIdleTimes == null) + return; + + float total = 0; + int count = 0; + for (int i = 0; i < _threadLoads.Length && i < _idleTimes.Length && i < newIdleTimes.Length; i++) + { + float idle = (newIdleTimes[i] - _idleTimes[i]) / (float)(newTotalTimes[i] - _totalTimes[i]); + _threadLoads[i] = 100f * (1.0f - Math.Min(idle, 1.0f)); + total += idle; + count++; + } + + if (count > 0) + { + total = 1.0f - (total / count); + total = total < 0 ? 0 : total; + } + else + { + total = 0; + } + + _totalLoad = total * 100; + _totalTimes = newTotalTimes; + _idleTimes = newIdleTimes; } } diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs index c8a071f..5781e65 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/GenericCpu.cs @@ -10,301 +10,300 @@ using System.Globalization; using System.Linq; using System.Text; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +public class GenericCpu : Hardware { - public class GenericCpu : Hardware + protected readonly int _coreCount; + protected readonly CpuId[][] _cpuId; + protected readonly uint _family; + protected readonly uint _model; + protected readonly uint _packageType; + protected readonly uint _stepping; + protected readonly int _threadCount; + + private readonly CpuLoad _cpuLoad; + private readonly double _estimatedTimeStampCounterFrequency; + private readonly double _estimatedTimeStampCounterFrequencyError; + private readonly bool _isInvariantTimeStampCounter; + private readonly Sensor[] _threadLoads; + + private readonly Sensor _totalLoad; + private readonly Vendor _vendor; + private long _lastTime; + private ulong _lastTimeStampCount; + + public GenericCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(cpuId[0][0].Name, CreateIdentifier(cpuId[0][0].Vendor, processorIndex), settings) { - protected readonly int _coreCount; - protected readonly CpuId[][] _cpuId; - protected readonly uint _family; - protected readonly uint _model; - protected readonly uint _packageType; - protected readonly uint _stepping; - protected readonly int _threadCount; + _cpuId = cpuId; + _vendor = cpuId[0][0].Vendor; + _family = cpuId[0][0].Family; + _model = cpuId[0][0].Model; + _stepping = cpuId[0][0].Stepping; + _packageType = cpuId[0][0].PkgType; - private readonly CpuLoad _cpuLoad; - private readonly double _estimatedTimeStampCounterFrequency; - private readonly double _estimatedTimeStampCounterFrequencyError; - private readonly bool _isInvariantTimeStampCounter; - private readonly Sensor[] _threadLoads; + Index = processorIndex; + _coreCount = cpuId.Length; + _threadCount = cpuId.Sum(x => x.Length); - private readonly Sensor _totalLoad; - private readonly Vendor _vendor; - private long _lastTime; - private ulong _lastTimeStampCount; + // Check if processor has MSRs. + HasModelSpecificRegisters = cpuId[0][0].Data.GetLength(0) > 1 && (cpuId[0][0].Data[1, 3] & 0x20) != 0; - public GenericCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(cpuId[0][0].Name, CreateIdentifier(cpuId[0][0].Vendor, processorIndex), settings) + // Check if processor has a TSC. + HasTimeStampCounter = cpuId[0][0].Data.GetLength(0) > 1 && (cpuId[0][0].Data[1, 3] & 0x10) != 0; + + // Check if processor supports an invariant TSC. + _isInvariantTimeStampCounter = cpuId[0][0].ExtData.GetLength(0) > 7 && (cpuId[0][0].ExtData[7, 3] & 0x100) != 0; + + _totalLoad = _coreCount > 1 ? new Sensor("CPU Total", 0, SensorType.Load, this, settings) : null; + + _cpuLoad = new CpuLoad(cpuId); + if (_cpuLoad.IsAvailable) { - _cpuId = cpuId; - _vendor = cpuId[0][0].Vendor; - _family = cpuId[0][0].Family; - _model = cpuId[0][0].Model; - _stepping = cpuId[0][0].Stepping; - _packageType = cpuId[0][0].PkgType; - - Index = processorIndex; - _coreCount = cpuId.Length; - _threadCount = cpuId.Sum(x => x.Length); - - // Check if processor has MSRs. - HasModelSpecificRegisters = cpuId[0][0].Data.GetLength(0) > 1 && (cpuId[0][0].Data[1, 3] & 0x20) != 0; - - // Check if processor has a TSC. - HasTimeStampCounter = cpuId[0][0].Data.GetLength(0) > 1 && (cpuId[0][0].Data[1, 3] & 0x10) != 0; - - // Check if processor supports an invariant TSC. - _isInvariantTimeStampCounter = cpuId[0][0].ExtData.GetLength(0) > 7 && (cpuId[0][0].ExtData[7, 3] & 0x100) != 0; - - _totalLoad = _coreCount > 1 ? new Sensor("CPU Total", 0, SensorType.Load, this, settings) : null; - - _cpuLoad = new CpuLoad(cpuId); - if (_cpuLoad.IsAvailable) + _threadLoads = new Sensor[_threadCount]; + for (int coreIdx = 0; coreIdx < cpuId.Length; coreIdx++) { - _threadLoads = new Sensor[_threadCount]; - for (int coreIdx = 0; coreIdx < cpuId.Length; coreIdx++) + for (int threadIdx = 0; threadIdx < cpuId[coreIdx].Length; threadIdx++) { - for (int threadIdx = 0; threadIdx < cpuId[coreIdx].Length; threadIdx++) + int thread = cpuId[coreIdx][threadIdx].Thread; + if (thread < _threadLoads.Length) { - int thread = cpuId[coreIdx][threadIdx].Thread; - if (thread < _threadLoads.Length) - { - // Some cores may have 2 threads while others have only one (e.g. P-cores vs E-cores on Intel 12th gen). - string sensorName = CoreString(coreIdx) + (cpuId[coreIdx].Length > 1 ? $" Thread #{threadIdx + 1}" : string.Empty); - _threadLoads[thread] = new Sensor(sensorName, thread + 1, SensorType.Load, this, settings); + // Some cores may have 2 threads while others have only one (e.g. P-cores vs E-cores on Intel 12th gen). + string sensorName = CoreString(coreIdx) + (cpuId[coreIdx].Length > 1 ? $" Thread #{threadIdx + 1}" : string.Empty); + _threadLoads[thread] = new Sensor(sensorName, thread + 1, SensorType.Load, this, settings); - ActivateSensor(_threadLoads[thread]); - } + ActivateSensor(_threadLoads[thread]); } } - - if (_totalLoad != null) - { - ActivateSensor(_totalLoad); - } } - if (HasTimeStampCounter) + if (_totalLoad != null) { - GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId[0][0].Affinity); - EstimateTimeStampCounterFrequency(out _estimatedTimeStampCounterFrequency, out _estimatedTimeStampCounterFrequencyError); - ThreadAffinity.Set(previousAffinity); - } - else - { - _estimatedTimeStampCounterFrequency = 0; - } - - TimeStampCounterFrequency = _estimatedTimeStampCounterFrequency; - } - - /// - /// Gets the CPUID. - /// - public CpuId[][] CpuId => _cpuId; - - public override HardwareType HardwareType => HardwareType.Cpu; - - public bool HasModelSpecificRegisters { get; } - - public bool HasTimeStampCounter { get; } - - /// - /// Gets the CPU index. - /// - public int Index { get; } - - public double TimeStampCounterFrequency { get; private set; } - - protected string CoreString(int i) - { - if (_coreCount == 1) - return "CPU Core"; - - return "CPU Core #" + (i + 1); - } - - private static Identifier CreateIdentifier(Vendor vendor, int processorIndex) - { - string s = vendor switch - { - Vendor.AMD => "amdcpu", - Vendor.Intel => "intelcpu", - _ => "genericcpu" - }; - - return new Identifier(s, processorIndex.ToString(CultureInfo.InvariantCulture)); - } - - private static void EstimateTimeStampCounterFrequency(out double frequency, out double error) - { - // preload the function - EstimateTimeStampCounterFrequency(0, out double f, out double e); - EstimateTimeStampCounterFrequency(0, out f, out e); - - // estimate the frequency - error = double.MaxValue; - frequency = 0; - for (int i = 0; i < 5; i++) - { - EstimateTimeStampCounterFrequency(0.025, out f, out e); - if (e < error) - { - error = e; - frequency = f; - } - - if (error < 1e-4) - break; + ActivateSensor(_totalLoad); } } - private static void EstimateTimeStampCounterFrequency(double timeWindow, out double frequency, out double error) + if (HasTimeStampCounter) { - long ticks = (long)(timeWindow * Stopwatch.Frequency); - - long timeBegin = Stopwatch.GetTimestamp() + (long)Math.Ceiling(0.001 * ticks); - long timeEnd = timeBegin + ticks; - - while (Stopwatch.GetTimestamp() < timeBegin) - { } - - ulong countBegin = OpCode.Rdtsc(); - long afterBegin = Stopwatch.GetTimestamp(); - - while (Stopwatch.GetTimestamp() < timeEnd) - { } - - ulong countEnd = OpCode.Rdtsc(); - long afterEnd = Stopwatch.GetTimestamp(); - - double delta = timeEnd - timeBegin; - frequency = 1e-6 * ((double)(countEnd - countBegin) * Stopwatch.Frequency) / delta; - - double beginError = (afterBegin - timeBegin) / delta; - double endError = (afterEnd - timeEnd) / delta; - error = beginError + endError; + GroupAffinity previousAffinity = ThreadAffinity.Set(cpuId[0][0].Affinity); + EstimateTimeStampCounterFrequency(out _estimatedTimeStampCounterFrequency, out _estimatedTimeStampCounterFrequencyError); + ThreadAffinity.Set(previousAffinity); + } + else + { + _estimatedTimeStampCounterFrequency = 0; } - private static void AppendMsrData(StringBuilder r, uint msr, GroupAffinity affinity) + TimeStampCounterFrequency = _estimatedTimeStampCounterFrequency; + } + + /// + /// Gets the CPUID. + /// + public CpuId[][] CpuId => _cpuId; + + public override HardwareType HardwareType => HardwareType.Cpu; + + public bool HasModelSpecificRegisters { get; } + + public bool HasTimeStampCounter { get; } + + /// + /// Gets the CPU index. + /// + public int Index { get; } + + public double TimeStampCounterFrequency { get; private set; } + + protected string CoreString(int i) + { + if (_coreCount == 1) + return "CPU Core"; + + return "CPU Core #" + (i + 1); + } + + private static Identifier CreateIdentifier(Vendor vendor, int processorIndex) + { + string s = vendor switch { - if (Ring0.ReadMsr(msr, out uint eax, out uint edx, affinity)) + Vendor.AMD => "amdcpu", + Vendor.Intel => "intelcpu", + _ => "genericcpu" + }; + + return new Identifier(s, processorIndex.ToString(CultureInfo.InvariantCulture)); + } + + private static void EstimateTimeStampCounterFrequency(out double frequency, out double error) + { + // preload the function + EstimateTimeStampCounterFrequency(0, out double f, out double e); + EstimateTimeStampCounterFrequency(0, out f, out e); + + // estimate the frequency + error = double.MaxValue; + frequency = 0; + for (int i = 0; i < 5; i++) + { + EstimateTimeStampCounterFrequency(0.025, out f, out e); + if (e < error) { - r.Append(" "); - r.Append(msr.ToString("X8", CultureInfo.InvariantCulture)); - r.Append(" "); - r.Append(edx.ToString("X8", CultureInfo.InvariantCulture)); - r.Append(" "); - r.Append(eax.ToString("X8", CultureInfo.InvariantCulture)); + error = e; + frequency = f; + } + + if (error < 1e-4) + break; + } + } + + private static void EstimateTimeStampCounterFrequency(double timeWindow, out double frequency, out double error) + { + long ticks = (long)(timeWindow * Stopwatch.Frequency); + + long timeBegin = Stopwatch.GetTimestamp() + (long)Math.Ceiling(0.001 * ticks); + long timeEnd = timeBegin + ticks; + + while (Stopwatch.GetTimestamp() < timeBegin) + { } + + ulong countBegin = OpCode.Rdtsc(); + long afterBegin = Stopwatch.GetTimestamp(); + + while (Stopwatch.GetTimestamp() < timeEnd) + { } + + ulong countEnd = OpCode.Rdtsc(); + long afterEnd = Stopwatch.GetTimestamp(); + + double delta = timeEnd - timeBegin; + frequency = 1e-6 * ((double)(countEnd - countBegin) * Stopwatch.Frequency) / delta; + + double beginError = (afterBegin - timeBegin) / delta; + double endError = (afterEnd - timeEnd) / delta; + error = beginError + endError; + } + + private static void AppendMsrData(StringBuilder r, uint msr, GroupAffinity affinity) + { + if (Ring0.ReadMsr(msr, out uint eax, out uint edx, affinity)) + { + r.Append(" "); + r.Append(msr.ToString("X8", CultureInfo.InvariantCulture)); + r.Append(" "); + r.Append(edx.ToString("X8", CultureInfo.InvariantCulture)); + r.Append(" "); + r.Append(eax.ToString("X8", CultureInfo.InvariantCulture)); + r.AppendLine(); + } + } + + protected virtual uint[] GetMsrs() + { + return null; + } + + public override string GetReport() + { + StringBuilder r = new(); + + switch (_vendor) + { + case Vendor.AMD: + r.AppendLine("AMD CPU"); + break; + case Vendor.Intel: + r.AppendLine("Intel CPU"); + break; + default: + r.AppendLine("Generic CPU"); + break; + } + + r.AppendLine(); + r.AppendFormat("Name: {0}{1}", _name, Environment.NewLine); + r.AppendFormat("Number of Cores: {0}{1}", _coreCount, Environment.NewLine); + r.AppendFormat("Threads per Core: {0}{1}", _cpuId[0].Length, Environment.NewLine); + r.AppendLine(string.Format(CultureInfo.InvariantCulture, "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6)); + r.AppendLine("Time Stamp Counter: " + (HasTimeStampCounter ? _isInvariantTimeStampCounter ? "Invariant" : "Not Invariant" : "None")); + r.AppendLine(string.Format(CultureInfo.InvariantCulture, "Estimated Time Stamp Counter Frequency: {0} MHz", Math.Round(_estimatedTimeStampCounterFrequency * 100) * 0.01)); + r.AppendLine(string.Format(CultureInfo.InvariantCulture, + "Estimated Time Stamp Counter Frequency Error: {0} Mhz", + Math.Round(_estimatedTimeStampCounterFrequency * _estimatedTimeStampCounterFrequencyError * 1e5) * 1e-5)); + + r.AppendLine(string.Format(CultureInfo.InvariantCulture, "Time Stamp Counter Frequency: {0} MHz", Math.Round(TimeStampCounterFrequency * 100) * 0.01)); + r.AppendLine(); + + uint[] msrArray = GetMsrs(); + if (msrArray is { Length: > 0 }) + { + for (int i = 0; i < _cpuId.Length; i++) + { + r.AppendLine("MSR Core #" + (i + 1)); + r.AppendLine(); + r.AppendLine(" MSR EDX EAX"); + foreach (uint msr in msrArray) + AppendMsrData(r, msr, _cpuId[i][0].Affinity); + r.AppendLine(); } } - protected virtual uint[] GetMsrs() + return r.ToString(); + } + + public override void Update() + { + if (HasTimeStampCounter && _isInvariantTimeStampCounter) { - return null; + // make sure always the same thread is used + GroupAffinity previousAffinity = ThreadAffinity.Set(_cpuId[0][0].Affinity); + + // read time before and after getting the TSC to estimate the error + long firstTime = Stopwatch.GetTimestamp(); + ulong timeStampCount = OpCode.Rdtsc(); + long time = Stopwatch.GetTimestamp(); + + // restore the thread affinity mask + ThreadAffinity.Set(previousAffinity); + + double delta = (double)(time - _lastTime) / Stopwatch.Frequency; + double error = (double)(time - firstTime) / Stopwatch.Frequency; + + // only use data if they are measured accurate enough (max 0.1ms delay) + if (error < 0.0001) + { + // ignore the first reading because there are no initial values + // ignore readings with too large or too small time window + if (_lastTime != 0 && delta is > 0.5 and < 2) + { + // update the TSC frequency with the new value + TimeStampCounterFrequency = (timeStampCount - _lastTimeStampCount) / (1e6 * delta); + } + + _lastTimeStampCount = timeStampCount; + _lastTime = time; + } } - public override string GetReport() + if (_cpuLoad.IsAvailable) { - StringBuilder r = new(); + _cpuLoad.Update(); - switch (_vendor) + if (_threadLoads != null) { - case Vendor.AMD: - r.AppendLine("AMD CPU"); - break; - case Vendor.Intel: - r.AppendLine("Intel CPU"); - break; - default: - r.AppendLine("Generic CPU"); - break; - } - - r.AppendLine(); - r.AppendFormat("Name: {0}{1}", _name, Environment.NewLine); - r.AppendFormat("Number of Cores: {0}{1}", _coreCount, Environment.NewLine); - r.AppendFormat("Threads per Core: {0}{1}", _cpuId[0].Length, Environment.NewLine); - r.AppendLine(string.Format(CultureInfo.InvariantCulture, "Timer Frequency: {0} MHz", Stopwatch.Frequency * 1e-6)); - r.AppendLine("Time Stamp Counter: " + (HasTimeStampCounter ? _isInvariantTimeStampCounter ? "Invariant" : "Not Invariant" : "None")); - r.AppendLine(string.Format(CultureInfo.InvariantCulture, "Estimated Time Stamp Counter Frequency: {0} MHz", Math.Round(_estimatedTimeStampCounterFrequency * 100) * 0.01)); - r.AppendLine(string.Format(CultureInfo.InvariantCulture, - "Estimated Time Stamp Counter Frequency Error: {0} Mhz", - Math.Round(_estimatedTimeStampCounterFrequency * _estimatedTimeStampCounterFrequencyError * 1e5) * 1e-5)); - - r.AppendLine(string.Format(CultureInfo.InvariantCulture, "Time Stamp Counter Frequency: {0} MHz", Math.Round(TimeStampCounterFrequency * 100) * 0.01)); - r.AppendLine(); - - uint[] msrArray = GetMsrs(); - if (msrArray is { Length: > 0 }) - { - for (int i = 0; i < _cpuId.Length; i++) + for (int i = 0; i < _threadLoads.Length; i++) { - r.AppendLine("MSR Core #" + (i + 1)); - r.AppendLine(); - r.AppendLine(" MSR EDX EAX"); - foreach (uint msr in msrArray) - AppendMsrData(r, msr, _cpuId[i][0].Affinity); - - r.AppendLine(); - } - } - - return r.ToString(); - } - - public override void Update() - { - if (HasTimeStampCounter && _isInvariantTimeStampCounter) - { - // make sure always the same thread is used - GroupAffinity previousAffinity = ThreadAffinity.Set(_cpuId[0][0].Affinity); - - // read time before and after getting the TSC to estimate the error - long firstTime = Stopwatch.GetTimestamp(); - ulong timeStampCount = OpCode.Rdtsc(); - long time = Stopwatch.GetTimestamp(); - - // restore the thread affinity mask - ThreadAffinity.Set(previousAffinity); - - double delta = (double)(time - _lastTime) / Stopwatch.Frequency; - double error = (double)(time - firstTime) / Stopwatch.Frequency; - - // only use data if they are measured accurate enough (max 0.1ms delay) - if (error < 0.0001) - { - // ignore the first reading because there are no initial values - // ignore readings with too large or too small time window - if (_lastTime != 0 && delta is > 0.5 and < 2) + if (_threadLoads[i] != null) { - // update the TSC frequency with the new value - TimeStampCounterFrequency = (timeStampCount - _lastTimeStampCount) / (1e6 * delta); - } - - _lastTimeStampCount = timeStampCount; - _lastTime = time; - } - } - - if (_cpuLoad.IsAvailable) - { - _cpuLoad.Update(); - - if (_threadLoads != null) - { - for (int i = 0; i < _threadLoads.Length; i++) - { - if (_threadLoads[i] != null) - { - _threadLoads[i].Value = _cpuLoad.GetThreadLoad(i); - } + _threadLoads[i].Value = _cpuLoad.GetThreadLoad(i); } } - - if (_totalLoad != null) - _totalLoad.Value = _cpuLoad.GetTotalLoad(); } + + if (_totalLoad != null) + _totalLoad.Value = _cpuLoad.GetTotalLoad(); } } } diff --git a/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs b/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs index bcc7bc0..bec1013 100644 --- a/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Cpu/IntelCpu.cs @@ -9,693 +9,692 @@ using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Text; -namespace LibreHardwareMonitor.Hardware.CPU +namespace LibreHardwareMonitor.Hardware.CPU; + +internal sealed class IntelCpu : GenericCpu { - internal sealed class IntelCpu : GenericCpu + private readonly Sensor _busClock; + private readonly Sensor _coreAvg; + private readonly Sensor[] _coreClocks; + private readonly Sensor _coreMax; + private readonly Sensor[] _coreTemperatures; + private readonly Sensor[] _coreVIDs; + private readonly Sensor _coreVoltage; + private readonly Sensor[] _distToTjMaxTemperatures; + + private readonly uint[] _energyStatusMsrs = { MSR_PKG_ENERGY_STATUS, MSR_PP0_ENERGY_STATUS, MSR_PP1_ENERGY_STATUS, MSR_DRAM_ENERGY_STATUS }; + private readonly uint[] _lastEnergyConsumed; + private readonly DateTime[] _lastEnergyTime; + + private readonly MicroArchitecture _microArchitecture; + private readonly Sensor _packageTemperature; + private readonly Sensor[] _powerSensors; + private readonly double _timeStampCounterMultiplier; + + public IntelCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) { - private readonly Sensor _busClock; - private readonly Sensor _coreAvg; - private readonly Sensor[] _coreClocks; - private readonly Sensor _coreMax; - private readonly Sensor[] _coreTemperatures; - private readonly Sensor[] _coreVIDs; - private readonly Sensor _coreVoltage; - private readonly Sensor[] _distToTjMaxTemperatures; + uint eax; - private readonly uint[] _energyStatusMsrs = { MSR_PKG_ENERGY_STATUS, MSR_PP0_ENERGY_STATUS, MSR_PP1_ENERGY_STATUS, MSR_DRAM_ENERGY_STATUS }; - private readonly uint[] _lastEnergyConsumed; - private readonly DateTime[] _lastEnergyTime; - - private readonly MicroArchitecture _microArchitecture; - private readonly Sensor _packageTemperature; - private readonly Sensor[] _powerSensors; - private readonly double _timeStampCounterMultiplier; - - public IntelCpu(int processorIndex, CpuId[][] cpuId, ISettings settings) : base(processorIndex, cpuId, settings) + // set tjMax + float[] tjMax; + switch (_family) { - uint eax; - - // set tjMax - float[] tjMax; - switch (_family) - { - case 0x06: - { - switch (_model) - { - case 0x0F: // Intel Core 2 (65nm) - _microArchitecture = MicroArchitecture.Core; - tjMax = _stepping switch - { - // B2 - 0x06 => _coreCount switch - { - 2 => Floats(80 + 10), - 4 => Floats(90 + 10), - _ => Floats(85 + 10) - }, - // G0 - 0x0B => Floats(90 + 10), - // M0 - 0x0D => Floats(85 + 10), - _ => Floats(85 + 10) - }; - break; - - case 0x17: // Intel Core 2 (45nm) - _microArchitecture = MicroArchitecture.Core; - tjMax = Floats(100); - break; - - case 0x1C: // Intel Atom (45nm) - _microArchitecture = MicroArchitecture.Atom; - tjMax = _stepping switch - { - // C0 - 0x02 => Floats(90), - // A0, B0 - 0x0A => Floats(100), - _ => Floats(90) - }; - break; - - case 0x1A: // Intel Core i7 LGA1366 (45nm) - case 0x1E: // Intel Core i5, i7 LGA1156 (45nm) - case 0x1F: // Intel Core i5, i7 - case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm) - case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core - case 0x2E: // Intel Xeon Processor 7500 series (45nm) - case 0x2F: // Intel Xeon Processor (32nm) - _microArchitecture = MicroArchitecture.Nehalem; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm) - case 0x2D: // Next Generation Intel Xeon, i7 3xxx LGA2011 (32nm) - _microArchitecture = MicroArchitecture.SandyBridge; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x3A: // Intel Core i5, i7 3xxx LGA1155 (22nm) - case 0x3E: // Intel Core i7 4xxx LGA2011 (22nm) - _microArchitecture = MicroArchitecture.IvyBridge; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm) - case 0x3F: // Intel Xeon E5-2600/1600 v3, Core i7-59xx - // LGA2011-v3, Haswell-E (22nm) - case 0x45: // Intel Core i5, i7 4xxxU (22nm) - case 0x46: - _microArchitecture = MicroArchitecture.Haswell; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x3D: // Intel Core M-5xxx (14nm) - case 0x47: // Intel i5, i7 5xxx, Xeon E3-1200 v4 (14nm) - case 0x4F: // Intel Xeon E5-26xx v4 - case 0x56: // Intel Xeon D-15xx - _microArchitecture = MicroArchitecture.Broadwell; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x36: // Intel Atom S1xxx, D2xxx, N2xxx (32nm) - _microArchitecture = MicroArchitecture.Atom; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x37: // Intel Atom E3xxx, Z3xxx (22nm) - case 0x4A: - case 0x4D: // Intel Atom C2xxx (22nm) - case 0x5A: - case 0x5D: - _microArchitecture = MicroArchitecture.Silvermont; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x4E: - case 0x5E: // Intel Core i5, i7 6xxxx LGA1151 (14nm) - case 0x55: // Intel Core X i7, i9 7xxx LGA2066 (14nm) - _microArchitecture = MicroArchitecture.Skylake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x4C: // Intel Airmont (Cherry Trail, Braswell) - _microArchitecture = MicroArchitecture.Airmont; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x8E: // Intel Core i5, i7 7xxxx (14nm) (Kaby Lake) and 8xxxx (14nm++) (Coffee Lake) - case 0x9E: - _microArchitecture = MicroArchitecture.KabyLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x5C: // Goldmont (Apollo Lake) - case 0x5F: // (Denverton) - _microArchitecture = MicroArchitecture.Goldmont; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x7A: // Goldmont plus (Gemini Lake) - _microArchitecture = MicroArchitecture.GoldmontPlus; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x66: // Intel Core i3 8xxx (10nm) (Cannon Lake) - _microArchitecture = MicroArchitecture.CannonLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x7D: // Intel Core i3, i5, i7 10xxx (10nm) (Ice Lake) - case 0x7E: - case 0x6A: // Ice Lake server - case 0x6C: - _microArchitecture = MicroArchitecture.IceLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0xA5: - case 0xA6: // Intel Core i3, i5, i7 10xxxU (14nm) - _microArchitecture = MicroArchitecture.CometLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x86: // Tremont (10nm) (Elkhart Lake, Skyhawk Lake) - _microArchitecture = MicroArchitecture.Tremont; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x8C: // Tiger Lake (10nm) - case 0x8D: - _microArchitecture = MicroArchitecture.TigerLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x97: // Alder Lake (7/10nm) - case 0x9A: // Alder Lake-L (7/10nm) - case 0xBE: // Alder Lake-N (7/10nm) - _microArchitecture = MicroArchitecture.AlderLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0xB7: // Raptor Lake (7nm) - case 0xBA: // Raptor Lake-P (7nm) - case 0xBF: // Raptor Lake-N (7nm) - _microArchitecture = MicroArchitecture.RaptorLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0x9C: // Jasper Lake (10nm) - _microArchitecture = MicroArchitecture.JasperLake; - tjMax = GetTjMaxFromMsr(); - break; - - case 0xA7: // Intel Core i5, i6, i7 11xxx (14nm) (Rocket Lake) - _microArchitecture = MicroArchitecture.RocketLake; - tjMax = GetTjMaxFromMsr(); - break; - - default: - _microArchitecture = MicroArchitecture.Unknown; - tjMax = Floats(100); - break; - } - } - - break; - case 0x0F: + case 0x06: + { switch (_model) { - case 0x00: // Pentium 4 (180nm) - case 0x01: // Pentium 4 (130nm) - case 0x02: // Pentium 4 (130nm) - case 0x03: // Pentium 4, Celeron D (90nm) - case 0x04: // Pentium 4, Pentium D, Celeron D (90nm) - case 0x06: // Pentium 4, Pentium D, Celeron D (65nm) - _microArchitecture = MicroArchitecture.NetBurst; + case 0x0F: // Intel Core 2 (65nm) + _microArchitecture = MicroArchitecture.Core; + tjMax = _stepping switch + { + // B2 + 0x06 => _coreCount switch + { + 2 => Floats(80 + 10), + 4 => Floats(90 + 10), + _ => Floats(85 + 10) + }, + // G0 + 0x0B => Floats(90 + 10), + // M0 + 0x0D => Floats(85 + 10), + _ => Floats(85 + 10) + }; + break; + + case 0x17: // Intel Core 2 (45nm) + _microArchitecture = MicroArchitecture.Core; tjMax = Floats(100); break; + case 0x1C: // Intel Atom (45nm) + _microArchitecture = MicroArchitecture.Atom; + tjMax = _stepping switch + { + // C0 + 0x02 => Floats(90), + // A0, B0 + 0x0A => Floats(100), + _ => Floats(90) + }; + break; + + case 0x1A: // Intel Core i7 LGA1366 (45nm) + case 0x1E: // Intel Core i5, i7 LGA1156 (45nm) + case 0x1F: // Intel Core i5, i7 + case 0x25: // Intel Core i3, i5, i7 LGA1156 (32nm) + case 0x2C: // Intel Core i7 LGA1366 (32nm) 6 Core + case 0x2E: // Intel Xeon Processor 7500 series (45nm) + case 0x2F: // Intel Xeon Processor (32nm) + _microArchitecture = MicroArchitecture.Nehalem; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x2A: // Intel Core i5, i7 2xxx LGA1155 (32nm) + case 0x2D: // Next Generation Intel Xeon, i7 3xxx LGA2011 (32nm) + _microArchitecture = MicroArchitecture.SandyBridge; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x3A: // Intel Core i5, i7 3xxx LGA1155 (22nm) + case 0x3E: // Intel Core i7 4xxx LGA2011 (22nm) + _microArchitecture = MicroArchitecture.IvyBridge; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x3C: // Intel Core i5, i7 4xxx LGA1150 (22nm) + case 0x3F: // Intel Xeon E5-2600/1600 v3, Core i7-59xx + // LGA2011-v3, Haswell-E (22nm) + case 0x45: // Intel Core i5, i7 4xxxU (22nm) + case 0x46: + _microArchitecture = MicroArchitecture.Haswell; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x3D: // Intel Core M-5xxx (14nm) + case 0x47: // Intel i5, i7 5xxx, Xeon E3-1200 v4 (14nm) + case 0x4F: // Intel Xeon E5-26xx v4 + case 0x56: // Intel Xeon D-15xx + _microArchitecture = MicroArchitecture.Broadwell; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x36: // Intel Atom S1xxx, D2xxx, N2xxx (32nm) + _microArchitecture = MicroArchitecture.Atom; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x37: // Intel Atom E3xxx, Z3xxx (22nm) + case 0x4A: + case 0x4D: // Intel Atom C2xxx (22nm) + case 0x5A: + case 0x5D: + _microArchitecture = MicroArchitecture.Silvermont; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x4E: + case 0x5E: // Intel Core i5, i7 6xxxx LGA1151 (14nm) + case 0x55: // Intel Core X i7, i9 7xxx LGA2066 (14nm) + _microArchitecture = MicroArchitecture.Skylake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x4C: // Intel Airmont (Cherry Trail, Braswell) + _microArchitecture = MicroArchitecture.Airmont; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x8E: // Intel Core i5, i7 7xxxx (14nm) (Kaby Lake) and 8xxxx (14nm++) (Coffee Lake) + case 0x9E: + _microArchitecture = MicroArchitecture.KabyLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x5C: // Goldmont (Apollo Lake) + case 0x5F: // (Denverton) + _microArchitecture = MicroArchitecture.Goldmont; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x7A: // Goldmont plus (Gemini Lake) + _microArchitecture = MicroArchitecture.GoldmontPlus; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x66: // Intel Core i3 8xxx (10nm) (Cannon Lake) + _microArchitecture = MicroArchitecture.CannonLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x7D: // Intel Core i3, i5, i7 10xxx (10nm) (Ice Lake) + case 0x7E: + case 0x6A: // Ice Lake server + case 0x6C: + _microArchitecture = MicroArchitecture.IceLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0xA5: + case 0xA6: // Intel Core i3, i5, i7 10xxxU (14nm) + _microArchitecture = MicroArchitecture.CometLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x86: // Tremont (10nm) (Elkhart Lake, Skyhawk Lake) + _microArchitecture = MicroArchitecture.Tremont; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x8C: // Tiger Lake (10nm) + case 0x8D: + _microArchitecture = MicroArchitecture.TigerLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x97: // Alder Lake (7/10nm) + case 0x9A: // Alder Lake-L (7/10nm) + case 0xBE: // Alder Lake-N (7/10nm) + _microArchitecture = MicroArchitecture.AlderLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0xB7: // Raptor Lake (7nm) + case 0xBA: // Raptor Lake-P (7nm) + case 0xBF: // Raptor Lake-N (7nm) + _microArchitecture = MicroArchitecture.RaptorLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0x9C: // Jasper Lake (10nm) + _microArchitecture = MicroArchitecture.JasperLake; + tjMax = GetTjMaxFromMsr(); + break; + + case 0xA7: // Intel Core i5, i6, i7 11xxx (14nm) (Rocket Lake) + _microArchitecture = MicroArchitecture.RocketLake; + tjMax = GetTjMaxFromMsr(); + break; + default: _microArchitecture = MicroArchitecture.Unknown; tjMax = Floats(100); break; } - - break; - default: - _microArchitecture = MicroArchitecture.Unknown; - tjMax = Floats(100); - break; - } - - // set timeStampCounterMultiplier - switch (_microArchitecture) - { - case MicroArchitecture.Atom: - case MicroArchitecture.Core: - case MicroArchitecture.NetBurst: - if (Ring0.ReadMsr(IA32_PERF_STATUS, out uint _, out uint edx)) - _timeStampCounterMultiplier = ((edx >> 8) & 0x1f) + (0.5 * ((edx >> 14) & 1)); - - break; - case MicroArchitecture.Airmont: - case MicroArchitecture.AlderLake: - case MicroArchitecture.Broadwell: - case MicroArchitecture.CannonLake: - case MicroArchitecture.CometLake: - case MicroArchitecture.Goldmont: - case MicroArchitecture.GoldmontPlus: - case MicroArchitecture.Haswell: - case MicroArchitecture.IceLake: - case MicroArchitecture.IvyBridge: - case MicroArchitecture.JasperLake: - case MicroArchitecture.KabyLake: - case MicroArchitecture.Nehalem: - case MicroArchitecture.RaptorLake: - case MicroArchitecture.RocketLake: - case MicroArchitecture.SandyBridge: - case MicroArchitecture.Silvermont: - case MicroArchitecture.Skylake: - case MicroArchitecture.TigerLake: - case MicroArchitecture.Tremont: - if (Ring0.ReadMsr(MSR_PLATFORM_INFO, out eax, out uint _)) - _timeStampCounterMultiplier = (eax >> 8) & 0xff; - - break; - default: - _timeStampCounterMultiplier = 0; - break; - } - - int coreSensorId = 0; - - // check if processor supports a digital thermal sensor at core level - if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 1) != 0 && _microArchitecture != MicroArchitecture.Unknown) - { - _coreTemperatures = new Sensor[_coreCount]; - for (int i = 0; i < _coreTemperatures.Length; i++) - { - _coreTemperatures[i] = new Sensor(CoreString(i), - coreSensorId, - SensorType.Temperature, - this, - new[] - { - new ParameterDescription("TjMax [°C]", "TjMax temperature of the core sensor.\n" + "Temperature = TjMax - TSlope * Value.", tjMax[i]), - new ParameterDescription("TSlope [°C]", "Temperature slope of the digital thermal sensor.\n" + "Temperature = TjMax - TSlope * Value.", 1) - }, - settings); - - ActivateSensor(_coreTemperatures[i]); - coreSensorId++; - } - } - else - _coreTemperatures = Array.Empty(); - - // check if processor supports a digital thermal sensor at package level - if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 0x40) != 0 && _microArchitecture != MicroArchitecture.Unknown) - { - _packageTemperature = new Sensor("CPU Package", - coreSensorId, - SensorType.Temperature, - this, - new[] - { - new ParameterDescription("TjMax [°C]", "TjMax temperature of the package sensor.\n" + "Temperature = TjMax - TSlope * Value.", tjMax[0]), - new ParameterDescription("TSlope [°C]", "Temperature slope of the digital thermal sensor.\n" + "Temperature = TjMax - TSlope * Value.", 1) - }, - settings); - - ActivateSensor(_packageTemperature); - coreSensorId++; - } - - // dist to tjmax sensor - if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 1) != 0 && _microArchitecture != MicroArchitecture.Unknown) - { - _distToTjMaxTemperatures = new Sensor[_coreCount]; - for (int i = 0; i < _distToTjMaxTemperatures.Length; i++) - { - _distToTjMaxTemperatures[i] = new Sensor(CoreString(i) + " Distance to TjMax", coreSensorId, SensorType.Temperature, this, settings); - ActivateSensor(_distToTjMaxTemperatures[i]); - coreSensorId++; - } - } - else - _distToTjMaxTemperatures = Array.Empty(); - - //core temp avg and max value - //is only available when the cpu has more than 1 core - if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 0x40) != 0 && _microArchitecture != MicroArchitecture.Unknown && _coreCount > 1) - { - _coreMax = new Sensor("Core Max", coreSensorId, SensorType.Temperature, this, settings); - ActivateSensor(_coreMax); - coreSensorId++; - - _coreAvg = new Sensor("Core Average", coreSensorId, SensorType.Temperature, this, settings); - ActivateSensor(_coreAvg); - } - else - { - _coreMax = null; - _coreAvg = null; - } - - _busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings); - _coreClocks = new Sensor[_coreCount]; - for (int i = 0; i < _coreClocks.Length; i++) - { - _coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); - if (HasTimeStampCounter && _microArchitecture != MicroArchitecture.Unknown) - ActivateSensor(_coreClocks[i]); - } - - if (_microArchitecture is MicroArchitecture.Airmont or - MicroArchitecture.AlderLake or - MicroArchitecture.Broadwell or - MicroArchitecture.CannonLake or - MicroArchitecture.CometLake or - MicroArchitecture.Goldmont or - MicroArchitecture.GoldmontPlus or - MicroArchitecture.Haswell or - MicroArchitecture.IceLake or - MicroArchitecture.IvyBridge or - MicroArchitecture.JasperLake or - MicroArchitecture.KabyLake or - MicroArchitecture.RaptorLake or - MicroArchitecture.RocketLake or - MicroArchitecture.SandyBridge or - MicroArchitecture.Silvermont or - MicroArchitecture.Skylake or - MicroArchitecture.TigerLake or - MicroArchitecture.Tremont) - { - _powerSensors = new Sensor[_energyStatusMsrs.Length]; - _lastEnergyTime = new DateTime[_energyStatusMsrs.Length]; - _lastEnergyConsumed = new uint[_energyStatusMsrs.Length]; - - if (Ring0.ReadMsr(MSR_RAPL_POWER_UNIT, out eax, out uint _)) - { - EnergyUnitsMultiplier = _microArchitecture switch - { - MicroArchitecture.Silvermont or MicroArchitecture.Airmont => 1.0e-6f * (1 << (int)((eax >> 8) & 0x1F)), - _ => 1.0f / (1 << (int)((eax >> 8) & 0x1F)) - }; } - if (EnergyUnitsMultiplier != 0) + break; + case 0x0F: + switch (_model) { - string[] powerSensorLabels = { "CPU Package", "CPU Cores", "CPU Graphics", "CPU Memory" }; + case 0x00: // Pentium 4 (180nm) + case 0x01: // Pentium 4 (130nm) + case 0x02: // Pentium 4 (130nm) + case 0x03: // Pentium 4, Celeron D (90nm) + case 0x04: // Pentium 4, Pentium D, Celeron D (90nm) + case 0x06: // Pentium 4, Pentium D, Celeron D (65nm) + _microArchitecture = MicroArchitecture.NetBurst; + tjMax = Floats(100); + break; - for (int i = 0; i < _energyStatusMsrs.Length; i++) - { - if (!Ring0.ReadMsr(_energyStatusMsrs[i], out eax, out uint _)) - continue; - - // Don't show the "GPU Graphics" sensor on windows, it will show up under the GPU instead. - if (i == 2 && !Software.OperatingSystem.IsUnix) - continue; - - _lastEnergyTime[i] = DateTime.UtcNow; - _lastEnergyConsumed[i] = eax; - _powerSensors[i] = new Sensor(powerSensorLabels[i], - i, - SensorType.Power, - this, - settings); - - ActivateSensor(_powerSensors[i]); - } + default: + _microArchitecture = MicroArchitecture.Unknown; + tjMax = Floats(100); + break; } - } - if (Ring0.ReadMsr(IA32_PERF_STATUS, out eax, out uint _) && ((eax >> 32) & 0xFFFF) > 0) - { - _coreVoltage = new Sensor("CPU Core", 0, SensorType.Voltage, this, settings); - ActivateSensor(_coreVoltage); - } - - _coreVIDs = new Sensor[_coreCount]; - for (int i = 0; i < _coreVIDs.Length; i++) - { - _coreVIDs[i] = new Sensor(CoreString(i), i + 1, SensorType.Voltage, this, settings); - ActivateSensor(_coreVIDs[i]); - } - - Update(); + break; + default: + _microArchitecture = MicroArchitecture.Unknown; + tjMax = Floats(100); + break; } - public float EnergyUnitsMultiplier { get; } - - private float[] Floats(float f) + // set timeStampCounterMultiplier + switch (_microArchitecture) { - float[] result = new float[_coreCount]; - for (int i = 0; i < _coreCount; i++) - result[i] = f; + case MicroArchitecture.Atom: + case MicroArchitecture.Core: + case MicroArchitecture.NetBurst: + if (Ring0.ReadMsr(IA32_PERF_STATUS, out uint _, out uint edx)) + _timeStampCounterMultiplier = ((edx >> 8) & 0x1f) + (0.5 * ((edx >> 14) & 1)); - return result; + break; + case MicroArchitecture.Airmont: + case MicroArchitecture.AlderLake: + case MicroArchitecture.Broadwell: + case MicroArchitecture.CannonLake: + case MicroArchitecture.CometLake: + case MicroArchitecture.Goldmont: + case MicroArchitecture.GoldmontPlus: + case MicroArchitecture.Haswell: + case MicroArchitecture.IceLake: + case MicroArchitecture.IvyBridge: + case MicroArchitecture.JasperLake: + case MicroArchitecture.KabyLake: + case MicroArchitecture.Nehalem: + case MicroArchitecture.RaptorLake: + case MicroArchitecture.RocketLake: + case MicroArchitecture.SandyBridge: + case MicroArchitecture.Silvermont: + case MicroArchitecture.Skylake: + case MicroArchitecture.TigerLake: + case MicroArchitecture.Tremont: + if (Ring0.ReadMsr(MSR_PLATFORM_INFO, out eax, out uint _)) + _timeStampCounterMultiplier = (eax >> 8) & 0xff; + + break; + default: + _timeStampCounterMultiplier = 0; + break; } - private float[] GetTjMaxFromMsr() + int coreSensorId = 0; + + // check if processor supports a digital thermal sensor at core level + if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 1) != 0 && _microArchitecture != MicroArchitecture.Unknown) { - float[] result = new float[_coreCount]; - for (int i = 0; i < _coreCount; i++) - { - if (Ring0.ReadMsr(IA32_TEMPERATURE_TARGET, out uint eax, out uint _, _cpuId[i][0].Affinity)) - result[i] = (eax >> 16) & 0xFF; - else - result[i] = 100; - } - - return result; - } - - protected override uint[] GetMsrs() - { - return new[] - { - MSR_PLATFORM_INFO, - IA32_PERF_STATUS, - IA32_THERM_STATUS_MSR, - IA32_TEMPERATURE_TARGET, - IA32_PACKAGE_THERM_STATUS, - MSR_RAPL_POWER_UNIT, - MSR_PKG_ENERGY_STATUS, - MSR_DRAM_ENERGY_STATUS, - MSR_PP0_ENERGY_STATUS, - MSR_PP1_ENERGY_STATUS - }; - } - - public override string GetReport() - { - StringBuilder r = new(); - r.Append(base.GetReport()); - r.Append("MicroArchitecture: "); - r.AppendLine(_microArchitecture.ToString()); - r.Append("Time Stamp Counter Multiplier: "); - r.AppendLine(_timeStampCounterMultiplier.ToString(CultureInfo.InvariantCulture)); - r.AppendLine(); - return r.ToString(); - } - - public override void Update() - { - base.Update(); - - float coreMax = float.MinValue; - float coreAvg = 0; - uint eax; - + _coreTemperatures = new Sensor[_coreCount]; for (int i = 0; i < _coreTemperatures.Length; i++) { - // if reading is valid - if (Ring0.ReadMsr(IA32_THERM_STATUS_MSR, out eax, out _, _cpuId[i][0].Affinity) && (eax & 0x80000000) != 0) - { - // get the dist from tjMax from bits 22:16 - float deltaT = (eax & 0x007F0000) >> 16; - float tjMax = _coreTemperatures[i].Parameters[0].Value; - float tSlope = _coreTemperatures[i].Parameters[1].Value; - _coreTemperatures[i].Value = tjMax - (tSlope * deltaT); + _coreTemperatures[i] = new Sensor(CoreString(i), + coreSensorId, + SensorType.Temperature, + this, + new[] + { + new ParameterDescription("TjMax [°C]", "TjMax temperature of the core sensor.\n" + "Temperature = TjMax - TSlope * Value.", tjMax[i]), + new ParameterDescription("TSlope [°C]", "Temperature slope of the digital thermal sensor.\n" + "Temperature = TjMax - TSlope * Value.", 1) + }, + settings); - coreAvg += (float)_coreTemperatures[i].Value; - if (coreMax < _coreTemperatures[i].Value) - coreMax = (float)_coreTemperatures[i].Value; - - _distToTjMaxTemperatures[i].Value = deltaT; - } - else - { - _coreTemperatures[i].Value = null; - _distToTjMaxTemperatures[i].Value = null; - } - } - - //calculate average cpu temperature over all cores - if (_coreMax != null && coreMax != float.MinValue) - { - _coreMax.Value = coreMax; - coreAvg /= _coreTemperatures.Length; - _coreAvg.Value = coreAvg; - } - - if (_packageTemperature != null) - { - // if reading is valid - if (Ring0.ReadMsr(IA32_PACKAGE_THERM_STATUS, out eax, out _, _cpuId[0][0].Affinity) && (eax & 0x80000000) != 0) - { - // get the dist from tjMax from bits 22:16 - float deltaT = (eax & 0x007F0000) >> 16; - float tjMax = _packageTemperature.Parameters[0].Value; - float tSlope = _packageTemperature.Parameters[1].Value; - _packageTemperature.Value = tjMax - (tSlope * deltaT); - } - else - { - _packageTemperature.Value = null; - } - } - - if (HasTimeStampCounter && _timeStampCounterMultiplier > 0) - { - double newBusClock = 0; - for (int i = 0; i < _coreClocks.Length; i++) - { - System.Threading.Thread.Sleep(1); - if (Ring0.ReadMsr(IA32_PERF_STATUS, out eax, out _, _cpuId[i][0].Affinity)) - { - newBusClock = TimeStampCounterFrequency / _timeStampCounterMultiplier; - switch (_microArchitecture) - { - case MicroArchitecture.Nehalem: - _coreClocks[i].Value = (float)((eax & 0xff) * newBusClock); - break; - case MicroArchitecture.Airmont: - case MicroArchitecture.AlderLake: - case MicroArchitecture.Broadwell: - case MicroArchitecture.CannonLake: - case MicroArchitecture.CometLake: - case MicroArchitecture.Goldmont: - case MicroArchitecture.GoldmontPlus: - case MicroArchitecture.Haswell: - case MicroArchitecture.IceLake: - case MicroArchitecture.IvyBridge: - case MicroArchitecture.JasperLake: - case MicroArchitecture.KabyLake: - case MicroArchitecture.RaptorLake: - case MicroArchitecture.RocketLake: - case MicroArchitecture.SandyBridge: - case MicroArchitecture.Silvermont: - case MicroArchitecture.Skylake: - case MicroArchitecture.TigerLake: - case MicroArchitecture.Tremont: - _coreClocks[i].Value = (float)(((eax >> 8) & 0xff) * newBusClock); - break; - default: - _coreClocks[i].Value = (float)((((eax >> 8) & 0x1f) + (0.5 * ((eax >> 14) & 1))) * newBusClock); - break; - } - } - else - { - // if IA32_PERF_STATUS is not available, assume TSC frequency - _coreClocks[i].Value = (float)TimeStampCounterFrequency; - } - } - - if (newBusClock > 0) - { - _busClock.Value = (float)newBusClock; - ActivateSensor(_busClock); - } - } - - if (_powerSensors != null) - { - foreach (Sensor sensor in _powerSensors) - { - if (sensor == null) - continue; - - if (!Ring0.ReadMsr(_energyStatusMsrs[sensor.Index], out eax, out _)) - continue; - - DateTime time = DateTime.UtcNow; - uint energyConsumed = eax; - float deltaTime = (float)(time - _lastEnergyTime[sensor.Index]).TotalSeconds; - if (deltaTime < 0.01) - continue; - - sensor.Value = EnergyUnitsMultiplier * unchecked(energyConsumed - _lastEnergyConsumed[sensor.Index]) / deltaTime; - _lastEnergyTime[sensor.Index] = time; - _lastEnergyConsumed[sensor.Index] = energyConsumed; - } - } - - if (_coreVoltage != null && Ring0.ReadMsr(IA32_PERF_STATUS, out _, out uint edx)) - { - _coreVoltage.Value = ((edx >> 32) & 0xFFFF) / (float)(1 << 13); - } - - for (int i = 0; i < _coreVIDs.Length; i++) - { - if (Ring0.ReadMsr(IA32_PERF_STATUS, out _, out edx, _cpuId[i][0].Affinity) && ((edx >> 32) & 0xFFFF) > 0) - { - _coreVIDs[i].Value = ((edx >> 32) & 0xFFFF) / (float)(1 << 13); - ActivateSensor(_coreVIDs[i]); - } - else - { - DeactivateSensor(_coreVIDs[i]); - } + ActivateSensor(_coreTemperatures[i]); + coreSensorId++; } } + else + _coreTemperatures = Array.Empty(); - [SuppressMessage("ReSharper", "IdentifierTypo")] - private enum MicroArchitecture + // check if processor supports a digital thermal sensor at package level + if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 0x40) != 0 && _microArchitecture != MicroArchitecture.Unknown) { - Airmont, - AlderLake, - Atom, - Broadwell, - CannonLake, - CometLake, - Core, - Goldmont, - GoldmontPlus, - Haswell, - IceLake, - IvyBridge, - JasperLake, - KabyLake, - Nehalem, - NetBurst, - RocketLake, - SandyBridge, - Silvermont, - Skylake, - TigerLake, - Tremont, - RaptorLake, - Unknown + _packageTemperature = new Sensor("CPU Package", + coreSensorId, + SensorType.Temperature, + this, + new[] + { + new ParameterDescription("TjMax [°C]", "TjMax temperature of the package sensor.\n" + "Temperature = TjMax - TSlope * Value.", tjMax[0]), + new ParameterDescription("TSlope [°C]", "Temperature slope of the digital thermal sensor.\n" + "Temperature = TjMax - TSlope * Value.", 1) + }, + settings); + + ActivateSensor(_packageTemperature); + coreSensorId++; } - // ReSharper disable InconsistentNaming - private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1; - private const uint IA32_PERF_STATUS = 0x0198; - private const uint IA32_TEMPERATURE_TARGET = 0x01A2; - private const uint IA32_THERM_STATUS_MSR = 0x019C; + // dist to tjmax sensor + if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 1) != 0 && _microArchitecture != MicroArchitecture.Unknown) + { + _distToTjMaxTemperatures = new Sensor[_coreCount]; + for (int i = 0; i < _distToTjMaxTemperatures.Length; i++) + { + _distToTjMaxTemperatures[i] = new Sensor(CoreString(i) + " Distance to TjMax", coreSensorId, SensorType.Temperature, this, settings); + ActivateSensor(_distToTjMaxTemperatures[i]); + coreSensorId++; + } + } + else + _distToTjMaxTemperatures = Array.Empty(); - private const uint MSR_DRAM_ENERGY_STATUS = 0x619; - private const uint MSR_PKG_ENERGY_STATUS = 0x611; - private const uint MSR_PLATFORM_INFO = 0xCE; - private const uint MSR_PP0_ENERGY_STATUS = 0x639; - private const uint MSR_PP1_ENERGY_STATUS = 0x641; + //core temp avg and max value + //is only available when the cpu has more than 1 core + if (cpuId[0][0].Data.GetLength(0) > 6 && (cpuId[0][0].Data[6, 0] & 0x40) != 0 && _microArchitecture != MicroArchitecture.Unknown && _coreCount > 1) + { + _coreMax = new Sensor("Core Max", coreSensorId, SensorType.Temperature, this, settings); + ActivateSensor(_coreMax); + coreSensorId++; - private const uint MSR_RAPL_POWER_UNIT = 0x606; - // ReSharper restore InconsistentNaming + _coreAvg = new Sensor("Core Average", coreSensorId, SensorType.Temperature, this, settings); + ActivateSensor(_coreAvg); + } + else + { + _coreMax = null; + _coreAvg = null; + } + + _busClock = new Sensor("Bus Speed", 0, SensorType.Clock, this, settings); + _coreClocks = new Sensor[_coreCount]; + for (int i = 0; i < _coreClocks.Length; i++) + { + _coreClocks[i] = new Sensor(CoreString(i), i + 1, SensorType.Clock, this, settings); + if (HasTimeStampCounter && _microArchitecture != MicroArchitecture.Unknown) + ActivateSensor(_coreClocks[i]); + } + + if (_microArchitecture is MicroArchitecture.Airmont or + MicroArchitecture.AlderLake or + MicroArchitecture.Broadwell or + MicroArchitecture.CannonLake or + MicroArchitecture.CometLake or + MicroArchitecture.Goldmont or + MicroArchitecture.GoldmontPlus or + MicroArchitecture.Haswell or + MicroArchitecture.IceLake or + MicroArchitecture.IvyBridge or + MicroArchitecture.JasperLake or + MicroArchitecture.KabyLake or + MicroArchitecture.RaptorLake or + MicroArchitecture.RocketLake or + MicroArchitecture.SandyBridge or + MicroArchitecture.Silvermont or + MicroArchitecture.Skylake or + MicroArchitecture.TigerLake or + MicroArchitecture.Tremont) + { + _powerSensors = new Sensor[_energyStatusMsrs.Length]; + _lastEnergyTime = new DateTime[_energyStatusMsrs.Length]; + _lastEnergyConsumed = new uint[_energyStatusMsrs.Length]; + + if (Ring0.ReadMsr(MSR_RAPL_POWER_UNIT, out eax, out uint _)) + { + EnergyUnitsMultiplier = _microArchitecture switch + { + MicroArchitecture.Silvermont or MicroArchitecture.Airmont => 1.0e-6f * (1 << (int)((eax >> 8) & 0x1F)), + _ => 1.0f / (1 << (int)((eax >> 8) & 0x1F)) + }; + } + + if (EnergyUnitsMultiplier != 0) + { + string[] powerSensorLabels = { "CPU Package", "CPU Cores", "CPU Graphics", "CPU Memory" }; + + for (int i = 0; i < _energyStatusMsrs.Length; i++) + { + if (!Ring0.ReadMsr(_energyStatusMsrs[i], out eax, out uint _)) + continue; + + // Don't show the "GPU Graphics" sensor on windows, it will show up under the GPU instead. + if (i == 2 && !Software.OperatingSystem.IsUnix) + continue; + + _lastEnergyTime[i] = DateTime.UtcNow; + _lastEnergyConsumed[i] = eax; + _powerSensors[i] = new Sensor(powerSensorLabels[i], + i, + SensorType.Power, + this, + settings); + + ActivateSensor(_powerSensors[i]); + } + } + } + + if (Ring0.ReadMsr(IA32_PERF_STATUS, out eax, out uint _) && ((eax >> 32) & 0xFFFF) > 0) + { + _coreVoltage = new Sensor("CPU Core", 0, SensorType.Voltage, this, settings); + ActivateSensor(_coreVoltage); + } + + _coreVIDs = new Sensor[_coreCount]; + for (int i = 0; i < _coreVIDs.Length; i++) + { + _coreVIDs[i] = new Sensor(CoreString(i), i + 1, SensorType.Voltage, this, settings); + ActivateSensor(_coreVIDs[i]); + } + + Update(); } + + public float EnergyUnitsMultiplier { get; } + + private float[] Floats(float f) + { + float[] result = new float[_coreCount]; + for (int i = 0; i < _coreCount; i++) + result[i] = f; + + return result; + } + + private float[] GetTjMaxFromMsr() + { + float[] result = new float[_coreCount]; + for (int i = 0; i < _coreCount; i++) + { + if (Ring0.ReadMsr(IA32_TEMPERATURE_TARGET, out uint eax, out uint _, _cpuId[i][0].Affinity)) + result[i] = (eax >> 16) & 0xFF; + else + result[i] = 100; + } + + return result; + } + + protected override uint[] GetMsrs() + { + return new[] + { + MSR_PLATFORM_INFO, + IA32_PERF_STATUS, + IA32_THERM_STATUS_MSR, + IA32_TEMPERATURE_TARGET, + IA32_PACKAGE_THERM_STATUS, + MSR_RAPL_POWER_UNIT, + MSR_PKG_ENERGY_STATUS, + MSR_DRAM_ENERGY_STATUS, + MSR_PP0_ENERGY_STATUS, + MSR_PP1_ENERGY_STATUS + }; + } + + public override string GetReport() + { + StringBuilder r = new(); + r.Append(base.GetReport()); + r.Append("MicroArchitecture: "); + r.AppendLine(_microArchitecture.ToString()); + r.Append("Time Stamp Counter Multiplier: "); + r.AppendLine(_timeStampCounterMultiplier.ToString(CultureInfo.InvariantCulture)); + r.AppendLine(); + return r.ToString(); + } + + public override void Update() + { + base.Update(); + + float coreMax = float.MinValue; + float coreAvg = 0; + uint eax; + + for (int i = 0; i < _coreTemperatures.Length; i++) + { + // if reading is valid + if (Ring0.ReadMsr(IA32_THERM_STATUS_MSR, out eax, out _, _cpuId[i][0].Affinity) && (eax & 0x80000000) != 0) + { + // get the dist from tjMax from bits 22:16 + float deltaT = (eax & 0x007F0000) >> 16; + float tjMax = _coreTemperatures[i].Parameters[0].Value; + float tSlope = _coreTemperatures[i].Parameters[1].Value; + _coreTemperatures[i].Value = tjMax - (tSlope * deltaT); + + coreAvg += (float)_coreTemperatures[i].Value; + if (coreMax < _coreTemperatures[i].Value) + coreMax = (float)_coreTemperatures[i].Value; + + _distToTjMaxTemperatures[i].Value = deltaT; + } + else + { + _coreTemperatures[i].Value = null; + _distToTjMaxTemperatures[i].Value = null; + } + } + + //calculate average cpu temperature over all cores + if (_coreMax != null && coreMax != float.MinValue) + { + _coreMax.Value = coreMax; + coreAvg /= _coreTemperatures.Length; + _coreAvg.Value = coreAvg; + } + + if (_packageTemperature != null) + { + // if reading is valid + if (Ring0.ReadMsr(IA32_PACKAGE_THERM_STATUS, out eax, out _, _cpuId[0][0].Affinity) && (eax & 0x80000000) != 0) + { + // get the dist from tjMax from bits 22:16 + float deltaT = (eax & 0x007F0000) >> 16; + float tjMax = _packageTemperature.Parameters[0].Value; + float tSlope = _packageTemperature.Parameters[1].Value; + _packageTemperature.Value = tjMax - (tSlope * deltaT); + } + else + { + _packageTemperature.Value = null; + } + } + + if (HasTimeStampCounter && _timeStampCounterMultiplier > 0) + { + double newBusClock = 0; + for (int i = 0; i < _coreClocks.Length; i++) + { + System.Threading.Thread.Sleep(1); + if (Ring0.ReadMsr(IA32_PERF_STATUS, out eax, out _, _cpuId[i][0].Affinity)) + { + newBusClock = TimeStampCounterFrequency / _timeStampCounterMultiplier; + switch (_microArchitecture) + { + case MicroArchitecture.Nehalem: + _coreClocks[i].Value = (float)((eax & 0xff) * newBusClock); + break; + case MicroArchitecture.Airmont: + case MicroArchitecture.AlderLake: + case MicroArchitecture.Broadwell: + case MicroArchitecture.CannonLake: + case MicroArchitecture.CometLake: + case MicroArchitecture.Goldmont: + case MicroArchitecture.GoldmontPlus: + case MicroArchitecture.Haswell: + case MicroArchitecture.IceLake: + case MicroArchitecture.IvyBridge: + case MicroArchitecture.JasperLake: + case MicroArchitecture.KabyLake: + case MicroArchitecture.RaptorLake: + case MicroArchitecture.RocketLake: + case MicroArchitecture.SandyBridge: + case MicroArchitecture.Silvermont: + case MicroArchitecture.Skylake: + case MicroArchitecture.TigerLake: + case MicroArchitecture.Tremont: + _coreClocks[i].Value = (float)(((eax >> 8) & 0xff) * newBusClock); + break; + default: + _coreClocks[i].Value = (float)((((eax >> 8) & 0x1f) + (0.5 * ((eax >> 14) & 1))) * newBusClock); + break; + } + } + else + { + // if IA32_PERF_STATUS is not available, assume TSC frequency + _coreClocks[i].Value = (float)TimeStampCounterFrequency; + } + } + + if (newBusClock > 0) + { + _busClock.Value = (float)newBusClock; + ActivateSensor(_busClock); + } + } + + if (_powerSensors != null) + { + foreach (Sensor sensor in _powerSensors) + { + if (sensor == null) + continue; + + if (!Ring0.ReadMsr(_energyStatusMsrs[sensor.Index], out eax, out _)) + continue; + + DateTime time = DateTime.UtcNow; + uint energyConsumed = eax; + float deltaTime = (float)(time - _lastEnergyTime[sensor.Index]).TotalSeconds; + if (deltaTime < 0.01) + continue; + + sensor.Value = EnergyUnitsMultiplier * unchecked(energyConsumed - _lastEnergyConsumed[sensor.Index]) / deltaTime; + _lastEnergyTime[sensor.Index] = time; + _lastEnergyConsumed[sensor.Index] = energyConsumed; + } + } + + if (_coreVoltage != null && Ring0.ReadMsr(IA32_PERF_STATUS, out _, out uint edx)) + { + _coreVoltage.Value = ((edx >> 32) & 0xFFFF) / (float)(1 << 13); + } + + for (int i = 0; i < _coreVIDs.Length; i++) + { + if (Ring0.ReadMsr(IA32_PERF_STATUS, out _, out edx, _cpuId[i][0].Affinity) && ((edx >> 32) & 0xFFFF) > 0) + { + _coreVIDs[i].Value = ((edx >> 32) & 0xFFFF) / (float)(1 << 13); + ActivateSensor(_coreVIDs[i]); + } + else + { + DeactivateSensor(_coreVIDs[i]); + } + } + } + + [SuppressMessage("ReSharper", "IdentifierTypo")] + private enum MicroArchitecture + { + Airmont, + AlderLake, + Atom, + Broadwell, + CannonLake, + CometLake, + Core, + Goldmont, + GoldmontPlus, + Haswell, + IceLake, + IvyBridge, + JasperLake, + KabyLake, + Nehalem, + NetBurst, + RocketLake, + SandyBridge, + Silvermont, + Skylake, + TigerLake, + Tremont, + RaptorLake, + Unknown + } + + // ReSharper disable InconsistentNaming + private const uint IA32_PACKAGE_THERM_STATUS = 0x1B1; + private const uint IA32_PERF_STATUS = 0x0198; + private const uint IA32_TEMPERATURE_TARGET = 0x01A2; + private const uint IA32_THERM_STATUS_MSR = 0x019C; + + private const uint MSR_DRAM_ENERGY_STATUS = 0x619; + private const uint MSR_PKG_ENERGY_STATUS = 0x611; + private const uint MSR_PLATFORM_INFO = 0xCE; + private const uint MSR_PP0_ENERGY_STATUS = 0x639; + private const uint MSR_PP1_ENERGY_STATUS = 0x641; + + private const uint MSR_RAPL_POWER_UNIT = 0x606; + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs b/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs index edc06ac..3c0ec39 100644 --- a/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs +++ b/LibreHardwareMonitorLib/Hardware/D3DDisplayDevice.cs @@ -9,279 +9,278 @@ using System.Linq; using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal static class D3DDisplayDevice { - internal static class D3DDisplayDevice + public static string[] GetDeviceIdentifiers() { - public static string[] GetDeviceIdentifiers() - { - if (CfgMgr32.CM_Get_Device_Interface_List_Size(out uint size, ref CfgMgr32.GUID_DISPLAY_DEVICE_ARRIVAL, null, CfgMgr32.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CfgMgr32.CR_SUCCESS) - return null; - - char[] data = new char[size]; - if (CfgMgr32.CM_Get_Device_Interface_List(ref CfgMgr32.GUID_DISPLAY_DEVICE_ARRIVAL, null, data, (uint)data.Length, CfgMgr32.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CfgMgr32.CR_SUCCESS) - return new string(data).Split('\0').Where(m => !string.IsNullOrEmpty(m)).ToArray(); - + if (CfgMgr32.CM_Get_Device_Interface_List_Size(out uint size, ref CfgMgr32.GUID_DISPLAY_DEVICE_ARRIVAL, null, CfgMgr32.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) != CfgMgr32.CR_SUCCESS) return null; + + char[] data = new char[size]; + if (CfgMgr32.CM_Get_Device_Interface_List(ref CfgMgr32.GUID_DISPLAY_DEVICE_ARRIVAL, null, data, (uint)data.Length, CfgMgr32.CM_GET_DEVICE_INTERFACE_LIST_PRESENT) == CfgMgr32.CR_SUCCESS) + return new string(data).Split('\0').Where(m => !string.IsNullOrEmpty(m)).ToArray(); + + return null; + } + + public static string GetActualDeviceIdentifier(string deviceIdentifier) + { + if (string.IsNullOrEmpty(deviceIdentifier)) + return deviceIdentifier; + + // For example: + // \\?\ROOT#BasicRender#0000#{1ca05180-a699-450a-9a0c-de4fbe3ddd89} --> ROOT\BasicRender\0000 + // \\?\PCI#VEN_1002&DEV_731F&SUBSYS_57051682&REV_C4#6&e539058&0&00000019#{1ca05180-a699-450a-9a0c-de4fbe3ddd89} --> PCI\VEN_1002&DEV_731F&SUBSYS_57051682&REV_C4\6&e539058&0&00000019 + + if (deviceIdentifier.StartsWith(@"\\?\")) + deviceIdentifier = deviceIdentifier.Substring(4); + + if (deviceIdentifier.Length > 0 && deviceIdentifier[deviceIdentifier.Length - 1] == '}') + { + int lastIndex = deviceIdentifier.LastIndexOf('{'); + if (lastIndex > 0) + deviceIdentifier = deviceIdentifier.Substring(0, lastIndex - 1); } - public static string GetActualDeviceIdentifier(string deviceIdentifier) + return deviceIdentifier.Replace('#', '\\'); + } + + public static bool GetDeviceInfoByIdentifier(string deviceIdentifier, out D3DDeviceInfo deviceInfo) + { + deviceInfo = new D3DDeviceInfo(); + + OpenAdapterFromDeviceName(out uint status, deviceIdentifier, out D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter); + if (status != WinNt.STATUS_SUCCESS) + return false; + + GetAdapterType(out status, adapter, out D3dkmth.D3DKMT_ADAPTERTYPE adapterType); + if (status != WinNt.STATUS_SUCCESS) + return false; + + if (!adapterType.Value.HasFlag(D3dkmth.D3DKMT_ADAPTERTYPE_FLAGS.SoftwareDevice)) + return false; + + deviceInfo.Integrated = !adapterType.Value.HasFlag(D3dkmth.D3DKMT_ADAPTERTYPE_FLAGS.HybridIntegrated); + + GetQueryStatisticsAdapterInformation(out status, adapter, out D3dkmth.D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION adapterInformation); + if (status != WinNt.STATUS_SUCCESS) + return false; + + uint segmentCount = adapterInformation.NbSegments; + uint nodeCount = adapterInformation.NodeCount; + + deviceInfo.Nodes = new D3DDeviceNodeInfo[nodeCount]; + + DateTime queryTime = DateTime.Now; + + for (uint nodeId = 0; nodeId < nodeCount; nodeId++) { - if (string.IsNullOrEmpty(deviceIdentifier)) - return deviceIdentifier; + GetNodeMetaData(out status, adapter, nodeId, out D3dkmth.D3DKMT_NODEMETADATA nodeMetaData); + if (status != WinNt.STATUS_SUCCESS) + return false; - // For example: - // \\?\ROOT#BasicRender#0000#{1ca05180-a699-450a-9a0c-de4fbe3ddd89} --> ROOT\BasicRender\0000 - // \\?\PCI#VEN_1002&DEV_731F&SUBSYS_57051682&REV_C4#6&e539058&0&00000019#{1ca05180-a699-450a-9a0c-de4fbe3ddd89} --> PCI\VEN_1002&DEV_731F&SUBSYS_57051682&REV_C4\6&e539058&0&00000019 + GetQueryStatisticsNode(out status, adapter, nodeId, out D3dkmth.D3DKMT_QUERYSTATISTICS_NODE_INFORMATION nodeInformation); + if (status != WinNt.STATUS_SUCCESS) + return false; - if (deviceIdentifier.StartsWith(@"\\?\")) - deviceIdentifier = deviceIdentifier.Substring(4); - - if (deviceIdentifier.Length > 0 && deviceIdentifier[deviceIdentifier.Length - 1] == '}') + deviceInfo.Nodes[nodeId] = new D3DDeviceNodeInfo { - int lastIndex = deviceIdentifier.LastIndexOf('{'); - if (lastIndex > 0) - deviceIdentifier = deviceIdentifier.Substring(0, lastIndex - 1); + Id = nodeId, + Name = GetNodeEngineTypeString(nodeMetaData), + RunningTime = nodeInformation.GlobalInformation.RunningTime.QuadPart, + QueryTime = queryTime + }; + } + + GetSegmentSize(out status, adapter, out D3dkmth.D3DKMT_SEGMENTSIZEINFO segmentSizeInfo); + if (status != WinNt.STATUS_SUCCESS) + return false; + + deviceInfo.GpuSharedLimit = segmentSizeInfo.SharedSystemMemorySize; + deviceInfo.GpuDedicatedLimit = segmentSizeInfo.DedicatedSystemMemorySize; + + for (uint segmentId = 0; segmentId < segmentCount; segmentId++) + { + GetQueryStatisticsSegment(out status, adapter, segmentId, out D3dkmth.D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION segmentInformation); + if (status != WinNt.STATUS_SUCCESS) + return false; + + ulong bytesResident = segmentInformation.BytesResident; + ulong bytesCommitted = segmentInformation.BytesCommitted; + + uint aperture = segmentInformation.Aperture; + + if (aperture == 1) + { + deviceInfo.GpuSharedUsed += bytesResident; + deviceInfo.GpuSharedMax += bytesCommitted; } - - return deviceIdentifier.Replace('#', '\\'); - } - - public static bool GetDeviceInfoByIdentifier(string deviceIdentifier, out D3DDeviceInfo deviceInfo) - { - deviceInfo = new D3DDeviceInfo(); - - OpenAdapterFromDeviceName(out uint status, deviceIdentifier, out D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter); - if (status != WinNt.STATUS_SUCCESS) - return false; - - GetAdapterType(out status, adapter, out D3dkmth.D3DKMT_ADAPTERTYPE adapterType); - if (status != WinNt.STATUS_SUCCESS) - return false; - - if (!adapterType.Value.HasFlag(D3dkmth.D3DKMT_ADAPTERTYPE_FLAGS.SoftwareDevice)) - return false; - - deviceInfo.Integrated = !adapterType.Value.HasFlag(D3dkmth.D3DKMT_ADAPTERTYPE_FLAGS.HybridIntegrated); - - GetQueryStatisticsAdapterInformation(out status, adapter, out D3dkmth.D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION adapterInformation); - if (status != WinNt.STATUS_SUCCESS) - return false; - - uint segmentCount = adapterInformation.NbSegments; - uint nodeCount = adapterInformation.NodeCount; - - deviceInfo.Nodes = new D3DDeviceNodeInfo[nodeCount]; - - DateTime queryTime = DateTime.Now; - - for (uint nodeId = 0; nodeId < nodeCount; nodeId++) + else { - GetNodeMetaData(out status, adapter, nodeId, out D3dkmth.D3DKMT_NODEMETADATA nodeMetaData); - if (status != WinNt.STATUS_SUCCESS) - return false; - - GetQueryStatisticsNode(out status, adapter, nodeId, out D3dkmth.D3DKMT_QUERYSTATISTICS_NODE_INFORMATION nodeInformation); - if (status != WinNt.STATUS_SUCCESS) - return false; - - deviceInfo.Nodes[nodeId] = new D3DDeviceNodeInfo - { - Id = nodeId, - Name = GetNodeEngineTypeString(nodeMetaData), - RunningTime = nodeInformation.GlobalInformation.RunningTime.QuadPart, - QueryTime = queryTime - }; + deviceInfo.GpuDedicatedUsed += bytesResident; + deviceInfo.GpuDedicatedMax += bytesCommitted; } - - GetSegmentSize(out status, adapter, out D3dkmth.D3DKMT_SEGMENTSIZEINFO segmentSizeInfo); - if (status != WinNt.STATUS_SUCCESS) - return false; - - deviceInfo.GpuSharedLimit = segmentSizeInfo.SharedSystemMemorySize; - deviceInfo.GpuDedicatedLimit = segmentSizeInfo.DedicatedSystemMemorySize; - - for (uint segmentId = 0; segmentId < segmentCount; segmentId++) - { - GetQueryStatisticsSegment(out status, adapter, segmentId, out D3dkmth.D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION segmentInformation); - if (status != WinNt.STATUS_SUCCESS) - return false; - - ulong bytesResident = segmentInformation.BytesResident; - ulong bytesCommitted = segmentInformation.BytesCommitted; - - uint aperture = segmentInformation.Aperture; - - if (aperture == 1) - { - deviceInfo.GpuSharedUsed += bytesResident; - deviceInfo.GpuSharedMax += bytesCommitted; - } - else - { - deviceInfo.GpuDedicatedUsed += bytesResident; - deviceInfo.GpuDedicatedMax += bytesCommitted; - } - } - - CloseAdapter(out status, adapter); - return status == WinNt.STATUS_SUCCESS; } - private static string GetNodeEngineTypeString(D3dkmth.D3DKMT_NODEMETADATA nodeMetaData) + CloseAdapter(out status, adapter); + return status == WinNt.STATUS_SUCCESS; + } + + private static string GetNodeEngineTypeString(D3dkmth.D3DKMT_NODEMETADATA nodeMetaData) + { + return nodeMetaData.NodeData.EngineType switch { - return nodeMetaData.NodeData.EngineType switch - { - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OTHER => "D3D " + (!string.IsNullOrWhiteSpace(nodeMetaData.NodeData.FriendlyName) ? nodeMetaData.NodeData.FriendlyName : "Other"), - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_3D => "D3D 3D", - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_DECODE => "D3D Video Decode", - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_ENCODE => "D3D Video Encode", - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_PROCESSING => "D3D Video Processing", - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_SCENE_ASSEMBLY => "D3D Scene Assembly", - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_COPY => "D3D Copy", - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OVERLAY => "D3D Overlay", - D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_CRYPTO => "D3D Crypto", - _ => "D3D Unknown" - }; - } + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OTHER => "D3D " + (!string.IsNullOrWhiteSpace(nodeMetaData.NodeData.FriendlyName) ? nodeMetaData.NodeData.FriendlyName : "Other"), + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_3D => "D3D 3D", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_DECODE => "D3D Video Decode", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_ENCODE => "D3D Video Encode", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_VIDEO_PROCESSING => "D3D Video Processing", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_SCENE_ASSEMBLY => "D3D Scene Assembly", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_COPY => "D3D Copy", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_OVERLAY => "D3D Overlay", + D3dkmdt.DXGK_ENGINE_TYPE.DXGK_ENGINE_TYPE_CRYPTO => "D3D Crypto", + _ => "D3D Unknown" + }; + } - private static void GetSegmentSize - ( - out uint status, - D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, - out D3dkmth.D3DKMT_SEGMENTSIZEINFO sizeInformation) + private static void GetSegmentSize + ( + out uint status, + D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, + out D3dkmth.D3DKMT_SEGMENTSIZEINFO sizeInformation) + { + IntPtr segmentSizePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_SEGMENTSIZEINFO))); + sizeInformation = new D3dkmth.D3DKMT_SEGMENTSIZEINFO(); + Marshal.StructureToPtr(sizeInformation, segmentSizePtr, true); + + var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO { - IntPtr segmentSizePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_SEGMENTSIZEINFO))); - sizeInformation = new D3dkmth.D3DKMT_SEGMENTSIZEINFO(); - Marshal.StructureToPtr(sizeInformation, segmentSizePtr, true); + hAdapter = adapter.hAdapter, + Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_GETSEGMENTSIZE, + pPrivateDriverData = segmentSizePtr, + PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_SEGMENTSIZEINFO)) + }; - var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO - { - hAdapter = adapter.hAdapter, - Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_GETSEGMENTSIZE, - pPrivateDriverData = segmentSizePtr, - PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_SEGMENTSIZEINFO)) - }; + status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); + sizeInformation = Marshal.PtrToStructure(segmentSizePtr); + Marshal.FreeHGlobal(segmentSizePtr); + } - status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); - sizeInformation = Marshal.PtrToStructure(segmentSizePtr); - Marshal.FreeHGlobal(segmentSizePtr); - } + private static void GetNodeMetaData(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, uint nodeId, out D3dkmth.D3DKMT_NODEMETADATA nodeMetaDataResult) + { + IntPtr nodeMetaDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_NODEMETADATA))); + nodeMetaDataResult = new D3dkmth.D3DKMT_NODEMETADATA { NodeOrdinalAndAdapterIndex = nodeId }; + Marshal.StructureToPtr(nodeMetaDataResult, nodeMetaDataPtr, true); - private static void GetNodeMetaData(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, uint nodeId, out D3dkmth.D3DKMT_NODEMETADATA nodeMetaDataResult) + var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO { - IntPtr nodeMetaDataPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_NODEMETADATA))); - nodeMetaDataResult = new D3dkmth.D3DKMT_NODEMETADATA { NodeOrdinalAndAdapterIndex = nodeId }; - Marshal.StructureToPtr(nodeMetaDataResult, nodeMetaDataPtr, true); + hAdapter = adapter.hAdapter, + Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_NODEMETADATA, + pPrivateDriverData = nodeMetaDataPtr, + PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_NODEMETADATA)) + }; - var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO - { - hAdapter = adapter.hAdapter, - Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_NODEMETADATA, - pPrivateDriverData = nodeMetaDataPtr, - PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_NODEMETADATA)) - }; + status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); + nodeMetaDataResult = Marshal.PtrToStructure(nodeMetaDataPtr); + Marshal.FreeHGlobal(nodeMetaDataPtr); + } - status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); - nodeMetaDataResult = Marshal.PtrToStructure(nodeMetaDataPtr); - Marshal.FreeHGlobal(nodeMetaDataPtr); - } + private static void GetQueryStatisticsNode(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, uint nodeId, out D3dkmth.D3DKMT_QUERYSTATISTICS_NODE_INFORMATION nodeInformation) + { + var queryElement = new D3dkmth.D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT { QueryNode = { NodeId = nodeId } }; - private static void GetQueryStatisticsNode(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, uint nodeId, out D3dkmth.D3DKMT_QUERYSTATISTICS_NODE_INFORMATION nodeInformation) + var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS { - var queryElement = new D3dkmth.D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT { QueryNode = { NodeId = nodeId } }; + AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_NODE, QueryElement = queryElement + }; - var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS - { - AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_NODE, QueryElement = queryElement - }; + status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); - status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); + nodeInformation = queryStatistics.QueryResult.NodeInformation; + } - nodeInformation = queryStatistics.QueryResult.NodeInformation; - } + private static void GetQueryStatisticsSegment + ( + out uint status, + D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, + uint segmentId, + out D3dkmth.D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION segmentInformation) + { + var queryElement = new D3dkmth.D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT { QuerySegment = { SegmentId = segmentId } }; - private static void GetQueryStatisticsSegment - ( - out uint status, - D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, - uint segmentId, - out D3dkmth.D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION segmentInformation) + var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS { - var queryElement = new D3dkmth.D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT { QuerySegment = { SegmentId = segmentId } }; + AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_SEGMENT, QueryElement = queryElement + }; - var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS - { - AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_SEGMENT, QueryElement = queryElement - }; + status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); - status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); + segmentInformation = queryStatistics.QueryResult.SegmentInformation; + } - segmentInformation = queryStatistics.QueryResult.SegmentInformation; - } + private static void GetQueryStatisticsAdapterInformation + ( + out uint status, + D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, + out D3dkmth.D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION adapterInformation) + { + var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS { AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_ADAPTER }; - private static void GetQueryStatisticsAdapterInformation - ( - out uint status, - D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, - out D3dkmth.D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION adapterInformation) + status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); + + adapterInformation = queryStatistics.QueryResult.AdapterInformation; + } + + private static void GetAdapterType(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, out D3dkmth.D3DKMT_ADAPTERTYPE adapterTypeResult) + { + IntPtr adapterTypePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_ADAPTERTYPE))); + var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO { - var queryStatistics = new D3dkmth.D3DKMT_QUERYSTATISTICS { AdapterLuid = adapter.AdapterLuid, Type = D3dkmth.D3DKMT_QUERYSTATISTICS_TYPE.D3DKMT_QUERYSTATISTICS_ADAPTER }; + hAdapter = adapter.hAdapter, + Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_ADAPTERTYPE, + pPrivateDriverData = adapterTypePtr, + PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_ADAPTERTYPE)) + }; - status = Gdi32.D3DKMTQueryStatistics(ref queryStatistics); + status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); + adapterTypeResult = Marshal.PtrToStructure(adapterTypePtr); + Marshal.FreeHGlobal(adapterTypePtr); + } - adapterInformation = queryStatistics.QueryResult.AdapterInformation; - } + private static void OpenAdapterFromDeviceName(out uint status, string displayDeviceName, out D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter) + { + adapter = new D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME { pDeviceName = displayDeviceName }; + status = Gdi32.D3DKMTOpenAdapterFromDeviceName(ref adapter); + } - private static void GetAdapterType(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter, out D3dkmth.D3DKMT_ADAPTERTYPE adapterTypeResult) - { - IntPtr adapterTypePtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(D3dkmth.D3DKMT_ADAPTERTYPE))); - var queryAdapterInfo = new D3dkmth.D3DKMT_QUERYADAPTERINFO - { - hAdapter = adapter.hAdapter, - Type = D3dkmth.KMTQUERYADAPTERINFOTYPE.KMTQAITYPE_ADAPTERTYPE, - pPrivateDriverData = adapterTypePtr, - PrivateDriverDataSize = Marshal.SizeOf(typeof(D3dkmth.D3DKMT_ADAPTERTYPE)) - }; + private static void CloseAdapter(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter) + { + var closeAdapter = new D3dkmth.D3DKMT_CLOSEADAPTER { hAdapter = adapter.hAdapter }; + status = Gdi32.D3DKMTCloseAdapter(ref closeAdapter); + } - status = Gdi32.D3DKMTQueryAdapterInfo(ref queryAdapterInfo); - adapterTypeResult = Marshal.PtrToStructure(adapterTypePtr); - Marshal.FreeHGlobal(adapterTypePtr); - } + public struct D3DDeviceNodeInfo + { + public ulong Id; + public string Name; + public long RunningTime; + public DateTime QueryTime; + } - private static void OpenAdapterFromDeviceName(out uint status, string displayDeviceName, out D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter) - { - adapter = new D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME { pDeviceName = displayDeviceName }; - status = Gdi32.D3DKMTOpenAdapterFromDeviceName(ref adapter); - } + public struct D3DDeviceInfo + { + public ulong GpuSharedLimit; + public ulong GpuDedicatedLimit; - private static void CloseAdapter(out uint status, D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME adapter) - { - var closeAdapter = new D3dkmth.D3DKMT_CLOSEADAPTER { hAdapter = adapter.hAdapter }; - status = Gdi32.D3DKMTCloseAdapter(ref closeAdapter); - } + public ulong GpuSharedUsed; + public ulong GpuDedicatedUsed; - public struct D3DDeviceNodeInfo - { - public ulong Id; - public string Name; - public long RunningTime; - public DateTime QueryTime; - } + public ulong GpuSharedMax; + public ulong GpuDedicatedMax; - public struct D3DDeviceInfo - { - public ulong GpuSharedLimit; - public ulong GpuDedicatedLimit; - - public ulong GpuSharedUsed; - public ulong GpuDedicatedUsed; - - public ulong GpuSharedMax; - public ulong GpuDedicatedMax; - - public D3DDeviceNodeInfo[] Nodes; - public bool Integrated; - } + public D3DDeviceNodeInfo[] Nodes; + public bool Integrated; } } diff --git a/LibreHardwareMonitorLib/Hardware/FirmwareTable.cs b/LibreHardwareMonitorLib/Hardware/FirmwareTable.cs index 6be9faf..9209bea 100644 --- a/LibreHardwareMonitorLib/Hardware/FirmwareTable.cs +++ b/LibreHardwareMonitorLib/Hardware/FirmwareTable.cs @@ -8,89 +8,88 @@ using System; using System.Runtime.InteropServices; using System.Text; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal static class FirmwareTable { - internal static class FirmwareTable + public static byte[] GetTable(Interop.Kernel32.Provider provider, string table) { - public static byte[] GetTable(Interop.Kernel32.Provider provider, string table) + int id = table[3] << 24 | table[2] << 16 | table[1] << 8 | table[0]; + return GetTable(provider, id); + } + + public static byte[] GetTable(Interop.Kernel32.Provider provider, int table) + { + int size; + + try { - int id = table[3] << 24 | table[2] << 16 | table[1] << 8 | table[0]; - return GetTable(provider, id); + size = Interop.Kernel32.GetSystemFirmwareTable(provider, table, IntPtr.Zero, 0); + } + catch (Exception e) when (e is DllNotFoundException or EntryPointNotFoundException) + { + return null; } - public static byte[] GetTable(Interop.Kernel32.Provider provider, int table) + if (size <= 0) + return null; + + IntPtr allocatedBuffer = IntPtr.Zero; + + try { - int size; + allocatedBuffer = Marshal.AllocHGlobal(size); - try - { - size = Interop.Kernel32.GetSystemFirmwareTable(provider, table, IntPtr.Zero, 0); - } - catch (Exception e) when (e is DllNotFoundException or EntryPointNotFoundException) - { - return null; - } - - if (size <= 0) + Interop.Kernel32.GetSystemFirmwareTable(provider, table, allocatedBuffer, size); + if (Marshal.GetLastWin32Error() != 0) return null; - IntPtr allocatedBuffer = IntPtr.Zero; - - try - { - allocatedBuffer = Marshal.AllocHGlobal(size); - - Interop.Kernel32.GetSystemFirmwareTable(provider, table, allocatedBuffer, size); - if (Marshal.GetLastWin32Error() != 0) - return null; - - byte[] buffer = new byte[size]; - Marshal.Copy(allocatedBuffer, buffer, 0, size); - return buffer; - } - finally - { - if (allocatedBuffer != IntPtr.Zero) - Marshal.FreeHGlobal(allocatedBuffer); - } + byte[] buffer = new byte[size]; + Marshal.Copy(allocatedBuffer, buffer, 0, size); + return buffer; } - - public static string[] EnumerateTables(Interop.Kernel32.Provider provider) + finally { - int size; - - try - { - size = Interop.Kernel32.EnumSystemFirmwareTables(provider, IntPtr.Zero, 0); - } - catch (Exception e) when (e is DllNotFoundException or EntryPointNotFoundException) - { - return null; - } - - IntPtr allocatedBuffer = IntPtr.Zero; - - try - { - allocatedBuffer = Marshal.AllocHGlobal(size); - - Interop.Kernel32.EnumSystemFirmwareTables(provider, allocatedBuffer, size); - - byte[] buffer = new byte[size]; - Marshal.Copy(allocatedBuffer, buffer, 0, size); - - string[] result = new string[size / 4]; - - for (int i = 0; i < result.Length; i++) - result[i] = Encoding.ASCII.GetString(buffer, 4 * i, 4); - - return result; - } - finally - { - if (allocatedBuffer != IntPtr.Zero) - Marshal.FreeHGlobal(allocatedBuffer); - } + if (allocatedBuffer != IntPtr.Zero) + Marshal.FreeHGlobal(allocatedBuffer); } } -} + + public static string[] EnumerateTables(Interop.Kernel32.Provider provider) + { + int size; + + try + { + size = Interop.Kernel32.EnumSystemFirmwareTables(provider, IntPtr.Zero, 0); + } + catch (Exception e) when (e is DllNotFoundException or EntryPointNotFoundException) + { + return null; + } + + IntPtr allocatedBuffer = IntPtr.Zero; + + try + { + allocatedBuffer = Marshal.AllocHGlobal(size); + + Interop.Kernel32.EnumSystemFirmwareTables(provider, allocatedBuffer, size); + + byte[] buffer = new byte[size]; + Marshal.Copy(allocatedBuffer, buffer, 0, size); + + string[] result = new string[size / 4]; + + for (int i = 0; i < result.Length; i++) + result[i] = Encoding.ASCII.GetString(buffer, 4 * i, 4); + + return result; + } + finally + { + if (allocatedBuffer != IntPtr.Zero) + Marshal.FreeHGlobal(allocatedBuffer); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs index 3873d74..a7e6cf9 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpu.cs @@ -10,754 +10,753 @@ using System.Linq; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Gpu +namespace LibreHardwareMonitor.Hardware.Gpu; + +internal sealed class AmdGpu : GenericGpu { - internal sealed class AmdGpu : GenericGpu + private readonly AtiAdlxx.ADLAdapterInfo _adapterInfo; + private readonly IntPtr _context = IntPtr.Zero; + private readonly Sensor _controlSensor; + private readonly Sensor _coreClock; + private readonly Sensor _coreLoad; + private readonly Sensor _coreVoltage; + private readonly int _currentOverdriveApiLevel; + private readonly string _d3dDeviceId; + private readonly Sensor _fan; + private readonly Control _fanControl; + private readonly bool _frameMetricsStarted; + private readonly Sensor _fullscreenFps; + private readonly Sensor _gpuDedicatedMemoryUsage; + private readonly Sensor[] _gpuNodeUsage; + private readonly DateTime[] _gpuNodeUsagePrevTick; + private readonly long[] _gpuNodeUsagePrevValue; + private readonly Sensor _gpuSharedMemoryUsage; + private readonly Sensor _memoryClock; + private readonly Sensor _memoryLoad; + private readonly Sensor _memoryVoltage; + private readonly bool _overdriveApiSupported; + private readonly Sensor _powerCore; + private readonly Sensor _powerPpt; + private readonly Sensor _powerSoC; + private readonly Sensor _powerTotal; + private readonly Sensor _socClock; + private readonly Sensor _socVoltage; + private readonly Sensor _temperatureCore; + private readonly Sensor _temperatureHotSpot; + private readonly Sensor _temperatureLiquid; + private readonly Sensor _temperatureMemory; + private readonly Sensor _temperatureMvdd; + private readonly Sensor _temperaturePlx; + private readonly Sensor _temperatureSoC; + private readonly Sensor _temperatureVddc; + + private bool? _newQueryPmLogDataGetExists; + + public AmdGpu(AtiAdlxx.ADLAdapterInfo adapterInfo, ISettings settings) + : base(adapterInfo.AdapterName.Trim(), new Identifier("gpu-amd", adapterInfo.AdapterIndex.ToString(CultureInfo.InvariantCulture)), settings) { - private readonly AtiAdlxx.ADLAdapterInfo _adapterInfo; - private readonly IntPtr _context = IntPtr.Zero; - private readonly Sensor _controlSensor; - private readonly Sensor _coreClock; - private readonly Sensor _coreLoad; - private readonly Sensor _coreVoltage; - private readonly int _currentOverdriveApiLevel; - private readonly string _d3dDeviceId; - private readonly Sensor _fan; - private readonly Control _fanControl; - private readonly bool _frameMetricsStarted; - private readonly Sensor _fullscreenFps; - private readonly Sensor _gpuDedicatedMemoryUsage; - private readonly Sensor[] _gpuNodeUsage; - private readonly DateTime[] _gpuNodeUsagePrevTick; - private readonly long[] _gpuNodeUsagePrevValue; - private readonly Sensor _gpuSharedMemoryUsage; - private readonly Sensor _memoryClock; - private readonly Sensor _memoryLoad; - private readonly Sensor _memoryVoltage; - private readonly bool _overdriveApiSupported; - private readonly Sensor _powerCore; - private readonly Sensor _powerPpt; - private readonly Sensor _powerSoC; - private readonly Sensor _powerTotal; - private readonly Sensor _socClock; - private readonly Sensor _socVoltage; - private readonly Sensor _temperatureCore; - private readonly Sensor _temperatureHotSpot; - private readonly Sensor _temperatureLiquid; - private readonly Sensor _temperatureMemory; - private readonly Sensor _temperatureMvdd; - private readonly Sensor _temperaturePlx; - private readonly Sensor _temperatureSoC; - private readonly Sensor _temperatureVddc; + _adapterInfo = adapterInfo; + BusNumber = adapterInfo.BusNumber; + DeviceNumber = adapterInfo.DeviceNumber; - private bool? _newQueryPmLogDataGetExists; + _temperatureCore = new Sensor("GPU Core", 0, SensorType.Temperature, this, settings); + _temperatureMemory = new Sensor("GPU Memory", 1, SensorType.Temperature, this, settings); + _temperatureVddc = new Sensor("GPU VR VDDC", 2, SensorType.Temperature, this, settings); + _temperatureMvdd = new Sensor("GPU VR MVDD", 3, SensorType.Temperature, this, settings); + _temperatureSoC = new Sensor("GPU VR SoC", 4, SensorType.Temperature, this, settings); + _temperatureLiquid = new Sensor("GPU Liquid", 5, SensorType.Temperature, this, settings); + _temperaturePlx = new Sensor("GPU PLX", 6, SensorType.Temperature, this, settings); + _temperatureHotSpot = new Sensor("GPU Hot Spot", 7, SensorType.Temperature, this, settings); - public AmdGpu(AtiAdlxx.ADLAdapterInfo adapterInfo, ISettings settings) - : base(adapterInfo.AdapterName.Trim(), new Identifier("gpu-amd", adapterInfo.AdapterIndex.ToString(CultureInfo.InvariantCulture)), settings) + _coreClock = new Sensor("GPU Core", 0, SensorType.Clock, this, settings); + _socClock = new Sensor("GPU SoC", 1, SensorType.Clock, this, settings); + _memoryClock = new Sensor("GPU Memory", 2, SensorType.Clock, this, settings); + + _fan = new Sensor("GPU Fan", 0, SensorType.Fan, this, settings); + + _coreVoltage = new Sensor("GPU Core", 0, SensorType.Voltage, this, settings); + _memoryVoltage = new Sensor("GPU Memory", 1, SensorType.Voltage, this, settings); + _socVoltage = new Sensor("GPU SoC", 2, SensorType.Voltage, this, settings); + + _coreLoad = new Sensor("GPU Core", 0, SensorType.Load, this, settings); + _memoryLoad = new Sensor("GPU Memory", 1, SensorType.Load, this, settings); + + _controlSensor = new Sensor("GPU Fan", 0, SensorType.Control, this, settings); + + _powerCore = new Sensor("GPU Core", 0, SensorType.Power, this, settings); + _powerPpt = new Sensor("GPU PPT", 1, SensorType.Power, this, settings); + _powerSoC = new Sensor("GPU SoC", 2, SensorType.Power, this, settings); + _powerTotal = new Sensor("GPU Package", 3, SensorType.Power, this, settings); + + _fullscreenFps = new Sensor("Fullscreen FPS", 0, SensorType.Factor, this, settings); + + if (!Software.OperatingSystem.IsUnix) { - _adapterInfo = adapterInfo; - BusNumber = adapterInfo.BusNumber; - DeviceNumber = adapterInfo.DeviceNumber; - - _temperatureCore = new Sensor("GPU Core", 0, SensorType.Temperature, this, settings); - _temperatureMemory = new Sensor("GPU Memory", 1, SensorType.Temperature, this, settings); - _temperatureVddc = new Sensor("GPU VR VDDC", 2, SensorType.Temperature, this, settings); - _temperatureMvdd = new Sensor("GPU VR MVDD", 3, SensorType.Temperature, this, settings); - _temperatureSoC = new Sensor("GPU VR SoC", 4, SensorType.Temperature, this, settings); - _temperatureLiquid = new Sensor("GPU Liquid", 5, SensorType.Temperature, this, settings); - _temperaturePlx = new Sensor("GPU PLX", 6, SensorType.Temperature, this, settings); - _temperatureHotSpot = new Sensor("GPU Hot Spot", 7, SensorType.Temperature, this, settings); - - _coreClock = new Sensor("GPU Core", 0, SensorType.Clock, this, settings); - _socClock = new Sensor("GPU SoC", 1, SensorType.Clock, this, settings); - _memoryClock = new Sensor("GPU Memory", 2, SensorType.Clock, this, settings); - - _fan = new Sensor("GPU Fan", 0, SensorType.Fan, this, settings); - - _coreVoltage = new Sensor("GPU Core", 0, SensorType.Voltage, this, settings); - _memoryVoltage = new Sensor("GPU Memory", 1, SensorType.Voltage, this, settings); - _socVoltage = new Sensor("GPU SoC", 2, SensorType.Voltage, this, settings); - - _coreLoad = new Sensor("GPU Core", 0, SensorType.Load, this, settings); - _memoryLoad = new Sensor("GPU Memory", 1, SensorType.Load, this, settings); - - _controlSensor = new Sensor("GPU Fan", 0, SensorType.Control, this, settings); - - _powerCore = new Sensor("GPU Core", 0, SensorType.Power, this, settings); - _powerPpt = new Sensor("GPU PPT", 1, SensorType.Power, this, settings); - _powerSoC = new Sensor("GPU SoC", 2, SensorType.Power, this, settings); - _powerTotal = new Sensor("GPU Package", 3, SensorType.Power, this, settings); - - _fullscreenFps = new Sensor("Fullscreen FPS", 0, SensorType.Factor, this, settings); - - if (!Software.OperatingSystem.IsUnix) + string[] deviceIds = D3DDisplayDevice.GetDeviceIdentifiers(); + if (deviceIds != null) { - string[] deviceIds = D3DDisplayDevice.GetDeviceIdentifiers(); - if (deviceIds != null) + foreach (string deviceId in deviceIds) { - foreach (string deviceId in deviceIds) - { - string actualDeviceId = D3DDisplayDevice.GetActualDeviceIdentifier(deviceId); + string actualDeviceId = D3DDisplayDevice.GetActualDeviceIdentifier(deviceId); - if ((actualDeviceId.IndexOf(adapterInfo.PNPString, StringComparison.OrdinalIgnoreCase) != -1 || - adapterInfo.PNPString.IndexOf(actualDeviceId, StringComparison.OrdinalIgnoreCase) != -1) && - D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + if ((actualDeviceId.IndexOf(adapterInfo.PNPString, StringComparison.OrdinalIgnoreCase) != -1 || + adapterInfo.PNPString.IndexOf(actualDeviceId, StringComparison.OrdinalIgnoreCase) != -1) && + D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _d3dDeviceId = deviceId; + + int nodeSensorIndex = 2; + int memorySensorIndex = 0; + + _gpuDedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); + _gpuSharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex, SensorType.SmallData, this, settings); + + _gpuNodeUsage = new Sensor[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes.OrderBy(x => x.Name)) { - _d3dDeviceId = deviceId; - - int nodeSensorIndex = 2; - int memorySensorIndex = 0; - - _gpuDedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); - _gpuSharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex, SensorType.SmallData, this, settings); - - _gpuNodeUsage = new Sensor[deviceInfo.Nodes.Length]; - _gpuNodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; - _gpuNodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; - - foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes.OrderBy(x => x.Name)) - { - _gpuNodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); - _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; - _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; - } - - break; + _gpuNodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; } + + break; } } } - - int supported = 0; - int enabled = 0; - int version = 0; - - if (AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL2_Adapter_FrameMetrics_Caps)) && - AtiAdlxx.ADL2_Adapter_FrameMetrics_Caps(_context, _adapterInfo.AdapterIndex, ref supported) == AtiAdlxx.ADLStatus.ADL_OK && supported == AtiAdlxx.ADL_TRUE && AtiAdlxx.ADL2_Adapter_FrameMetrics_Start(_context, _adapterInfo.AdapterIndex, 0) == AtiAdlxx.ADLStatus.ADL_OK) - { - _frameMetricsStarted = true; - _fullscreenFps.Value = -1; - ActivateSensor(_fullscreenFps); - } - - if (AtiAdlxx.ADL_Overdrive_Caps(_adapterInfo.AdapterIndex, ref supported, ref enabled, ref version) == AtiAdlxx.ADLStatus.ADL_OK) - { - _overdriveApiSupported = supported == AtiAdlxx.ADL_TRUE; - _currentOverdriveApiLevel = version; - } - else - { - _currentOverdriveApiLevel = -1; - } - - if (_currentOverdriveApiLevel >= 5 && - AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL2_Main_Control_Create)) && - AtiAdlxx.ADL2_Main_Control_Create(AtiAdlxx.Main_Memory_Alloc, _adapterInfo.AdapterIndex, ref _context) != AtiAdlxx.ADLStatus.ADL_OK) - { - _context = IntPtr.Zero; - } - - AtiAdlxx.ADLFanSpeedInfo fanSpeedInfo = new(); - if (AtiAdlxx.ADL_Overdrive5_FanSpeedInfo_Get(_adapterInfo.AdapterIndex, 0, ref fanSpeedInfo) != AtiAdlxx.ADLStatus.ADL_OK) - { - fanSpeedInfo.MaxPercent = 100; - fanSpeedInfo.MinPercent = 0; - } - - _fanControl = new Control(_controlSensor, settings, fanSpeedInfo.MinPercent, fanSpeedInfo.MaxPercent); - _fanControl.ControlModeChanged += ControlModeChanged; - _fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged; - ControlModeChanged(_fanControl); - _controlSensor.Control = _fanControl; - - Update(); } - public int BusNumber { get; } + int supported = 0; + int enabled = 0; + int version = 0; - /// - public override string DeviceId => _adapterInfo.PNPString; - - public int DeviceNumber { get; } - - public override HardwareType HardwareType + if (AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL2_Adapter_FrameMetrics_Caps)) && + AtiAdlxx.ADL2_Adapter_FrameMetrics_Caps(_context, _adapterInfo.AdapterIndex, ref supported) == AtiAdlxx.ADLStatus.ADL_OK && supported == AtiAdlxx.ADL_TRUE && AtiAdlxx.ADL2_Adapter_FrameMetrics_Start(_context, _adapterInfo.AdapterIndex, 0) == AtiAdlxx.ADLStatus.ADL_OK) { - get { return HardwareType.GpuAmd; } + _frameMetricsStarted = true; + _fullscreenFps.Value = -1; + ActivateSensor(_fullscreenFps); } - private void SoftwareControlValueChanged(IControl control) + if (AtiAdlxx.ADL_Overdrive_Caps(_adapterInfo.AdapterIndex, ref supported, ref enabled, ref version) == AtiAdlxx.ADLStatus.ADL_OK) { - if (control.ControlMode == ControlMode.Software) - { - AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new() - { - SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT, Flags = AtiAdlxx.ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED, FanSpeed = (int)control.SoftwareValue - }; + _overdriveApiSupported = supported == AtiAdlxx.ADL_TRUE; + _currentOverdriveApiLevel = version; + } + else + { + _currentOverdriveApiLevel = -1; + } - AtiAdlxx.ADL_Overdrive5_FanSpeed_Set(_adapterInfo.AdapterIndex, 0, ref fanSpeedValue); + if (_currentOverdriveApiLevel >= 5 && + AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL2_Main_Control_Create)) && + AtiAdlxx.ADL2_Main_Control_Create(AtiAdlxx.Main_Memory_Alloc, _adapterInfo.AdapterIndex, ref _context) != AtiAdlxx.ADLStatus.ADL_OK) + { + _context = IntPtr.Zero; + } + + AtiAdlxx.ADLFanSpeedInfo fanSpeedInfo = new(); + if (AtiAdlxx.ADL_Overdrive5_FanSpeedInfo_Get(_adapterInfo.AdapterIndex, 0, ref fanSpeedInfo) != AtiAdlxx.ADLStatus.ADL_OK) + { + fanSpeedInfo.MaxPercent = 100; + fanSpeedInfo.MinPercent = 0; + } + + _fanControl = new Control(_controlSensor, settings, fanSpeedInfo.MinPercent, fanSpeedInfo.MaxPercent); + _fanControl.ControlModeChanged += ControlModeChanged; + _fanControl.SoftwareControlValueChanged += SoftwareControlValueChanged; + ControlModeChanged(_fanControl); + _controlSensor.Control = _fanControl; + + Update(); + } + + public int BusNumber { get; } + + /// + public override string DeviceId => _adapterInfo.PNPString; + + public int DeviceNumber { get; } + + public override HardwareType HardwareType + { + get { return HardwareType.GpuAmd; } + } + + private void SoftwareControlValueChanged(IControl control) + { + if (control.ControlMode == ControlMode.Software) + { + AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new() + { + SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT, Flags = AtiAdlxx.ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED, FanSpeed = (int)control.SoftwareValue + }; + + AtiAdlxx.ADL_Overdrive5_FanSpeed_Set(_adapterInfo.AdapterIndex, 0, ref fanSpeedValue); + } + } + + private void ControlModeChanged(IControl control) + { + switch (control.ControlMode) + { + case ControlMode.Undefined: + return; + case ControlMode.Default: + SetDefaultFanSpeed(); + break; + case ControlMode.Software: + SoftwareControlValueChanged(control); + break; + default: + return; + } + } + + /// + /// Sets the default fan speed. + /// + private void SetDefaultFanSpeed() + { + AtiAdlxx.ADL_Overdrive5_FanSpeedToDefault_Set(_adapterInfo.AdapterIndex, 0); + } + + public override void Update() + { + if (_d3dDeviceId != null && D3DDisplayDevice.GetDeviceInfoByIdentifier(_d3dDeviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _gpuDedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; + _gpuSharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; + ActivateSensor(_gpuDedicatedMemoryUsage); + ActivateSensor(_gpuSharedMemoryUsage); + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) + { + long runningTimeDiff = node.RunningTime - _gpuNodeUsagePrevValue[node.Id]; + long timeDiff = node.QueryTime.Ticks - _gpuNodeUsagePrevTick[node.Id].Ticks; + + _gpuNodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; + ActivateSensor(_gpuNodeUsage[node.Id]); } } - private void ControlModeChanged(IControl control) + if (_frameMetricsStarted) { - switch (control.ControlMode) + float framesPerSecond = 0; + if (AtiAdlxx.ADL2_Adapter_FrameMetrics_Get(_context, _adapterInfo.AdapterIndex, 0, ref framesPerSecond) == AtiAdlxx.ADLStatus.ADL_OK) { - case ControlMode.Undefined: - return; - case ControlMode.Default: - SetDefaultFanSpeed(); - break; - case ControlMode.Software: - SoftwareControlValueChanged(control); - break; - default: - return; + _fullscreenFps.Value = framesPerSecond; } } - /// - /// Sets the default fan speed. - /// - private void SetDefaultFanSpeed() + if (_overdriveApiSupported) { - AtiAdlxx.ADL_Overdrive5_FanSpeedToDefault_Set(_adapterInfo.AdapterIndex, 0); - } + GetOD5Temperature(_temperatureCore); + GetOD5FanSpeed(AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_RPM, _fan); + GetOD5FanSpeed(AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT, _controlSensor); + GetOD5CurrentActivity(); - public override void Update() - { - if (_d3dDeviceId != null && D3DDisplayDevice.GetDeviceInfoByIdentifier(_d3dDeviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + if (_currentOverdriveApiLevel >= 6) { - _gpuDedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; - _gpuSharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; - ActivateSensor(_gpuDedicatedMemoryUsage); - ActivateSensor(_gpuSharedMemoryUsage); - - foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) - { - long runningTimeDiff = node.RunningTime - _gpuNodeUsagePrevValue[node.Id]; - long timeDiff = node.QueryTime.Ticks - _gpuNodeUsagePrevTick[node.Id].Ticks; - - _gpuNodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; - _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; - _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; - ActivateSensor(_gpuNodeUsage[node.Id]); - } + GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_TOTAL_POWER, _powerTotal); + GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_PPT_POWER, _powerPpt); + GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_SOCKET_POWER, _powerSoC); + GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_CHIP_POWER, _powerCore); } - if (_frameMetricsStarted) + if (_currentOverdriveApiLevel >= 7) { - float framesPerSecond = 0; - if (AtiAdlxx.ADL2_Adapter_FrameMetrics_Get(_context, _adapterInfo.AdapterIndex, 0, ref framesPerSecond) == AtiAdlxx.ADLStatus.ADL_OK) - { - _fullscreenFps.Value = framesPerSecond; - } - } - - if (_overdriveApiSupported) - { - GetOD5Temperature(_temperatureCore); - GetOD5FanSpeed(AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_RPM, _fan); - GetOD5FanSpeed(AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT, _controlSensor); - GetOD5CurrentActivity(); - - if (_currentOverdriveApiLevel >= 6) - { - GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_TOTAL_POWER, _powerTotal); - GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_PPT_POWER, _powerPpt); - GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_SOCKET_POWER, _powerSoC); - GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType.ODN_GPU_CHIP_POWER, _powerCore); - } - - if (_currentOverdriveApiLevel >= 7) - { - GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.EDGE, _temperatureCore, -256, 0.001, false); - GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.MEM, _temperatureMemory); - GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.VRVDDC, _temperatureVddc); - GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.VRMVDD, _temperatureMvdd); - GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.LIQUID, _temperatureLiquid); - GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.PLX, _temperaturePlx); - GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.HOTSPOT, _temperatureHotSpot); - } - } - - if (_currentOverdriveApiLevel >= 8 || !_overdriveApiSupported) - { - AtiAdlxx.ADLPMLogDataOutput logDataOutput = new(); - - _newQueryPmLogDataGetExists ??= AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL2_New_QueryPMLogData_Get)); - - if (_newQueryPmLogDataGetExists == true && AtiAdlxx.ADL2_New_QueryPMLogData_Get(_context, _adapterInfo.AdapterIndex, ref logDataOutput) == AtiAdlxx.ADLStatus.ADL_OK) - { - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_EDGE, _temperatureCore, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_MEM, _temperatureMemory, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_VRVDDC, _temperatureVddc, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_VRMVDD, _temperatureMvdd, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_LIQUID, _temperatureLiquid, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_PLX, _temperaturePlx, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_HOTSPOT, _temperatureHotSpot, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_SOC, _temperatureSoC); - - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_CLK_GFXCLK, _coreClock, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_CLK_SOCCLK, _socClock); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_CLK_MEMCLK, _memoryClock, reset: false); - - const int fanRpmIndex = (int)AtiAdlxx.ADLSensorType.PMLOG_FAN_RPM; - const int fanPercentageIndex = (int)AtiAdlxx.ADLSensorType.PMLOG_FAN_PERCENTAGE; - - if (logDataOutput.sensors.Length is > fanRpmIndex and > fanPercentageIndex && - logDataOutput.sensors[fanRpmIndex].value != ushort.MaxValue && - logDataOutput.sensors[fanRpmIndex].supported != 0) - { - _fan.Value = logDataOutput.sensors[fanRpmIndex].value; - _controlSensor.Value = logDataOutput.sensors[fanPercentageIndex].value; - - ActivateSensor(_fan); - ActivateSensor(_controlSensor); - } - - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_GFX_VOLTAGE, _coreVoltage, 0.001f, false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_SOC_VOLTAGE, _socVoltage, 0.001f); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_MEM_VOLTAGE, _memoryVoltage, 0.001f); - - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_INFO_ACTIVITY_GFX, _coreLoad, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_INFO_ACTIVITY_MEM, _memoryLoad); - - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_ASIC_POWER, _powerTotal, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_GFX_POWER, _powerCore, reset: false); - GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_SOC_POWER, _powerSoC, reset: false); - } + GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.EDGE, _temperatureCore, -256, 0.001, false); + GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.MEM, _temperatureMemory); + GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.VRVDDC, _temperatureVddc); + GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.VRMVDD, _temperatureMvdd); + GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.LIQUID, _temperatureLiquid); + GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.PLX, _temperaturePlx); + GetODNTemperature(AtiAdlxx.ADLODNTemperatureType.HOTSPOT, _temperatureHotSpot); } } - private void GetOD5CurrentActivity() + if (_currentOverdriveApiLevel >= 8 || !_overdriveApiSupported) { - AtiAdlxx.ADLPMActivity adlpmActivity = new(); - if (AtiAdlxx.ADL_Overdrive5_CurrentActivity_Get(_adapterInfo.AdapterIndex, ref adlpmActivity) == AtiAdlxx.ADLStatus.ADL_OK) + AtiAdlxx.ADLPMLogDataOutput logDataOutput = new(); + + _newQueryPmLogDataGetExists ??= AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL2_New_QueryPMLogData_Get)); + + if (_newQueryPmLogDataGetExists == true && AtiAdlxx.ADL2_New_QueryPMLogData_Get(_context, _adapterInfo.AdapterIndex, ref logDataOutput) == AtiAdlxx.ADLStatus.ADL_OK) { - if (adlpmActivity.EngineClock > 0) + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_EDGE, _temperatureCore, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_MEM, _temperatureMemory, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_VRVDDC, _temperatureVddc, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_VRMVDD, _temperatureMvdd, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_LIQUID, _temperatureLiquid, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_PLX, _temperaturePlx, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_HOTSPOT, _temperatureHotSpot, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_TEMPERATURE_SOC, _temperatureSoC); + + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_CLK_GFXCLK, _coreClock, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_CLK_SOCCLK, _socClock); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_CLK_MEMCLK, _memoryClock, reset: false); + + const int fanRpmIndex = (int)AtiAdlxx.ADLSensorType.PMLOG_FAN_RPM; + const int fanPercentageIndex = (int)AtiAdlxx.ADLSensorType.PMLOG_FAN_PERCENTAGE; + + if (logDataOutput.sensors.Length is > fanRpmIndex and > fanPercentageIndex && + logDataOutput.sensors[fanRpmIndex].value != ushort.MaxValue && + logDataOutput.sensors[fanRpmIndex].supported != 0) { - _coreClock.Value = 0.01f * adlpmActivity.EngineClock; - ActivateSensor(_coreClock); - } - else - { - _coreClock.Value = null; + _fan.Value = logDataOutput.sensors[fanRpmIndex].value; + _controlSensor.Value = logDataOutput.sensors[fanPercentageIndex].value; + + ActivateSensor(_fan); + ActivateSensor(_controlSensor); } - if (adlpmActivity.MemoryClock > 0) - { - _memoryClock.Value = 0.01f * adlpmActivity.MemoryClock; - ActivateSensor(_memoryClock); - } - else - { - _memoryClock.Value = null; - } + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_GFX_VOLTAGE, _coreVoltage, 0.001f, false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_SOC_VOLTAGE, _socVoltage, 0.001f); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_MEM_VOLTAGE, _memoryVoltage, 0.001f); - if (adlpmActivity.Vddc > 0) - { - _coreVoltage.Value = 0.001f * adlpmActivity.Vddc; - ActivateSensor(_coreVoltage); - } - else - { - _coreVoltage.Value = null; - } + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_INFO_ACTIVITY_GFX, _coreLoad, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_INFO_ACTIVITY_MEM, _memoryLoad); - _coreLoad.Value = Math.Min(adlpmActivity.ActivityPercent, 100); - ActivateSensor(_coreLoad); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_ASIC_POWER, _powerTotal, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_GFX_POWER, _powerCore, reset: false); + GetPMLog(logDataOutput, AtiAdlxx.ADLSensorType.PMLOG_SOC_POWER, _powerSoC, reset: false); + } + } + } + + private void GetOD5CurrentActivity() + { + AtiAdlxx.ADLPMActivity adlpmActivity = new(); + if (AtiAdlxx.ADL_Overdrive5_CurrentActivity_Get(_adapterInfo.AdapterIndex, ref adlpmActivity) == AtiAdlxx.ADLStatus.ADL_OK) + { + if (adlpmActivity.EngineClock > 0) + { + _coreClock.Value = 0.01f * adlpmActivity.EngineClock; + ActivateSensor(_coreClock); } else { _coreClock.Value = null; + } + + if (adlpmActivity.MemoryClock > 0) + { + _memoryClock.Value = 0.01f * adlpmActivity.MemoryClock; + ActivateSensor(_memoryClock); + } + else + { _memoryClock.Value = null; + } + + if (adlpmActivity.Vddc > 0) + { + _coreVoltage.Value = 0.001f * adlpmActivity.Vddc; + ActivateSensor(_coreVoltage); + } + else + { _coreVoltage.Value = null; - _coreLoad.Value = null; } + + _coreLoad.Value = Math.Min(adlpmActivity.ActivityPercent, 100); + ActivateSensor(_coreLoad); } - - private void GetOD5FanSpeed(int speedType, Sensor sensor) + else { - AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new() { SpeedType = speedType }; - if (AtiAdlxx.ADL_Overdrive5_FanSpeed_Get(_adapterInfo.AdapterIndex, 0, ref fanSpeedValue) == AtiAdlxx.ADLStatus.ADL_OK) - { - sensor.Value = fanSpeedValue.FanSpeed; - ActivateSensor(sensor); - } - else - { - sensor.Value = null; - } - } - - private void GetOD5Temperature(Sensor temperatureCore) - { - AtiAdlxx.ADLTemperature temperature = new(); - if (AtiAdlxx.ADL_Overdrive5_Temperature_Get(_adapterInfo.AdapterIndex, 0, ref temperature) == AtiAdlxx.ADLStatus.ADL_OK) - { - temperatureCore.Value = 0.001f * temperature.Temperature; - ActivateSensor(temperatureCore); - } - else - { - temperatureCore.Value = null; - } - } - - /// - /// Gets the OverdriveN temperature. - /// - /// The type. - /// The sensor. - /// The minimum temperature. - /// The scale. - /// If set to true, resets the sensor value to null. - private void GetODNTemperature(AtiAdlxx.ADLODNTemperatureType type, Sensor sensor, double minTemperature = -256, double scale = 1, bool reset = true) - { - // If a sensor isn't available, some cards report 54000 degrees C. - // 110C is expected for Navi, so 256C should be enough to use as a maximum. - - int maxTemperature = (int)(256 / scale); - minTemperature = (int)(minTemperature / scale); - - int temperature = 0; - if (AtiAdlxx.ADL2_OverdriveN_Temperature_Get(_context, _adapterInfo.AdapterIndex, type, ref temperature) == AtiAdlxx.ADLStatus.ADL_OK && - temperature >= minTemperature && - temperature <= maxTemperature) - { - sensor.Value = (float)(scale * temperature); - ActivateSensor(sensor); - } - else if (reset) - { - sensor.Value = null; - } - } - - /// - /// Gets a PMLog sensor value. - /// - /// The data. - /// Type of the sensor. - /// The sensor. - /// The factor. - private void GetPMLog(AtiAdlxx.ADLPMLogDataOutput data, AtiAdlxx.ADLSensorType sensorType, Sensor sensor, float factor = 1.0f, bool reset = true) - { - int i = (int)sensorType; - if (i < data.sensors.Length && data.sensors[i].supported != 0) - { - sensor.Value = data.sensors[i].value * factor; - ActivateSensor(sensor); - } - else if (reset) - { - sensor.Value = null; - } - } - - /// - /// Gets the Overdrive6 power. - /// - /// The type. - /// The sensor. - private void GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType type, Sensor sensor) - { - int powerOf8 = 0; - if (AtiAdlxx.ADL2_Overdrive6_CurrentPower_Get(_context, _adapterInfo.AdapterIndex, type, ref powerOf8) == AtiAdlxx.ADLStatus.ADL_OK) - { - sensor.Value = powerOf8 >> 8; - ActivateSensor(sensor); - } - else - { - sensor.Value = null; - } - } - - public override void Close() - { - _fanControl.ControlModeChanged -= ControlModeChanged; - _fanControl.SoftwareControlValueChanged -= SoftwareControlValueChanged; - - if (_fanControl.ControlMode != ControlMode.Undefined) - SetDefaultFanSpeed(); - - if (_frameMetricsStarted) - AtiAdlxx.ADL2_Adapter_FrameMetrics_Stop(_context, _adapterInfo.AdapterIndex, 0); - - if (_context != IntPtr.Zero) - AtiAdlxx.ADL2_Main_Control_Destroy(_context); - - base.Close(); - } - - public override string GetReport() - { - var r = new StringBuilder(); - - r.AppendLine("AMD GPU"); - r.AppendLine(); - - r.Append("AdapterIndex: "); - r.AppendLine(_adapterInfo.AdapterIndex.ToString(CultureInfo.InvariantCulture)); - r.AppendLine(); - - r.AppendLine("Overdrive Caps"); - r.AppendLine(); - - try - { - int supported = 0; - int enabled = 0; - int version = 0; - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive_Caps(_adapterInfo.AdapterIndex, ref supported, ref enabled, ref version); - - r.Append(" Status: "); - r.AppendLine(status.ToString()); - r.Append(" Supported: "); - r.AppendLine(supported.ToString(CultureInfo.InvariantCulture)); - r.Append(" Enabled: "); - r.AppendLine(enabled.ToString(CultureInfo.InvariantCulture)); - r.Append(" Version: "); - r.AppendLine(version.ToString(CultureInfo.InvariantCulture)); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - - r.AppendLine("Overdrive5 Parameters"); - r.AppendLine(); - try - { - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_ODParameters_Get(_adapterInfo.AdapterIndex, out AtiAdlxx.ADLODParameters p); - - r.Append(" Status: "); - r.AppendLine(status.ToString()); - r.AppendFormat(" NumberOfPerformanceLevels: {0}{1}", p.NumberOfPerformanceLevels, Environment.NewLine); - r.AppendFormat(" ActivityReportingSupported: {0}{1}", p.ActivityReportingSupported, Environment.NewLine); - r.AppendFormat(" DiscretePerformanceLevels: {0}{1}", p.DiscretePerformanceLevels, Environment.NewLine); - r.AppendFormat(" EngineClock.Min: {0}{1}", p.EngineClock.Min, Environment.NewLine); - r.AppendFormat(" EngineClock.Max: {0}{1}", p.EngineClock.Max, Environment.NewLine); - r.AppendFormat(" EngineClock.Step: {0}{1}", p.EngineClock.Step, Environment.NewLine); - r.AppendFormat(" MemoryClock.Min: {0}{1}", p.MemoryClock.Min, Environment.NewLine); - r.AppendFormat(" MemoryClock.Max: {0}{1}", p.MemoryClock.Max, Environment.NewLine); - r.AppendFormat(" MemoryClock.Step: {0}{1}", p.MemoryClock.Step, Environment.NewLine); - r.AppendFormat(" Vddc.Min: {0}{1}", p.Vddc.Min, Environment.NewLine); - r.AppendFormat(" Vddc.Max: {0}{1}", p.Vddc.Max, Environment.NewLine); - r.AppendFormat(" Vddc.Step: {0}{1}", p.Vddc.Step, Environment.NewLine); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - - r.AppendLine("Overdrive5 Temperature"); - r.AppendLine(); - try - { - var adlt = new AtiAdlxx.ADLTemperature(); - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_Temperature_Get(_adapterInfo.AdapterIndex, 0, ref adlt); - r.Append(" Status: "); - r.AppendLine(status.ToString()); - r.AppendFormat(" Value: {0}{1}", 0.001f * adlt.Temperature, Environment.NewLine); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - - r.AppendLine("Overdrive5 FanSpeed"); - r.AppendLine(); - try - { - var adlf = new AtiAdlxx.ADLFanSpeedValue { SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_RPM }; - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_FanSpeed_Get(_adapterInfo.AdapterIndex, 0, ref adlf); - r.Append(" Status RPM: "); - r.AppendLine(status.ToString()); - r.AppendFormat(" Value RPM: {0}{1}", adlf.FanSpeed, Environment.NewLine); - - adlf.SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT; - status = AtiAdlxx.ADL_Overdrive5_FanSpeed_Get(_adapterInfo.AdapterIndex, 0, ref adlf); - r.Append(" Status Percent: "); - r.AppendLine(status.ToString()); - r.AppendFormat(" Value Percent: {0}{1}", adlf.FanSpeed, Environment.NewLine); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - - r.AppendLine("Overdrive5 CurrentActivity"); - r.AppendLine(); - try - { - var adlp = new AtiAdlxx.ADLPMActivity(); - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_CurrentActivity_Get(_adapterInfo.AdapterIndex, ref adlp); - - r.Append(" Status: "); - r.AppendLine(status.ToString()); - r.AppendFormat(" EngineClock: {0}{1}", 0.01f * adlp.EngineClock, Environment.NewLine); - r.AppendFormat(" MemoryClock: {0}{1}", 0.01f * adlp.MemoryClock, Environment.NewLine); - r.AppendFormat(" Vddc: {0}{1}", 0.001f * adlp.Vddc, Environment.NewLine); - r.AppendFormat(" ActivityPercent: {0}{1}", adlp.ActivityPercent, Environment.NewLine); - r.AppendFormat(" CurrentPerformanceLevel: {0}{1}", adlp.CurrentPerformanceLevel, Environment.NewLine); - r.AppendFormat(" CurrentBusSpeed: {0}{1}", adlp.CurrentBusSpeed, Environment.NewLine); - r.AppendFormat(" CurrentBusLanes: {0}{1}", adlp.CurrentBusLanes, Environment.NewLine); - r.AppendFormat(" MaximumBusLanes: {0}{1}", adlp.MaximumBusLanes, Environment.NewLine); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - - if (_context != IntPtr.Zero) - { - r.AppendLine("Overdrive6 CurrentPower"); - r.AppendLine(); - try - { - int power = 0; - for (int i = 0; i < 4; i++) - { - string pt = ((AtiAdlxx.ADLODNCurrentPowerType)i).ToString(); - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_Overdrive6_CurrentPower_Get(_context, _adapterInfo.AdapterIndex, (AtiAdlxx.ADLODNCurrentPowerType)i, ref power); - - r.AppendFormat(" Power[{0}].Status: {1}{2}", pt, status.ToString(), Environment.NewLine); - r.AppendFormat(" Power[{0}].Value: {1}{2}", pt, power * (1.0f / 0xFF), Environment.NewLine); - } - } - catch (EntryPointNotFoundException) - { - r.AppendLine(" Status: Entry point not found"); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - } - - if (_context != IntPtr.Zero) - { - r.AppendLine("OverdriveN Temperature"); - r.AppendLine(); - try - { - for (int i = 1; i < 8; i++) - { - int temperature = 0; - string tt = ((AtiAdlxx.ADLODNTemperatureType)i).ToString(); - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_OverdriveN_Temperature_Get(_context, _adapterInfo.AdapterIndex, (AtiAdlxx.ADLODNTemperatureType)i, ref temperature); - - r.AppendFormat(" Temperature[{0}].Status: {1}{2}", tt, status.ToString(), Environment.NewLine); - r.AppendFormat(" Temperature[{0}].Value: {1}{2}", tt, 0.001f * temperature, Environment.NewLine); - } - } - catch (EntryPointNotFoundException) - { - r.AppendLine(" Status: Entry point not found"); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - } - - if (_context != IntPtr.Zero) - { - r.AppendLine("OverdriveN Performance Status"); - r.AppendLine(); - try - { - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_OverdriveN_PerformanceStatus_Get(_context, _adapterInfo.AdapterIndex, out AtiAdlxx.ADLODNPerformanceStatus ps); - - r.Append(" Status: "); - r.AppendLine(status.ToString()); - r.AppendFormat(" CoreClock: {0}{1}", ps.CoreClock, Environment.NewLine); - r.AppendFormat(" MemoryClock: {0}{1}", ps.MemoryClock, Environment.NewLine); - r.AppendFormat(" DCEFClock: {0}{1}", ps.DCEFClock, Environment.NewLine); - r.AppendFormat(" GFXClock: {0}{1}", ps.GFXClock, Environment.NewLine); - r.AppendFormat(" UVDClock: {0}{1}", ps.UVDClock, Environment.NewLine); - r.AppendFormat(" VCEClock: {0}{1}", ps.VCEClock, Environment.NewLine); - r.AppendFormat(" GPUActivityPercent: {0}{1}", ps.GPUActivityPercent, Environment.NewLine); - r.AppendFormat(" CurrentCorePerformanceLevel: {0}{1}", ps.CurrentCorePerformanceLevel, Environment.NewLine); - r.AppendFormat(" CurrentMemoryPerformanceLevel: {0}{1}", ps.CurrentMemoryPerformanceLevel, Environment.NewLine); - r.AppendFormat(" CurrentDCEFPerformanceLevel: {0}{1}", ps.CurrentDCEFPerformanceLevel, Environment.NewLine); - r.AppendFormat(" CurrentGFXPerformanceLevel: {0}{1}", ps.CurrentGFXPerformanceLevel, Environment.NewLine); - r.AppendFormat(" UVDPerformanceLevel: {0}{1}", ps.UVDPerformanceLevel, Environment.NewLine); - r.AppendFormat(" VCEPerformanceLevel: {0}{1}", ps.VCEPerformanceLevel, Environment.NewLine); - r.AppendFormat(" CurrentBusSpeed: {0}{1}", ps.CurrentBusSpeed, Environment.NewLine); - r.AppendFormat(" CurrentBusLanes: {0}{1}", ps.CurrentBusLanes, Environment.NewLine); - r.AppendFormat(" MaximumBusLanes: {0}{1}", ps.MaximumBusLanes, Environment.NewLine); - r.AppendFormat(" VDDC: {0}{1}", ps.VDDC, Environment.NewLine); - r.AppendFormat(" VDDCI: {0}{1}", ps.VDDCI, Environment.NewLine); - } - catch (EntryPointNotFoundException) - { - r.AppendLine(" Status: Entry point not found"); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - } - - if (_context != IntPtr.Zero) - { - r.AppendLine("Performance Metrics"); - r.AppendLine(); - try - { - var data = new AtiAdlxx.ADLPMLogDataOutput(); - AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_New_QueryPMLogData_Get(_context, _adapterInfo.AdapterIndex, ref data); - - r.Append(" Status: "); - r.AppendLine(status.ToString()); - - for (int i = 0; i < data.sensors.Length; i++) - { - string st = ((AtiAdlxx.ADLSensorType)i).ToString(); - - r.AppendFormat(" Sensor[{0}].Supported: {1}{2}", st, data.sensors[i].supported, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].Value: {1}{2}", st, data.sensors[i].value, Environment.NewLine); - } - } - catch (EntryPointNotFoundException) - { - r.AppendLine(" Status: Entry point not found"); - } - catch (Exception e) - { - r.AppendLine(" Status: " + e.Message); - } - - r.AppendLine(); - } - - if (_d3dDeviceId != null) - { - r.AppendLine("D3D"); - r.AppendLine(); - r.AppendLine(" Id: " + _d3dDeviceId); - } - - return r.ToString(); + _coreClock.Value = null; + _memoryClock.Value = null; + _coreVoltage.Value = null; + _coreLoad.Value = null; } } + + private void GetOD5FanSpeed(int speedType, Sensor sensor) + { + AtiAdlxx.ADLFanSpeedValue fanSpeedValue = new() { SpeedType = speedType }; + if (AtiAdlxx.ADL_Overdrive5_FanSpeed_Get(_adapterInfo.AdapterIndex, 0, ref fanSpeedValue) == AtiAdlxx.ADLStatus.ADL_OK) + { + sensor.Value = fanSpeedValue.FanSpeed; + ActivateSensor(sensor); + } + else + { + sensor.Value = null; + } + } + + private void GetOD5Temperature(Sensor temperatureCore) + { + AtiAdlxx.ADLTemperature temperature = new(); + if (AtiAdlxx.ADL_Overdrive5_Temperature_Get(_adapterInfo.AdapterIndex, 0, ref temperature) == AtiAdlxx.ADLStatus.ADL_OK) + { + temperatureCore.Value = 0.001f * temperature.Temperature; + ActivateSensor(temperatureCore); + } + else + { + temperatureCore.Value = null; + } + } + + /// + /// Gets the OverdriveN temperature. + /// + /// The type. + /// The sensor. + /// The minimum temperature. + /// The scale. + /// If set to true, resets the sensor value to null. + private void GetODNTemperature(AtiAdlxx.ADLODNTemperatureType type, Sensor sensor, double minTemperature = -256, double scale = 1, bool reset = true) + { + // If a sensor isn't available, some cards report 54000 degrees C. + // 110C is expected for Navi, so 256C should be enough to use as a maximum. + + int maxTemperature = (int)(256 / scale); + minTemperature = (int)(minTemperature / scale); + + int temperature = 0; + if (AtiAdlxx.ADL2_OverdriveN_Temperature_Get(_context, _adapterInfo.AdapterIndex, type, ref temperature) == AtiAdlxx.ADLStatus.ADL_OK && + temperature >= minTemperature && + temperature <= maxTemperature) + { + sensor.Value = (float)(scale * temperature); + ActivateSensor(sensor); + } + else if (reset) + { + sensor.Value = null; + } + } + + /// + /// Gets a PMLog sensor value. + /// + /// The data. + /// Type of the sensor. + /// The sensor. + /// The factor. + private void GetPMLog(AtiAdlxx.ADLPMLogDataOutput data, AtiAdlxx.ADLSensorType sensorType, Sensor sensor, float factor = 1.0f, bool reset = true) + { + int i = (int)sensorType; + if (i < data.sensors.Length && data.sensors[i].supported != 0) + { + sensor.Value = data.sensors[i].value * factor; + ActivateSensor(sensor); + } + else if (reset) + { + sensor.Value = null; + } + } + + /// + /// Gets the Overdrive6 power. + /// + /// The type. + /// The sensor. + private void GetOD6Power(AtiAdlxx.ADLODNCurrentPowerType type, Sensor sensor) + { + int powerOf8 = 0; + if (AtiAdlxx.ADL2_Overdrive6_CurrentPower_Get(_context, _adapterInfo.AdapterIndex, type, ref powerOf8) == AtiAdlxx.ADLStatus.ADL_OK) + { + sensor.Value = powerOf8 >> 8; + ActivateSensor(sensor); + } + else + { + sensor.Value = null; + } + } + + public override void Close() + { + _fanControl.ControlModeChanged -= ControlModeChanged; + _fanControl.SoftwareControlValueChanged -= SoftwareControlValueChanged; + + if (_fanControl.ControlMode != ControlMode.Undefined) + SetDefaultFanSpeed(); + + if (_frameMetricsStarted) + AtiAdlxx.ADL2_Adapter_FrameMetrics_Stop(_context, _adapterInfo.AdapterIndex, 0); + + if (_context != IntPtr.Zero) + AtiAdlxx.ADL2_Main_Control_Destroy(_context); + + base.Close(); + } + + public override string GetReport() + { + var r = new StringBuilder(); + + r.AppendLine("AMD GPU"); + r.AppendLine(); + + r.Append("AdapterIndex: "); + r.AppendLine(_adapterInfo.AdapterIndex.ToString(CultureInfo.InvariantCulture)); + r.AppendLine(); + + r.AppendLine("Overdrive Caps"); + r.AppendLine(); + + try + { + int supported = 0; + int enabled = 0; + int version = 0; + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive_Caps(_adapterInfo.AdapterIndex, ref supported, ref enabled, ref version); + + r.Append(" Status: "); + r.AppendLine(status.ToString()); + r.Append(" Supported: "); + r.AppendLine(supported.ToString(CultureInfo.InvariantCulture)); + r.Append(" Enabled: "); + r.AppendLine(enabled.ToString(CultureInfo.InvariantCulture)); + r.Append(" Version: "); + r.AppendLine(version.ToString(CultureInfo.InvariantCulture)); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + + r.AppendLine("Overdrive5 Parameters"); + r.AppendLine(); + try + { + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_ODParameters_Get(_adapterInfo.AdapterIndex, out AtiAdlxx.ADLODParameters p); + + r.Append(" Status: "); + r.AppendLine(status.ToString()); + r.AppendFormat(" NumberOfPerformanceLevels: {0}{1}", p.NumberOfPerformanceLevels, Environment.NewLine); + r.AppendFormat(" ActivityReportingSupported: {0}{1}", p.ActivityReportingSupported, Environment.NewLine); + r.AppendFormat(" DiscretePerformanceLevels: {0}{1}", p.DiscretePerformanceLevels, Environment.NewLine); + r.AppendFormat(" EngineClock.Min: {0}{1}", p.EngineClock.Min, Environment.NewLine); + r.AppendFormat(" EngineClock.Max: {0}{1}", p.EngineClock.Max, Environment.NewLine); + r.AppendFormat(" EngineClock.Step: {0}{1}", p.EngineClock.Step, Environment.NewLine); + r.AppendFormat(" MemoryClock.Min: {0}{1}", p.MemoryClock.Min, Environment.NewLine); + r.AppendFormat(" MemoryClock.Max: {0}{1}", p.MemoryClock.Max, Environment.NewLine); + r.AppendFormat(" MemoryClock.Step: {0}{1}", p.MemoryClock.Step, Environment.NewLine); + r.AppendFormat(" Vddc.Min: {0}{1}", p.Vddc.Min, Environment.NewLine); + r.AppendFormat(" Vddc.Max: {0}{1}", p.Vddc.Max, Environment.NewLine); + r.AppendFormat(" Vddc.Step: {0}{1}", p.Vddc.Step, Environment.NewLine); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + + r.AppendLine("Overdrive5 Temperature"); + r.AppendLine(); + try + { + var adlt = new AtiAdlxx.ADLTemperature(); + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_Temperature_Get(_adapterInfo.AdapterIndex, 0, ref adlt); + r.Append(" Status: "); + r.AppendLine(status.ToString()); + r.AppendFormat(" Value: {0}{1}", 0.001f * adlt.Temperature, Environment.NewLine); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + + r.AppendLine("Overdrive5 FanSpeed"); + r.AppendLine(); + try + { + var adlf = new AtiAdlxx.ADLFanSpeedValue { SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_RPM }; + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_FanSpeed_Get(_adapterInfo.AdapterIndex, 0, ref adlf); + r.Append(" Status RPM: "); + r.AppendLine(status.ToString()); + r.AppendFormat(" Value RPM: {0}{1}", adlf.FanSpeed, Environment.NewLine); + + adlf.SpeedType = AtiAdlxx.ADL_DL_FANCTRL_SPEED_TYPE_PERCENT; + status = AtiAdlxx.ADL_Overdrive5_FanSpeed_Get(_adapterInfo.AdapterIndex, 0, ref adlf); + r.Append(" Status Percent: "); + r.AppendLine(status.ToString()); + r.AppendFormat(" Value Percent: {0}{1}", adlf.FanSpeed, Environment.NewLine); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + + r.AppendLine("Overdrive5 CurrentActivity"); + r.AppendLine(); + try + { + var adlp = new AtiAdlxx.ADLPMActivity(); + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL_Overdrive5_CurrentActivity_Get(_adapterInfo.AdapterIndex, ref adlp); + + r.Append(" Status: "); + r.AppendLine(status.ToString()); + r.AppendFormat(" EngineClock: {0}{1}", 0.01f * adlp.EngineClock, Environment.NewLine); + r.AppendFormat(" MemoryClock: {0}{1}", 0.01f * adlp.MemoryClock, Environment.NewLine); + r.AppendFormat(" Vddc: {0}{1}", 0.001f * adlp.Vddc, Environment.NewLine); + r.AppendFormat(" ActivityPercent: {0}{1}", adlp.ActivityPercent, Environment.NewLine); + r.AppendFormat(" CurrentPerformanceLevel: {0}{1}", adlp.CurrentPerformanceLevel, Environment.NewLine); + r.AppendFormat(" CurrentBusSpeed: {0}{1}", adlp.CurrentBusSpeed, Environment.NewLine); + r.AppendFormat(" CurrentBusLanes: {0}{1}", adlp.CurrentBusLanes, Environment.NewLine); + r.AppendFormat(" MaximumBusLanes: {0}{1}", adlp.MaximumBusLanes, Environment.NewLine); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + + if (_context != IntPtr.Zero) + { + r.AppendLine("Overdrive6 CurrentPower"); + r.AppendLine(); + try + { + int power = 0; + for (int i = 0; i < 4; i++) + { + string pt = ((AtiAdlxx.ADLODNCurrentPowerType)i).ToString(); + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_Overdrive6_CurrentPower_Get(_context, _adapterInfo.AdapterIndex, (AtiAdlxx.ADLODNCurrentPowerType)i, ref power); + + r.AppendFormat(" Power[{0}].Status: {1}{2}", pt, status.ToString(), Environment.NewLine); + r.AppendFormat(" Power[{0}].Value: {1}{2}", pt, power * (1.0f / 0xFF), Environment.NewLine); + } + } + catch (EntryPointNotFoundException) + { + r.AppendLine(" Status: Entry point not found"); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + } + + if (_context != IntPtr.Zero) + { + r.AppendLine("OverdriveN Temperature"); + r.AppendLine(); + try + { + for (int i = 1; i < 8; i++) + { + int temperature = 0; + string tt = ((AtiAdlxx.ADLODNTemperatureType)i).ToString(); + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_OverdriveN_Temperature_Get(_context, _adapterInfo.AdapterIndex, (AtiAdlxx.ADLODNTemperatureType)i, ref temperature); + + r.AppendFormat(" Temperature[{0}].Status: {1}{2}", tt, status.ToString(), Environment.NewLine); + r.AppendFormat(" Temperature[{0}].Value: {1}{2}", tt, 0.001f * temperature, Environment.NewLine); + } + } + catch (EntryPointNotFoundException) + { + r.AppendLine(" Status: Entry point not found"); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + } + + if (_context != IntPtr.Zero) + { + r.AppendLine("OverdriveN Performance Status"); + r.AppendLine(); + try + { + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_OverdriveN_PerformanceStatus_Get(_context, _adapterInfo.AdapterIndex, out AtiAdlxx.ADLODNPerformanceStatus ps); + + r.Append(" Status: "); + r.AppendLine(status.ToString()); + r.AppendFormat(" CoreClock: {0}{1}", ps.CoreClock, Environment.NewLine); + r.AppendFormat(" MemoryClock: {0}{1}", ps.MemoryClock, Environment.NewLine); + r.AppendFormat(" DCEFClock: {0}{1}", ps.DCEFClock, Environment.NewLine); + r.AppendFormat(" GFXClock: {0}{1}", ps.GFXClock, Environment.NewLine); + r.AppendFormat(" UVDClock: {0}{1}", ps.UVDClock, Environment.NewLine); + r.AppendFormat(" VCEClock: {0}{1}", ps.VCEClock, Environment.NewLine); + r.AppendFormat(" GPUActivityPercent: {0}{1}", ps.GPUActivityPercent, Environment.NewLine); + r.AppendFormat(" CurrentCorePerformanceLevel: {0}{1}", ps.CurrentCorePerformanceLevel, Environment.NewLine); + r.AppendFormat(" CurrentMemoryPerformanceLevel: {0}{1}", ps.CurrentMemoryPerformanceLevel, Environment.NewLine); + r.AppendFormat(" CurrentDCEFPerformanceLevel: {0}{1}", ps.CurrentDCEFPerformanceLevel, Environment.NewLine); + r.AppendFormat(" CurrentGFXPerformanceLevel: {0}{1}", ps.CurrentGFXPerformanceLevel, Environment.NewLine); + r.AppendFormat(" UVDPerformanceLevel: {0}{1}", ps.UVDPerformanceLevel, Environment.NewLine); + r.AppendFormat(" VCEPerformanceLevel: {0}{1}", ps.VCEPerformanceLevel, Environment.NewLine); + r.AppendFormat(" CurrentBusSpeed: {0}{1}", ps.CurrentBusSpeed, Environment.NewLine); + r.AppendFormat(" CurrentBusLanes: {0}{1}", ps.CurrentBusLanes, Environment.NewLine); + r.AppendFormat(" MaximumBusLanes: {0}{1}", ps.MaximumBusLanes, Environment.NewLine); + r.AppendFormat(" VDDC: {0}{1}", ps.VDDC, Environment.NewLine); + r.AppendFormat(" VDDCI: {0}{1}", ps.VDDCI, Environment.NewLine); + } + catch (EntryPointNotFoundException) + { + r.AppendLine(" Status: Entry point not found"); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + } + + if (_context != IntPtr.Zero) + { + r.AppendLine("Performance Metrics"); + r.AppendLine(); + try + { + var data = new AtiAdlxx.ADLPMLogDataOutput(); + AtiAdlxx.ADLStatus status = AtiAdlxx.ADL2_New_QueryPMLogData_Get(_context, _adapterInfo.AdapterIndex, ref data); + + r.Append(" Status: "); + r.AppendLine(status.ToString()); + + for (int i = 0; i < data.sensors.Length; i++) + { + string st = ((AtiAdlxx.ADLSensorType)i).ToString(); + + r.AppendFormat(" Sensor[{0}].Supported: {1}{2}", st, data.sensors[i].supported, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].Value: {1}{2}", st, data.sensors[i].value, Environment.NewLine); + } + } + catch (EntryPointNotFoundException) + { + r.AppendLine(" Status: Entry point not found"); + } + catch (Exception e) + { + r.AppendLine(" Status: " + e.Message); + } + + r.AppendLine(); + } + + if (_d3dDeviceId != null) + { + r.AppendLine("D3D"); + r.AppendLine(); + r.AppendLine(" Id: " + _d3dDeviceId); + } + + return r.ToString(); + } } diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs index f65fa62..d54e7f3 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/AmdGpuGroup.cs @@ -11,118 +11,117 @@ using System.Linq; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Gpu +namespace LibreHardwareMonitor.Hardware.Gpu; + +internal class AmdGpuGroup : IGroup { - internal class AmdGpuGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + private readonly AtiAdlxx.ADLStatus _status; + + public AmdGpuGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); - private readonly AtiAdlxx.ADLStatus _status; - - public AmdGpuGroup(ISettings settings) + try { - try + _status = AtiAdlxx.ADL_Main_Control_Create(1); + + _report.AppendLine("AMD Display Library"); + _report.AppendLine(); + _report.Append("Status: "); + _report.AppendLine(_status == AtiAdlxx.ADLStatus.ADL_OK ? "OK" : _status.ToString()); + _report.AppendLine(); + + if (_status == AtiAdlxx.ADLStatus.ADL_OK) { - _status = AtiAdlxx.ADL_Main_Control_Create(1); + int numberOfAdapters = 0; + AtiAdlxx.ADL_Adapter_NumberOfAdapters_Get(ref numberOfAdapters); - _report.AppendLine("AMD Display Library"); - _report.AppendLine(); - _report.Append("Status: "); - _report.AppendLine(_status == AtiAdlxx.ADLStatus.ADL_OK ? "OK" : _status.ToString()); + _report.Append("Number of adapters: "); + _report.AppendLine(numberOfAdapters.ToString(CultureInfo.InvariantCulture)); _report.AppendLine(); - if (_status == AtiAdlxx.ADLStatus.ADL_OK) + if (numberOfAdapters > 0) { - int numberOfAdapters = 0; - AtiAdlxx.ADL_Adapter_NumberOfAdapters_Get(ref numberOfAdapters); + List potentialHardware = new(); - _report.Append("Number of adapters: "); - _report.AppendLine(numberOfAdapters.ToString(CultureInfo.InvariantCulture)); - _report.AppendLine(); - - if (numberOfAdapters > 0) + AtiAdlxx.ADLAdapterInfo[] adapterInfo = new AtiAdlxx.ADLAdapterInfo[numberOfAdapters]; + if (AtiAdlxx.ADL_Adapter_AdapterInfo_Get(adapterInfo) == AtiAdlxx.ADLStatus.ADL_OK) { - List potentialHardware = new(); - - AtiAdlxx.ADLAdapterInfo[] adapterInfo = new AtiAdlxx.ADLAdapterInfo[numberOfAdapters]; - if (AtiAdlxx.ADL_Adapter_AdapterInfo_Get(adapterInfo) == AtiAdlxx.ADLStatus.ADL_OK) + for (int i = 0; i < numberOfAdapters; i++) { - for (int i = 0; i < numberOfAdapters; i++) - { - AtiAdlxx.ADL_Adapter_Active_Get(adapterInfo[i].AdapterIndex, out int isActive); + AtiAdlxx.ADL_Adapter_Active_Get(adapterInfo[i].AdapterIndex, out int isActive); - int adapterId = -1; - if (AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL_Adapter_ID_Get))) - AtiAdlxx.ADL_Adapter_ID_Get(adapterInfo[i].AdapterIndex, out adapterId); + int adapterId = -1; + if (AtiAdlxx.ADL_Method_Exists(nameof(AtiAdlxx.ADL_Adapter_ID_Get))) + AtiAdlxx.ADL_Adapter_ID_Get(adapterInfo[i].AdapterIndex, out adapterId); - _report.Append("AdapterIndex: "); - _report.AppendLine(i.ToString(CultureInfo.InvariantCulture)); - _report.Append("isActive: "); - _report.AppendLine(isActive.ToString(CultureInfo.InvariantCulture)); - _report.Append("AdapterName: "); - _report.AppendLine(adapterInfo[i].AdapterName); - _report.Append("UDID: "); - _report.AppendLine(adapterInfo[i].UDID); - _report.Append("PNPString: "); - _report.AppendLine(adapterInfo[i].PNPString); - _report.Append("Present: "); - _report.AppendLine(adapterInfo[i].Present.ToString(CultureInfo.InvariantCulture)); - _report.Append("VendorID: 0x"); - _report.AppendLine(adapterInfo[i].VendorID.ToString("X", CultureInfo.InvariantCulture)); - _report.Append("BusNumber: "); - _report.AppendLine(adapterInfo[i].BusNumber.ToString(CultureInfo.InvariantCulture)); - _report.Append("DeviceNumber: "); - _report.AppendLine(adapterInfo[i].DeviceNumber.ToString(CultureInfo.InvariantCulture)); - _report.Append("FunctionNumber: "); - _report.AppendLine(adapterInfo[i].FunctionNumber.ToString(CultureInfo.InvariantCulture)); - _report.Append("AdapterID: 0x"); - _report.AppendLine(adapterId.ToString("X", CultureInfo.InvariantCulture)); + _report.Append("AdapterIndex: "); + _report.AppendLine(i.ToString(CultureInfo.InvariantCulture)); + _report.Append("isActive: "); + _report.AppendLine(isActive.ToString(CultureInfo.InvariantCulture)); + _report.Append("AdapterName: "); + _report.AppendLine(adapterInfo[i].AdapterName); + _report.Append("UDID: "); + _report.AppendLine(adapterInfo[i].UDID); + _report.Append("PNPString: "); + _report.AppendLine(adapterInfo[i].PNPString); + _report.Append("Present: "); + _report.AppendLine(adapterInfo[i].Present.ToString(CultureInfo.InvariantCulture)); + _report.Append("VendorID: 0x"); + _report.AppendLine(adapterInfo[i].VendorID.ToString("X", CultureInfo.InvariantCulture)); + _report.Append("BusNumber: "); + _report.AppendLine(adapterInfo[i].BusNumber.ToString(CultureInfo.InvariantCulture)); + _report.Append("DeviceNumber: "); + _report.AppendLine(adapterInfo[i].DeviceNumber.ToString(CultureInfo.InvariantCulture)); + _report.Append("FunctionNumber: "); + _report.AppendLine(adapterInfo[i].FunctionNumber.ToString(CultureInfo.InvariantCulture)); + _report.Append("AdapterID: 0x"); + _report.AppendLine(adapterId.ToString("X", CultureInfo.InvariantCulture)); - if (!string.IsNullOrEmpty(adapterInfo[i].UDID) && adapterInfo[i].VendorID == AtiAdlxx.ATI_VENDOR_ID) - potentialHardware.Add(new AmdGpu(adapterInfo[i], settings)); + if (!string.IsNullOrEmpty(adapterInfo[i].UDID) && adapterInfo[i].VendorID == AtiAdlxx.ATI_VENDOR_ID) + potentialHardware.Add(new AmdGpu(adapterInfo[i], settings)); - _report.AppendLine(); - } + _report.AppendLine(); } + } - foreach (IGrouping amdGpus in potentialHardware.GroupBy(x => $"{x.BusNumber}-{x.DeviceNumber}")) - { - AmdGpu amdGpu = amdGpus.OrderByDescending(x => x.Sensors.Length).FirstOrDefault(); - if (amdGpu != null) - _hardware.Add(amdGpu); - } + foreach (IGrouping amdGpus in potentialHardware.GroupBy(x => $"{x.BusNumber}-{x.DeviceNumber}")) + { + AmdGpu amdGpu = amdGpus.OrderByDescending(x => x.Sensors.Length).FirstOrDefault(); + if (amdGpu != null) + _hardware.Add(amdGpu); } } } - catch (DllNotFoundException) - { } - catch (EntryPointNotFoundException e) - { - _report.AppendLine(); - _report.AppendLine(e.ToString()); - _report.AppendLine(); - } } - - public IReadOnlyList Hardware => _hardware; - - public string GetReport() + catch (DllNotFoundException) + { } + catch (EntryPointNotFoundException e) { - return _report.ToString(); - } - - public void Close() - { - try - { - foreach (AmdGpu gpu in _hardware) - gpu.Close(); - - if (_status == AtiAdlxx.ADLStatus.ADL_OK) - AtiAdlxx.ADL_Main_Control_Destroy(); - } - catch (Exception) - { } + _report.AppendLine(); + _report.AppendLine(e.ToString()); + _report.AppendLine(); } } + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + return _report.ToString(); + } + + public void Close() + { + try + { + foreach (AmdGpu gpu in _hardware) + gpu.Close(); + + if (_status == AtiAdlxx.ADLStatus.ADL_OK) + AtiAdlxx.ADL_Main_Control_Destroy(); + } + catch (Exception) + { } + } } diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs index e9e86b8..cb4ff96 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/GenericGpu.cs @@ -3,22 +3,21 @@ // Copyright (C) LibreHardwareMonitor and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.Gpu -{ - public abstract class GenericGpu : Hardware - { - /// - /// Initializes a new instance of the class. - /// - /// Component name. - /// Identifier that will be assigned to the device. Based on - /// Additional settings passed by the . - protected GenericGpu(string name, Identifier identifier, ISettings settings) : base(name, identifier, settings) - { } +namespace LibreHardwareMonitor.Hardware.Gpu; - /// - /// Gets the device identifier. - /// - public abstract string DeviceId { get; } - } -} +public abstract class GenericGpu : Hardware +{ + /// + /// Initializes a new instance of the class. + /// + /// Component name. + /// Identifier that will be assigned to the device. Based on + /// Additional settings passed by the . + protected GenericGpu(string name, Identifier identifier, ISettings settings) : base(name, identifier, settings) + { } + + /// + /// Gets the device identifier. + /// + public abstract string DeviceId { get; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs b/LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs index 52e3346..f8821e7 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/IntelGpuGroup.cs @@ -9,79 +9,78 @@ using System.Globalization; using System.Text; using LibreHardwareMonitor.Hardware.CPU; -namespace LibreHardwareMonitor.Hardware.Gpu +namespace LibreHardwareMonitor.Hardware.Gpu; + +internal class IntelGpuGroup : IGroup { - internal class IntelGpuGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public IntelGpuGroup(List intelCpus, ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); - - public IntelGpuGroup(List intelCpus, ISettings settings) + if (!Software.OperatingSystem.IsUnix && intelCpus?.Count > 0) { - if (!Software.OperatingSystem.IsUnix && intelCpus?.Count > 0) + _report.AppendLine("Intel GPU (D3D)"); + _report.AppendLine(); + + string[] ids = D3DDisplayDevice.GetDeviceIdentifiers(); + + _report.Append("Number of adapters: "); + _report.AppendLine(ids.Length.ToString(CultureInfo.InvariantCulture)); + _report.AppendLine(); + + for (int i = 0; i < ids.Length; i++) { - _report.AppendLine("Intel GPU (D3D)"); - _report.AppendLine(); + string deviceId = ids[i]; + bool isIntel = deviceId.IndexOf("VEN_8086", StringComparison.Ordinal) != -1; - string[] ids = D3DDisplayDevice.GetDeviceIdentifiers(); + _report.Append("AdapterIndex: "); + _report.AppendLine(i.ToString(CultureInfo.InvariantCulture)); + _report.Append("DeviceId: "); + _report.AppendLine(deviceId); + _report.Append("IsIntel: "); + _report.AppendLine(isIntel.ToString(CultureInfo.InvariantCulture)); - _report.Append("Number of adapters: "); - _report.AppendLine(ids.Length.ToString(CultureInfo.InvariantCulture)); - _report.AppendLine(); - - for (int i = 0; i < ids.Length; i++) + if (isIntel && D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) { - string deviceId = ids[i]; - bool isIntel = deviceId.IndexOf("VEN_8086", StringComparison.Ordinal) != -1; + _report.Append("GpuSharedLimit: "); + _report.AppendLine(deviceInfo.GpuSharedLimit.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuSharedUsed: "); + _report.AppendLine(deviceInfo.GpuSharedUsed.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuSharedMax: "); + _report.AppendLine(deviceInfo.GpuSharedMax.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuDedicatedLimit: "); + _report.AppendLine(deviceInfo.GpuDedicatedLimit.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuDedicatedUsed: "); + _report.AppendLine(deviceInfo.GpuDedicatedUsed.ToString(CultureInfo.InvariantCulture)); + _report.Append("GpuDedicatedMax: "); + _report.AppendLine(deviceInfo.GpuDedicatedMax.ToString(CultureInfo.InvariantCulture)); + _report.Append("Integrated: "); + _report.AppendLine(deviceInfo.Integrated.ToString(CultureInfo.InvariantCulture)); - _report.Append("AdapterIndex: "); - _report.AppendLine(i.ToString(CultureInfo.InvariantCulture)); - _report.Append("DeviceId: "); - _report.AppendLine(deviceId); - _report.Append("IsIntel: "); - _report.AppendLine(isIntel.ToString(CultureInfo.InvariantCulture)); - - if (isIntel && D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + if (deviceInfo.Integrated) { - _report.Append("GpuSharedLimit: "); - _report.AppendLine(deviceInfo.GpuSharedLimit.ToString(CultureInfo.InvariantCulture)); - _report.Append("GpuSharedUsed: "); - _report.AppendLine(deviceInfo.GpuSharedUsed.ToString(CultureInfo.InvariantCulture)); - _report.Append("GpuSharedMax: "); - _report.AppendLine(deviceInfo.GpuSharedMax.ToString(CultureInfo.InvariantCulture)); - _report.Append("GpuDedicatedLimit: "); - _report.AppendLine(deviceInfo.GpuDedicatedLimit.ToString(CultureInfo.InvariantCulture)); - _report.Append("GpuDedicatedUsed: "); - _report.AppendLine(deviceInfo.GpuDedicatedUsed.ToString(CultureInfo.InvariantCulture)); - _report.Append("GpuDedicatedMax: "); - _report.AppendLine(deviceInfo.GpuDedicatedMax.ToString(CultureInfo.InvariantCulture)); - _report.Append("Integrated: "); - _report.AppendLine(deviceInfo.Integrated.ToString(CultureInfo.InvariantCulture)); - - if (deviceInfo.Integrated) - { - // It may seem strange to only use the first cpu here, but in-case we have a multi cpu system with integrated graphics (does that exist?), - // we would pick up the multiple device identifiers above and would add one instance for each CPU. - _hardware.Add(new IntelIntegratedGpu(intelCpus[0], deviceId, deviceInfo, settings)); - } + // It may seem strange to only use the first cpu here, but in-case we have a multi cpu system with integrated graphics (does that exist?), + // we would pick up the multiple device identifiers above and would add one instance for each CPU. + _hardware.Add(new IntelIntegratedGpu(intelCpus[0], deviceId, deviceInfo, settings)); } - - _report.AppendLine(); } + + _report.AppendLine(); } } - - public IReadOnlyList Hardware => _hardware; - - public string GetReport() - { - return _report.ToString(); - } - - public void Close() - { - foreach (Hardware gpu in _hardware) - gpu.Close(); - } } -} + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + return _report.ToString(); + } + + public void Close() + { + foreach (Hardware gpu in _hardware) + gpu.Close(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs index 2a58564..1f9532e 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/IntelIntegratedGpu.cs @@ -3,120 +3,119 @@ using System.Globalization; using System.Linq; using Microsoft.Win32; -namespace LibreHardwareMonitor.Hardware.Gpu +namespace LibreHardwareMonitor.Hardware.Gpu; + +internal class IntelIntegratedGpu : GenericGpu { - internal class IntelIntegratedGpu : GenericGpu + private const uint MSR_PP1_ENERGY_STATUS = 0x641; + private const uint MSR_RAPL_POWER_UNIT = 0x606; + + private readonly Sensor _dedicatedMemoryUsage; + private readonly string _deviceId; + private readonly float _energyUnitMultiplier; + private readonly Sensor[] _nodeUsage; + private readonly DateTime[] _nodeUsagePrevTick; + private readonly long[] _nodeUsagePrevValue; + private readonly Sensor _powerSensor; + private readonly Sensor _sharedMemoryUsage; + + private uint _lastEnergyConsumed; + private DateTime _lastEnergyTime; + + public IntelIntegratedGpu(CPU.IntelCpu intelCpu, string deviceId, D3DDisplayDevice.D3DDeviceInfo deviceInfo, ISettings settings) + : base(GetName(deviceId), + new Identifier("gpu-intel-integrated", deviceId.ToString(CultureInfo.InvariantCulture)), + settings) { - private const uint MSR_PP1_ENERGY_STATUS = 0x641; - private const uint MSR_RAPL_POWER_UNIT = 0x606; + _deviceId = deviceId; - private readonly Sensor _dedicatedMemoryUsage; - private readonly string _deviceId; - private readonly float _energyUnitMultiplier; - private readonly Sensor[] _nodeUsage; - private readonly DateTime[] _nodeUsagePrevTick; - private readonly long[] _nodeUsagePrevValue; - private readonly Sensor _powerSensor; - private readonly Sensor _sharedMemoryUsage; + int memorySensorIndex = 0; - private uint _lastEnergyConsumed; - private DateTime _lastEnergyTime; - - public IntelIntegratedGpu(CPU.IntelCpu intelCpu, string deviceId, D3DDisplayDevice.D3DDeviceInfo deviceInfo, ISettings settings) - : base(GetName(deviceId), - new Identifier("gpu-intel-integrated", deviceId.ToString(CultureInfo.InvariantCulture)), - settings) + if (deviceInfo.GpuDedicatedLimit > 0) { - _deviceId = deviceId; + _dedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); + } - int memorySensorIndex = 0; + _sharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); - if (deviceInfo.GpuDedicatedLimit > 0) + if (Ring0.ReadMsr(MSR_RAPL_POWER_UNIT, out uint eax, out uint _)) + { + _energyUnitMultiplier = intelCpu.EnergyUnitsMultiplier; + if (_energyUnitMultiplier != 0) { - _dedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); - } - - _sharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); - - if (Ring0.ReadMsr(MSR_RAPL_POWER_UNIT, out uint eax, out uint _)) - { - _energyUnitMultiplier = intelCpu.EnergyUnitsMultiplier; - if (_energyUnitMultiplier != 0) - { - _lastEnergyTime = DateTime.UtcNow; - _lastEnergyConsumed = eax; - _powerSensor = new Sensor("GPU Power", 0, SensorType.Power, this, settings); - ActivateSensor(_powerSensor); - } - } - - _nodeUsage = new Sensor[deviceInfo.Nodes.Length]; - _nodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; - _nodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; - - int nodeSensorIndex = 0; - foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes.OrderBy(x => x.Name)) - { - _nodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); - _nodeUsagePrevValue[node.Id] = node.RunningTime; - _nodeUsagePrevTick[node.Id] = node.QueryTime; + _lastEnergyTime = DateTime.UtcNow; + _lastEnergyConsumed = eax; + _powerSensor = new Sensor("GPU Power", 0, SensorType.Power, this, settings); + ActivateSensor(_powerSensor); } } - /// - public override string DeviceId => D3DDisplayDevice.GetActualDeviceIdentifier(_deviceId); + _nodeUsage = new Sensor[deviceInfo.Nodes.Length]; + _nodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; + _nodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; - public override HardwareType HardwareType => HardwareType.GpuIntel; - - public override void Update() + int nodeSensorIndex = 0; + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes.OrderBy(x => x.Name)) { - if (D3DDisplayDevice.GetDeviceInfoByIdentifier(_deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) - { - if (_dedicatedMemoryUsage != null) - { - _dedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; - ActivateSensor(_dedicatedMemoryUsage); - } - - _sharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; - ActivateSensor(_sharedMemoryUsage); - - if (_powerSensor != null && Ring0.ReadMsr(MSR_PP1_ENERGY_STATUS, out uint eax, out uint _)) - { - DateTime time = DateTime.UtcNow; - uint energyConsumed = eax; - float deltaTime = (float)(time - _lastEnergyTime).TotalSeconds; - if (deltaTime >= 0.01) - { - _powerSensor.Value = _energyUnitMultiplier * unchecked(energyConsumed - _lastEnergyConsumed) / deltaTime; - _lastEnergyTime = time; - _lastEnergyConsumed = energyConsumed; - } - } - - foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) - { - long runningTimeDiff = node.RunningTime - _nodeUsagePrevValue[node.Id]; - long timeDiff = node.QueryTime.Ticks - _nodeUsagePrevTick[node.Id].Ticks; - - _nodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; - _nodeUsagePrevValue[node.Id] = node.RunningTime; - _nodeUsagePrevTick[node.Id] = node.QueryTime; - ActivateSensor(_nodeUsage[node.Id]); - } - } - } - - private static string GetName(string deviceId) - { - string path = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" + D3DDisplayDevice.GetActualDeviceIdentifier(deviceId); - - if (Registry.GetValue(path, "DeviceDesc", null) is string deviceDesc) - { - return deviceDesc.Split(';').Last(); - } - - return "Intel Integrated Graphics"; + _nodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); + _nodeUsagePrevValue[node.Id] = node.RunningTime; + _nodeUsagePrevTick[node.Id] = node.QueryTime; } } -} + + /// + public override string DeviceId => D3DDisplayDevice.GetActualDeviceIdentifier(_deviceId); + + public override HardwareType HardwareType => HardwareType.GpuIntel; + + public override void Update() + { + if (D3DDisplayDevice.GetDeviceInfoByIdentifier(_deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + if (_dedicatedMemoryUsage != null) + { + _dedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; + ActivateSensor(_dedicatedMemoryUsage); + } + + _sharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; + ActivateSensor(_sharedMemoryUsage); + + if (_powerSensor != null && Ring0.ReadMsr(MSR_PP1_ENERGY_STATUS, out uint eax, out uint _)) + { + DateTime time = DateTime.UtcNow; + uint energyConsumed = eax; + float deltaTime = (float)(time - _lastEnergyTime).TotalSeconds; + if (deltaTime >= 0.01) + { + _powerSensor.Value = _energyUnitMultiplier * unchecked(energyConsumed - _lastEnergyConsumed) / deltaTime; + _lastEnergyTime = time; + _lastEnergyConsumed = energyConsumed; + } + } + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) + { + long runningTimeDiff = node.RunningTime - _nodeUsagePrevValue[node.Id]; + long timeDiff = node.QueryTime.Ticks - _nodeUsagePrevTick[node.Id].Ticks; + + _nodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; + _nodeUsagePrevValue[node.Id] = node.RunningTime; + _nodeUsagePrevTick[node.Id] = node.QueryTime; + ActivateSensor(_nodeUsage[node.Id]); + } + } + } + + private static string GetName(string deviceId) + { + string path = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" + D3DDisplayDevice.GetActualDeviceIdentifier(deviceId); + + if (Registry.GetValue(path, "DeviceDesc", null) is string deviceDesc) + { + return deviceDesc.Split(';').Last(); + } + + return "Intel Integrated Graphics"; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs index b8dd3db..f847d2d 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGpu.cs @@ -12,231 +12,258 @@ using System.Text; using LibreHardwareMonitor.Interop; using Microsoft.Win32; -namespace LibreHardwareMonitor.Hardware.Gpu +namespace LibreHardwareMonitor.Hardware.Gpu; + +internal sealed class NvidiaGpu : GenericGpu { - internal sealed class NvidiaGpu : GenericGpu + private readonly int _adapterIndex; + private readonly Sensor[] _clocks; + private readonly int _clockVersion; + private readonly Sensor[] _controls; + private readonly string _d3dDeviceId; + private readonly NvApi.NvDisplayHandle? _displayHandle; + private readonly Control[] _fanControls; + private readonly Sensor[] _fans; + private readonly Sensor _gpuDedicatedMemoryUsage; + private readonly Sensor[] _gpuNodeUsage; + private readonly DateTime[] _gpuNodeUsagePrevTick; + private readonly long[] _gpuNodeUsagePrevValue; + private readonly Sensor _gpuSharedMemoryUsage; + private readonly NvApi.NvPhysicalGpuHandle _handle; + private readonly Sensor _hotSpotTemperature; + private readonly Sensor[] _loads; + private readonly Sensor _memoryFree; + private readonly Sensor _memoryJunctionTemperature; + private readonly Sensor _memoryTotal; + private readonly Sensor _memoryUsed; + private readonly NvidiaML.NvmlDevice? _nvmlDevice; + private readonly Sensor _pcieThroughputRx; + private readonly Sensor _pcieThroughputTx; + private readonly Sensor[] _powers; + private readonly Sensor _powerUsage; + private readonly Sensor[] _temperatures; + private readonly uint _thermalSensorsMask; + + public NvidiaGpu(int adapterIndex, NvApi.NvPhysicalGpuHandle handle, NvApi.NvDisplayHandle? displayHandle, ISettings settings) + : base(GetName(handle), + new Identifier("gpu-nvidia", adapterIndex.ToString(CultureInfo.InvariantCulture)), + settings) { - private readonly int _adapterIndex; - private readonly Sensor[] _clocks; - private readonly int _clockVersion; - private readonly Sensor[] _controls; - private readonly string _d3dDeviceId; - private readonly NvApi.NvDisplayHandle? _displayHandle; - private readonly Control[] _fanControls; - private readonly Sensor[] _fans; - private readonly Sensor _gpuDedicatedMemoryUsage; - private readonly Sensor[] _gpuNodeUsage; - private readonly DateTime[] _gpuNodeUsagePrevTick; - private readonly long[] _gpuNodeUsagePrevValue; - private readonly Sensor _gpuSharedMemoryUsage; - private readonly NvApi.NvPhysicalGpuHandle _handle; - private readonly Sensor _hotSpotTemperature; - private readonly Sensor[] _loads; - private readonly Sensor _memoryFree; - private readonly Sensor _memoryJunctionTemperature; - private readonly Sensor _memoryTotal; - private readonly Sensor _memoryUsed; - private readonly NvidiaML.NvmlDevice? _nvmlDevice; - private readonly Sensor _pcieThroughputRx; - private readonly Sensor _pcieThroughputTx; - private readonly Sensor[] _powers; - private readonly Sensor _powerUsage; - private readonly Sensor[] _temperatures; - private readonly uint _thermalSensorsMask; + _adapterIndex = adapterIndex; + _handle = handle; + _displayHandle = displayHandle; - public NvidiaGpu(int adapterIndex, NvApi.NvPhysicalGpuHandle handle, NvApi.NvDisplayHandle? displayHandle, ISettings settings) - : base(GetName(handle), - new Identifier("gpu-nvidia", adapterIndex.ToString(CultureInfo.InvariantCulture)), - settings) + bool hasBusId = NvApi.NvAPI_GPU_GetBusId(handle, out uint busId) == NvApi.NvStatus.OK; + + // Thermal settings. + NvApi.NvThermalSettings thermalSettings = GetThermalSettings(out NvApi.NvStatus status); + if (status == NvApi.NvStatus.OK && thermalSettings.Count > 0) { - _adapterIndex = adapterIndex; - _handle = handle; - _displayHandle = displayHandle; + _temperatures = new Sensor[thermalSettings.Count]; - bool hasBusId = NvApi.NvAPI_GPU_GetBusId(handle, out uint busId) == NvApi.NvStatus.OK; - - // Thermal settings. - NvApi.NvThermalSettings thermalSettings = GetThermalSettings(out NvApi.NvStatus status); - if (status == NvApi.NvStatus.OK && thermalSettings.Count > 0) + for (int i = 0; i < thermalSettings.Count; i++) { - _temperatures = new Sensor[thermalSettings.Count]; + NvApi.NvSensor sensor = thermalSettings.Sensor[i]; - for (int i = 0; i < thermalSettings.Count; i++) + string name = sensor.Target switch { - NvApi.NvSensor sensor = thermalSettings.Sensor[i]; + NvApi.NvThermalTarget.Gpu => "GPU Core", + NvApi.NvThermalTarget.Memory => "GPU Memory", + NvApi.NvThermalTarget.PowerSupply => "GPU Power Supply", + NvApi.NvThermalTarget.Board => "GPU Board", + NvApi.NvThermalTarget.VisualComputingBoard => "GPU Visual Computing Board", + NvApi.NvThermalTarget.VisualComputingInlet => "GPU Visual Computing Inlet", + NvApi.NvThermalTarget.VisualComputingOutlet => "GPU Visual Computing Outlet", + _ => "GPU" + }; - string name = sensor.Target switch + _temperatures[i] = new Sensor(name, i, SensorType.Temperature, this, Array.Empty(), settings); + ActivateSensor(_temperatures[i]); + } + } + + // Thermal sensors. + _hotSpotTemperature = new Sensor("GPU Hot Spot", (int)thermalSettings.Count + 1, SensorType.Temperature, this, settings); + _memoryJunctionTemperature = new Sensor("GPU Memory Junction", (int)thermalSettings.Count + 2, SensorType.Temperature, this, settings); + bool hasAnyThermalSensor = false; + + for (int thermalSensorsMaxBit = 0; thermalSensorsMaxBit < 32; thermalSensorsMaxBit++) + { + // Find the maximum thermal sensor mask value. + _thermalSensorsMask = 1u << thermalSensorsMaxBit; + + GetThermalSensors(_thermalSensorsMask, out NvApi.NvStatus thermalSensorsStatus); + if (thermalSensorsStatus == NvApi.NvStatus.OK) + { + hasAnyThermalSensor = true; + continue; + } + + _thermalSensorsMask--; + break; + } + + if (!hasAnyThermalSensor) + { + _thermalSensorsMask = 0; + } + + // Clock frequencies. + for (int clockVersion = 1; clockVersion <= 3; clockVersion++) + { + _clockVersion = clockVersion; + + NvApi.NvGpuClockFrequencies clockFrequencies = GetClockFrequencies(out status); + if (status == NvApi.NvStatus.OK) + { + var clocks = new List(); + for (int i = 0; i < clockFrequencies.Clocks.Length; i++) + { + NvApi.NvGpuClockFrequenciesDomain clock = clockFrequencies.Clocks[i]; + if (clock.IsPresent && Enum.IsDefined(typeof(NvApi.NvGpuPublicClockId), i)) { - NvApi.NvThermalTarget.Gpu => "GPU Core", - NvApi.NvThermalTarget.Memory => "GPU Memory", - NvApi.NvThermalTarget.PowerSupply => "GPU Power Supply", - NvApi.NvThermalTarget.Board => "GPU Board", - NvApi.NvThermalTarget.VisualComputingBoard => "GPU Visual Computing Board", - NvApi.NvThermalTarget.VisualComputingInlet => "GPU Visual Computing Inlet", - NvApi.NvThermalTarget.VisualComputingOutlet => "GPU Visual Computing Outlet", - _ => "GPU" - }; - - _temperatures[i] = new Sensor(name, i, SensorType.Temperature, this, Array.Empty(), settings); - ActivateSensor(_temperatures[i]); - } - } - - // Thermal sensors. - _hotSpotTemperature = new Sensor("GPU Hot Spot", (int)thermalSettings.Count + 1, SensorType.Temperature, this, settings); - _memoryJunctionTemperature = new Sensor("GPU Memory Junction", (int)thermalSettings.Count + 2, SensorType.Temperature, this, settings); - bool hasAnyThermalSensor = false; - - for (int thermalSensorsMaxBit = 0; thermalSensorsMaxBit < 32; thermalSensorsMaxBit++) - { - // Find the maximum thermal sensor mask value. - _thermalSensorsMask = 1u << thermalSensorsMaxBit; - - GetThermalSensors(_thermalSensorsMask, out NvApi.NvStatus thermalSensorsStatus); - if (thermalSensorsStatus == NvApi.NvStatus.OK) - { - hasAnyThermalSensor = true; - continue; - } - - _thermalSensorsMask--; - break; - } - - if (!hasAnyThermalSensor) - { - _thermalSensorsMask = 0; - } - - // Clock frequencies. - for (int clockVersion = 1; clockVersion <= 3; clockVersion++) - { - _clockVersion = clockVersion; - - NvApi.NvGpuClockFrequencies clockFrequencies = GetClockFrequencies(out status); - if (status == NvApi.NvStatus.OK) - { - var clocks = new List(); - for (int i = 0; i < clockFrequencies.Clocks.Length; i++) - { - NvApi.NvGpuClockFrequenciesDomain clock = clockFrequencies.Clocks[i]; - if (clock.IsPresent && Enum.IsDefined(typeof(NvApi.NvGpuPublicClockId), i)) + var clockId = (NvApi.NvGpuPublicClockId)i; + string name = clockId switch { - var clockId = (NvApi.NvGpuPublicClockId)i; - string name = clockId switch - { - NvApi.NvGpuPublicClockId.Graphics => "GPU Core", - NvApi.NvGpuPublicClockId.Memory => "GPU Memory", - NvApi.NvGpuPublicClockId.Processor => "GPU Shader", - NvApi.NvGpuPublicClockId.Video => "GPU Video", - _ => null - }; + NvApi.NvGpuPublicClockId.Graphics => "GPU Core", + NvApi.NvGpuPublicClockId.Memory => "GPU Memory", + NvApi.NvGpuPublicClockId.Processor => "GPU Shader", + NvApi.NvGpuPublicClockId.Video => "GPU Video", + _ => null + }; - if (name != null) - clocks.Add(new Sensor(name, i, SensorType.Clock, this, settings)); - } - } - - if (clocks.Count > 0) - { - _clocks = clocks.ToArray(); - - foreach (Sensor sensor in clocks) - ActivateSensor(sensor); - - break; + if (name != null) + clocks.Add(new Sensor(name, i, SensorType.Clock, this, settings)); } } - } - // Fans + controllers. - NvApi.NvFanCoolersStatus fanCoolers = GetFanCoolersStatus(out status); - if (status == NvApi.NvStatus.OK && fanCoolers.Count > 0) - { - _fans = new Sensor[fanCoolers.Count]; - - for (int i = 0; i < fanCoolers.Count; i++) + if (clocks.Count > 0) { - NvApi.NvFanCoolersStatusItem item = fanCoolers.Items[i]; + _clocks = clocks.ToArray(); - string name = "GPU Fan" + (fanCoolers.Count > 1 ? " " + (i + 1) : string.Empty); + foreach (Sensor sensor in clocks) + ActivateSensor(sensor); - _fans[i] = new Sensor(name, (int)item.CoolerId, SensorType.Fan, this, settings); - ActivateSensor(_fans[i]); + break; } } - else + } + + // Fans + controllers. + NvApi.NvFanCoolersStatus fanCoolers = GetFanCoolersStatus(out status); + if (status == NvApi.NvStatus.OK && fanCoolers.Count > 0) + { + _fans = new Sensor[fanCoolers.Count]; + + for (int i = 0; i < fanCoolers.Count; i++) { - GetTachReading(out status); - if (status == NvApi.NvStatus.OK) + NvApi.NvFanCoolersStatusItem item = fanCoolers.Items[i]; + + string name = "GPU Fan" + (fanCoolers.Count > 1 ? " " + (i + 1) : string.Empty); + + _fans[i] = new Sensor(name, (int)item.CoolerId, SensorType.Fan, this, settings); + ActivateSensor(_fans[i]); + } + } + else + { + GetTachReading(out status); + if (status == NvApi.NvStatus.OK) + { + _fans = new[] { new Sensor("GPU", 1, SensorType.Fan, this, settings) }; + ActivateSensor(_fans[0]); + } + } + + NvApi.NvFanCoolerControl fanControllers = GetFanCoolersControllers(out status); + if (status == NvApi.NvStatus.OK && fanControllers.Count > 0 && fanCoolers.Count > 0) + { + _controls = new Sensor[fanControllers.Count]; + _fanControls = new Control[fanControllers.Count]; + + for (int i = 0; i < fanControllers.Count; i++) + { + NvApi.NvFanCoolerControlItem item = fanControllers.Items[i]; + + string name = "GPU Fan" + (fanControllers.Count > 1 ? " " + (i + 1) : string.Empty); + + NvApi.NvFanCoolersStatusItem fanItem = Array.Find(fanCoolers.Items, x => x.CoolerId == item.CoolerId); + if (!fanItem.Equals(default(NvApi.NvFanCoolersStatusItem))) { - _fans = new[] { new Sensor("GPU", 1, SensorType.Fan, this, settings) }; - ActivateSensor(_fans[0]); + _controls[i] = new Sensor(name, (int)item.CoolerId, SensorType.Control, this, settings); + ActivateSensor(_controls[i]); + + _fanControls[i] = new Control(_controls[i], settings, fanItem.CurrentMinLevel, fanItem.CurrentMaxLevel); + _fanControls[i].ControlModeChanged += ControlModeChanged; + _fanControls[i].SoftwareControlValueChanged += SoftwareControlValueChanged; + _controls[i].Control = _fanControls[i]; + + ControlModeChanged(_fanControls[i]); + } + } + } + else + { + NvApi.NvCoolerSettings coolerSettings = GetCoolerSettings(out status); + if (status == NvApi.NvStatus.OK && coolerSettings.Count > 0) + { + _controls = new Sensor[coolerSettings.Count]; + _fanControls = new Control[coolerSettings.Count]; + + for (int i = 0; i < coolerSettings.Count; i++) + { + NvApi.NvCooler cooler = coolerSettings.Cooler[i]; + string name = "GPU Fan" + (coolerSettings.Count > 1 ? " " + cooler.Controller : string.Empty); + + _controls[i] = new Sensor(name, i, SensorType.Control, this, settings); + ActivateSensor(_controls[i]); + + _fanControls[i] = new Control(_controls[i], settings, cooler.DefaultMin, cooler.DefaultMax); + _fanControls[i].ControlModeChanged += ControlModeChanged; + _fanControls[i].SoftwareControlValueChanged += SoftwareControlValueChanged; + _controls[i].Control = _fanControls[i]; + + ControlModeChanged(_fanControls[i]); + } + } + } + + // Load usages. + NvApi.NvDynamicPStatesInfo pStatesInfo = GetDynamicPstatesInfoEx(out status); + if (status == NvApi.NvStatus.OK) + { + var loads = new List(); + for (int index = 0; index < pStatesInfo.Utilizations.Length; index++) + { + NvApi.NvDynamicPState load = pStatesInfo.Utilizations[index]; + if (load.IsPresent && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) + { + var utilizationDomain = (NvApi.NvUtilizationDomain)index; + string name = GetUtilizationDomainName(utilizationDomain); + + if (name != null) + loads.Add(new Sensor(name, index, SensorType.Load, this, settings)); } } - NvApi.NvFanCoolerControl fanControllers = GetFanCoolersControllers(out status); - if (status == NvApi.NvStatus.OK && fanControllers.Count > 0 && fanCoolers.Count > 0) + if (loads.Count > 0) { - _controls = new Sensor[fanControllers.Count]; - _fanControls = new Control[fanControllers.Count]; + _loads = loads.ToArray(); - for (int i = 0; i < fanControllers.Count; i++) - { - NvApi.NvFanCoolerControlItem item = fanControllers.Items[i]; - - string name = "GPU Fan" + (fanControllers.Count > 1 ? " " + (i + 1) : string.Empty); - - NvApi.NvFanCoolersStatusItem fanItem = Array.Find(fanCoolers.Items, x => x.CoolerId == item.CoolerId); - if (!fanItem.Equals(default(NvApi.NvFanCoolersStatusItem))) - { - _controls[i] = new Sensor(name, (int)item.CoolerId, SensorType.Control, this, settings); - ActivateSensor(_controls[i]); - - _fanControls[i] = new Control(_controls[i], settings, fanItem.CurrentMinLevel, fanItem.CurrentMaxLevel); - _fanControls[i].ControlModeChanged += ControlModeChanged; - _fanControls[i].SoftwareControlValueChanged += SoftwareControlValueChanged; - _controls[i].Control = _fanControls[i]; - - ControlModeChanged(_fanControls[i]); - } - } + foreach (Sensor sensor in loads) + ActivateSensor(sensor); } - else - { - NvApi.NvCoolerSettings coolerSettings = GetCoolerSettings(out status); - if (status == NvApi.NvStatus.OK && coolerSettings.Count > 0) - { - _controls = new Sensor[coolerSettings.Count]; - _fanControls = new Control[coolerSettings.Count]; - - for (int i = 0; i < coolerSettings.Count; i++) - { - NvApi.NvCooler cooler = coolerSettings.Cooler[i]; - string name = "GPU Fan" + (coolerSettings.Count > 1 ? " " + cooler.Controller : string.Empty); - - _controls[i] = new Sensor(name, i, SensorType.Control, this, settings); - ActivateSensor(_controls[i]); - - _fanControls[i] = new Control(_controls[i], settings, cooler.DefaultMin, cooler.DefaultMax); - _fanControls[i].ControlModeChanged += ControlModeChanged; - _fanControls[i].SoftwareControlValueChanged += SoftwareControlValueChanged; - _controls[i].Control = _fanControls[i]; - - ControlModeChanged(_fanControls[i]); - } - } - } - - // Load usages. - NvApi.NvDynamicPStatesInfo pStatesInfo = GetDynamicPstatesInfoEx(out status); + } + else + { + NvApi.NvUsages usages = GetUsages(out status); if (status == NvApi.NvStatus.OK) { var loads = new List(); - for (int index = 0; index < pStatesInfo.Utilizations.Length; index++) + for (int index = 0; index < usages.Entries.Length; index++) { - NvApi.NvDynamicPState load = pStatesInfo.Utilizations[index]; - if (load.IsPresent && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) + NvApi.NvUsagesEntry load = usages.Entries[index]; + if (load.IsPresent > 0 && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) { var utilizationDomain = (NvApi.NvUtilizationDomain)index; string name = GetUtilizationDomainName(utilizationDomain); @@ -254,99 +281,104 @@ namespace LibreHardwareMonitor.Hardware.Gpu ActivateSensor(sensor); } } + } + + // Power. + NvApi.NvPowerTopology powerTopology = GetPowerTopology(out NvApi.NvStatus powerStatus); + if (powerStatus == NvApi.NvStatus.OK && powerTopology.Count > 0) + { + _powers = new Sensor[powerTopology.Count]; + for (int i = 0; i < powerTopology.Count; i++) + { + NvApi.NvPowerTopologyEntry entry = powerTopology.Entries[i]; + string name = entry.Domain switch + { + NvApi.NvPowerTopologyDomain.Gpu => "GPU Power", + NvApi.NvPowerTopologyDomain.Board => "GPU Board Power", + _ => null + }; + + if (name != null) + { + _powers[i] = new Sensor(name, i + (_loads?.Length ?? 0), SensorType.Load, this, settings); + ActivateSensor(_powers[i]); + } + } + } + + if (NvidiaML.IsAvailable || NvidiaML.Initialize()) + { + if (hasBusId) + _nvmlDevice = NvidiaML.NvmlDeviceGetHandleByPciBusId($" 0000:{busId:X2}:00.0") ?? NvidiaML.NvmlDeviceGetHandleByIndex(_adapterIndex); else + _nvmlDevice = NvidiaML.NvmlDeviceGetHandleByIndex(_adapterIndex); + + if (_nvmlDevice.HasValue) { - NvApi.NvUsages usages = GetUsages(out status); - if (status == NvApi.NvStatus.OK) + _powerUsage = new Sensor("GPU Package", 0, SensorType.Power, this, settings); + + _pcieThroughputRx = new Sensor("GPU PCIe Rx", 0, SensorType.Throughput, this, settings); + _pcieThroughputTx = new Sensor("GPU PCIe Tx", 1, SensorType.Throughput, this, settings); + + if (!Software.OperatingSystem.IsUnix) { - var loads = new List(); - for (int index = 0; index < usages.Entries.Length; index++) + NvidiaML.NvmlPciInfo? pciInfo = NvidiaML.NvmlDeviceGetPciInfo(_nvmlDevice.Value); + + if (pciInfo is { } pci) { - NvApi.NvUsagesEntry load = usages.Entries[index]; - if (load.IsPresent > 0 && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) + string[] deviceIds = D3DDisplayDevice.GetDeviceIdentifiers(); + if (deviceIds != null) { - var utilizationDomain = (NvApi.NvUtilizationDomain)index; - string name = GetUtilizationDomainName(utilizationDomain); - - if (name != null) - loads.Add(new Sensor(name, index, SensorType.Load, this, settings)); - } - } - - if (loads.Count > 0) - { - _loads = loads.ToArray(); - - foreach (Sensor sensor in loads) - ActivateSensor(sensor); - } - } - } - - // Power. - NvApi.NvPowerTopology powerTopology = GetPowerTopology(out NvApi.NvStatus powerStatus); - if (powerStatus == NvApi.NvStatus.OK && powerTopology.Count > 0) - { - _powers = new Sensor[powerTopology.Count]; - for (int i = 0; i < powerTopology.Count; i++) - { - NvApi.NvPowerTopologyEntry entry = powerTopology.Entries[i]; - string name = entry.Domain switch - { - NvApi.NvPowerTopologyDomain.Gpu => "GPU Power", - NvApi.NvPowerTopologyDomain.Board => "GPU Board Power", - _ => null - }; - - if (name != null) - { - _powers[i] = new Sensor(name, i + (_loads?.Length ?? 0), SensorType.Load, this, settings); - ActivateSensor(_powers[i]); - } - } - } - - if (NvidiaML.IsAvailable || NvidiaML.Initialize()) - { - if (hasBusId) - _nvmlDevice = NvidiaML.NvmlDeviceGetHandleByPciBusId($" 0000:{busId:X2}:00.0") ?? NvidiaML.NvmlDeviceGetHandleByIndex(_adapterIndex); - else - _nvmlDevice = NvidiaML.NvmlDeviceGetHandleByIndex(_adapterIndex); - - if (_nvmlDevice.HasValue) - { - _powerUsage = new Sensor("GPU Package", 0, SensorType.Power, this, settings); - - _pcieThroughputRx = new Sensor("GPU PCIe Rx", 0, SensorType.Throughput, this, settings); - _pcieThroughputTx = new Sensor("GPU PCIe Tx", 1, SensorType.Throughput, this, settings); - - if (!Software.OperatingSystem.IsUnix) - { - NvidiaML.NvmlPciInfo? pciInfo = NvidiaML.NvmlDeviceGetPciInfo(_nvmlDevice.Value); - - if (pciInfo is { } pci) - { - string[] deviceIds = D3DDisplayDevice.GetDeviceIdentifiers(); - if (deviceIds != null) + foreach (string deviceId in deviceIds) { - foreach (string deviceId in deviceIds) + if (deviceId.IndexOf("VEN_" + pci.pciVendorId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1 && + deviceId.IndexOf("DEV_" + pci.pciDeviceId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1 && + deviceId.IndexOf("SUBSYS_" + pci.pciSubSystemId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1) { - if (deviceId.IndexOf("VEN_" + pci.pciVendorId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1 && - deviceId.IndexOf("DEV_" + pci.pciDeviceId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1 && - deviceId.IndexOf("SUBSYS_" + pci.pciSubSystemId.ToString("X"), StringComparison.OrdinalIgnoreCase) != -1) + bool isMatch = false; + + string actualDeviceId = D3DDisplayDevice.GetActualDeviceIdentifier(deviceId); + + try { - bool isMatch = false; - - string actualDeviceId = D3DDisplayDevice.GetActualDeviceIdentifier(deviceId); + if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nvlddmkm\Enum", adapterIndex.ToString(), null) is string adapterPnpId) + { + if (actualDeviceId.IndexOf(adapterPnpId, StringComparison.OrdinalIgnoreCase) != -1 || + adapterPnpId.IndexOf(actualDeviceId, StringComparison.OrdinalIgnoreCase) != -1) + { + isMatch = true; + } + } + } + catch + { + // Ignored. + } + if (!isMatch) + { try { - if (Registry.GetValue(@"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\nvlddmkm\Enum", adapterIndex.ToString(), null) is string adapterPnpId) + string path = actualDeviceId; + path = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" + path; + + if (Registry.GetValue(path, "LocationInformation", null) is string locationInformation) { - if (actualDeviceId.IndexOf(adapterPnpId, StringComparison.OrdinalIgnoreCase) != -1 || - adapterPnpId.IndexOf(actualDeviceId, StringComparison.OrdinalIgnoreCase) != -1) + // For example: + // @System32\drivers\pci.sys,#65536;PCI bus %1, device %2, function %3;(38,0,0) + + int index = locationInformation.IndexOf('('); + if (index != -1) { - isMatch = true; + index++; + int secondIndex = locationInformation.IndexOf(',', index); + if (secondIndex != -1) + { + string bus = locationInformation.Substring(index, secondIndex - index); + + if (pci.bus.ToString() == bus) + isMatch = true; + } } } } @@ -354,60 +386,27 @@ namespace LibreHardwareMonitor.Hardware.Gpu { // Ignored. } + } - if (!isMatch) + if (isMatch && D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + int nodeSensorIndex = (_loads?.Length ?? 0) + (_powers?.Length ?? 0); + int memorySensorIndex = 3; // There are three normal GPU memory sensors. + + _d3dDeviceId = deviceId; + + _gpuDedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); + _gpuSharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex, SensorType.SmallData, this, settings); + + _gpuNodeUsage = new Sensor[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; + _gpuNodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes.OrderBy(x => x.Name)) { - try - { - string path = actualDeviceId; - path = @"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\" + path; - - if (Registry.GetValue(path, "LocationInformation", null) is string locationInformation) - { - // For example: - // @System32\drivers\pci.sys,#65536;PCI bus %1, device %2, function %3;(38,0,0) - - int index = locationInformation.IndexOf('('); - if (index != -1) - { - index++; - int secondIndex = locationInformation.IndexOf(',', index); - if (secondIndex != -1) - { - string bus = locationInformation.Substring(index, secondIndex - index); - - if (pci.bus.ToString() == bus) - isMatch = true; - } - } - } - } - catch - { - // Ignored. - } - } - - if (isMatch && D3DDisplayDevice.GetDeviceInfoByIdentifier(deviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) - { - int nodeSensorIndex = (_loads?.Length ?? 0) + (_powers?.Length ?? 0); - int memorySensorIndex = 3; // There are three normal GPU memory sensors. - - _d3dDeviceId = deviceId; - - _gpuDedicatedMemoryUsage = new Sensor("D3D Dedicated Memory Used", memorySensorIndex++, SensorType.SmallData, this, settings); - _gpuSharedMemoryUsage = new Sensor("D3D Shared Memory Used", memorySensorIndex, SensorType.SmallData, this, settings); - - _gpuNodeUsage = new Sensor[deviceInfo.Nodes.Length]; - _gpuNodeUsagePrevValue = new long[deviceInfo.Nodes.Length]; - _gpuNodeUsagePrevTick = new DateTime[deviceInfo.Nodes.Length]; - - foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes.OrderBy(x => x.Name)) - { - _gpuNodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); - _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; - _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; - } + _gpuNodeUsage[node.Id] = new Sensor(node.Name, nodeSensorIndex++, SensorType.Load, this, settings); + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; } } } @@ -416,811 +415,811 @@ namespace LibreHardwareMonitor.Hardware.Gpu } } } - - _memoryFree = new Sensor("GPU Memory Free", 0, SensorType.SmallData, this, settings); - _memoryUsed = new Sensor("GPU Memory Used", 1, SensorType.SmallData, this, settings); - _memoryTotal = new Sensor("GPU Memory Total", 2, SensorType.SmallData, this, settings); - - Update(); } - /// - public override string DeviceId + _memoryFree = new Sensor("GPU Memory Free", 0, SensorType.SmallData, this, settings); + _memoryUsed = new Sensor("GPU Memory Used", 1, SensorType.SmallData, this, settings); + _memoryTotal = new Sensor("GPU Memory Total", 2, SensorType.SmallData, this, settings); + + Update(); + } + + /// + public override string DeviceId + { + get { - get + return _d3dDeviceId != null ? D3DDisplayDevice.GetActualDeviceIdentifier(_d3dDeviceId) : null; + } + } + + public override HardwareType HardwareType + { + get { return HardwareType.GpuNvidia; } + } + + public override void Update() + { + if (_d3dDeviceId != null && D3DDisplayDevice.GetDeviceInfoByIdentifier(_d3dDeviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + { + _gpuDedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; + _gpuSharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; + ActivateSensor(_gpuDedicatedMemoryUsage); + ActivateSensor(_gpuSharedMemoryUsage); + + foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) { - return _d3dDeviceId != null ? D3DDisplayDevice.GetActualDeviceIdentifier(_d3dDeviceId) : null; + long runningTimeDiff = node.RunningTime - _gpuNodeUsagePrevValue[node.Id]; + long timeDiff = node.QueryTime.Ticks - _gpuNodeUsagePrevTick[node.Id].Ticks; + + _gpuNodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; + _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; + _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; + ActivateSensor(_gpuNodeUsage[node.Id]); } } - public override HardwareType HardwareType + NvApi.NvStatus status; + + if (_temperatures is { Length: > 0 }) { - get { return HardwareType.GpuNvidia; } + NvApi.NvThermalSettings settings = GetThermalSettings(out status); + // settings.Count is 0 when no valid data available, this happens when you try to read out this value with a high polling interval. + if (status == NvApi.NvStatus.OK && settings.Count > 0) + { + foreach (Sensor sensor in _temperatures) + sensor.Value = settings.Sensor[sensor.Index].CurrentTemp; + } } - public override void Update() + if (_thermalSensorsMask > 0) { - if (_d3dDeviceId != null && D3DDisplayDevice.GetDeviceInfoByIdentifier(_d3dDeviceId, out D3DDisplayDevice.D3DDeviceInfo deviceInfo)) + NvApi.NvThermalSensors thermalSensors = GetThermalSensors(_thermalSensorsMask, out status); + + if (status == NvApi.NvStatus.OK) { - _gpuDedicatedMemoryUsage.Value = 1f * deviceInfo.GpuDedicatedUsed / 1024 / 1024; - _gpuSharedMemoryUsage.Value = 1f * deviceInfo.GpuSharedUsed / 1024 / 1024; - ActivateSensor(_gpuDedicatedMemoryUsage); - ActivateSensor(_gpuSharedMemoryUsage); - - foreach (D3DDisplayDevice.D3DDeviceNodeInfo node in deviceInfo.Nodes) - { - long runningTimeDiff = node.RunningTime - _gpuNodeUsagePrevValue[node.Id]; - long timeDiff = node.QueryTime.Ticks - _gpuNodeUsagePrevTick[node.Id].Ticks; - - _gpuNodeUsage[node.Id].Value = 100f * runningTimeDiff / timeDiff; - _gpuNodeUsagePrevValue[node.Id] = node.RunningTime; - _gpuNodeUsagePrevTick[node.Id] = node.QueryTime; - ActivateSensor(_gpuNodeUsage[node.Id]); - } + _hotSpotTemperature.Value = thermalSensors.Temperatures[1] / 256.0f; + _memoryJunctionTemperature.Value = thermalSensors.Temperatures[9] / 256.0f; } - NvApi.NvStatus status; + if (_hotSpotTemperature.Value != 0) + ActivateSensor(_hotSpotTemperature); - if (_temperatures is { Length: > 0 }) + if (_memoryJunctionTemperature.Value != 0) + ActivateSensor(_memoryJunctionTemperature); + } + else + { + _hotSpotTemperature.Value = null; + _memoryJunctionTemperature.Value = null; + } + + if (_clocks is { Length: > 0 }) + { + NvApi.NvGpuClockFrequencies clockFrequencies = GetClockFrequencies(out status); + if (status == NvApi.NvStatus.OK) { - NvApi.NvThermalSettings settings = GetThermalSettings(out status); - // settings.Count is 0 when no valid data available, this happens when you try to read out this value with a high polling interval. - if (status == NvApi.NvStatus.OK && settings.Count > 0) + int current = 0; + for (int i = 0; i < clockFrequencies.Clocks.Length; i++) { - foreach (Sensor sensor in _temperatures) - sensor.Value = settings.Sensor[sensor.Index].CurrentTemp; + NvApi.NvGpuClockFrequenciesDomain clock = clockFrequencies.Clocks[i]; + if (clock.IsPresent && Enum.IsDefined(typeof(NvApi.NvGpuPublicClockId), i)) + _clocks[current++].Value = clock.Frequency / 1000f; } } + } - if (_thermalSensorsMask > 0) + if (_fans is { Length: > 0 }) + { + NvApi.NvFanCoolersStatus fanCoolers = GetFanCoolersStatus(out status); + if (status == NvApi.NvStatus.OK && fanCoolers.Count > 0) { - NvApi.NvThermalSensors thermalSensors = GetThermalSensors(_thermalSensorsMask, out status); - - if (status == NvApi.NvStatus.OK) + for (int i = 0; i < fanCoolers.Count; i++) { - _hotSpotTemperature.Value = thermalSensors.Temperatures[1] / 256.0f; - _memoryJunctionTemperature.Value = thermalSensors.Temperatures[9] / 256.0f; + NvApi.NvFanCoolersStatusItem item = fanCoolers.Items[i]; + _fans[i].Value = item.CurrentRpm; } - - if (_hotSpotTemperature.Value != 0) - ActivateSensor(_hotSpotTemperature); - - if (_memoryJunctionTemperature.Value != 0) - ActivateSensor(_memoryJunctionTemperature); } else { - _hotSpotTemperature.Value = null; - _memoryJunctionTemperature.Value = null; - } - - if (_clocks is { Length: > 0 }) - { - NvApi.NvGpuClockFrequencies clockFrequencies = GetClockFrequencies(out status); + int tachReading = GetTachReading(out status); if (status == NvApi.NvStatus.OK) - { - int current = 0; - for (int i = 0; i < clockFrequencies.Clocks.Length; i++) - { - NvApi.NvGpuClockFrequenciesDomain clock = clockFrequencies.Clocks[i]; - if (clock.IsPresent && Enum.IsDefined(typeof(NvApi.NvGpuPublicClockId), i)) - _clocks[current++].Value = clock.Frequency / 1000f; - } - } - } - - if (_fans is { Length: > 0 }) - { - NvApi.NvFanCoolersStatus fanCoolers = GetFanCoolersStatus(out status); - if (status == NvApi.NvStatus.OK && fanCoolers.Count > 0) - { - for (int i = 0; i < fanCoolers.Count; i++) - { - NvApi.NvFanCoolersStatusItem item = fanCoolers.Items[i]; - _fans[i].Value = item.CurrentRpm; - } - } - else - { - int tachReading = GetTachReading(out status); - if (status == NvApi.NvStatus.OK) - _fans[0].Value = tachReading; - } - } - - if (_controls is { Length: > 0 }) - { - NvApi.NvFanCoolersStatus fanCoolers = GetFanCoolersStatus(out status); - if (status == NvApi.NvStatus.OK && fanCoolers.Count > 0 && fanCoolers.Count == _controls.Length) - { - for (int i = 0; i < fanCoolers.Count; i++) - { - NvApi.NvFanCoolersStatusItem item = fanCoolers.Items[i]; - - if (Array.Find(_controls, c => c.Index == item.CoolerId) is { } control) - control.Value = item.CurrentLevel; - } - } - else - { - NvApi.NvCoolerSettings coolerSettings = GetCoolerSettings(out status); - if (status == NvApi.NvStatus.OK && coolerSettings.Count > 0) - { - for (int i = 0; i < coolerSettings.Count; i++) - { - NvApi.NvCooler cooler = coolerSettings.Cooler[i]; - _controls[i].Value = cooler.CurrentLevel; - } - } - } - } - - if (_loads is { Length: > 0 }) - { - NvApi.NvDynamicPStatesInfo pStatesInfo = GetDynamicPstatesInfoEx(out status); - if (status == NvApi.NvStatus.OK) - { - for (int index = 0; index < pStatesInfo.Utilizations.Length; index++) - { - NvApi.NvDynamicPState load = pStatesInfo.Utilizations[index]; - if (load.IsPresent && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) - _loads[index].Value = load.Percentage; - } - } - else - { - NvApi.NvUsages usages = GetUsages(out status); - if (status == NvApi.NvStatus.OK) - { - for (int index = 0; index < usages.Entries.Length; index++) - { - NvApi.NvUsagesEntry load = usages.Entries[index]; - if (load.IsPresent > 0 && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) - _loads[index].Value = load.Percentage; - } - } - } - } - - if (_powers is { Length: > 0 }) - { - NvApi.NvPowerTopology powerTopology = GetPowerTopology(out status); - if (status == NvApi.NvStatus.OK && powerTopology.Count > 0) - { - for (int i = 0; i < powerTopology.Count; i++) - { - NvApi.NvPowerTopologyEntry entry = powerTopology.Entries[i]; - _powers[i].Value = entry.PowerUsage / 1000f; - } - } - } - - if (_displayHandle != null) - { - NvApi.NvMemoryInfo memoryInfo = GetMemoryInfo(out status); - if (status == NvApi.NvStatus.OK) - { - uint free = memoryInfo.CurrentAvailableDedicatedVideoMemory; - uint total = memoryInfo.DedicatedVideoMemory; - - _memoryTotal.Value = total / 1024; - ActivateSensor(_memoryTotal); - - _memoryFree.Value = free / 1024; - ActivateSensor(_memoryFree); - - _memoryUsed.Value = (total - free) / 1024; - ActivateSensor(_memoryUsed); - } - } - - if (NvidiaML.IsAvailable && _nvmlDevice.HasValue) - { - int? result = NvidiaML.NvmlDeviceGetPowerUsage(_nvmlDevice.Value); - if (result.HasValue) - { - _powerUsage.Value = result.Value / 1000f; - ActivateSensor(_powerUsage); - } - - // In MB/s, throughput sensors are passed as in KB/s. - uint? rx = NvidiaML.NvmlDeviceGetPcieThroughput(_nvmlDevice.Value, NvidiaML.NvmlPcieUtilCounter.RxBytes); - if (rx.HasValue) - { - _pcieThroughputRx.Value = rx * 1024; - ActivateSensor(_pcieThroughputRx); - } - - uint? tx = NvidiaML.NvmlDeviceGetPcieThroughput(_nvmlDevice.Value, NvidiaML.NvmlPcieUtilCounter.TxBytes); - if (tx.HasValue) - { - _pcieThroughputTx.Value = tx * 1024; - ActivateSensor(_pcieThroughputTx); - } + _fans[0].Value = tachReading; } } - public override string GetReport() + if (_controls is { Length: > 0 }) { - StringBuilder r = new(); - - r.AppendLine("Nvidia GPU"); - r.AppendLine(); - r.AppendFormat("Name: {0}{1}", _name, Environment.NewLine); - r.AppendFormat("Index: {0}{1}", _adapterIndex, Environment.NewLine); - - if (_displayHandle.HasValue && NvApi.NvAPI_GetDisplayDriverVersion != null) + NvApi.NvFanCoolersStatus fanCoolers = GetFanCoolersStatus(out status); + if (status == NvApi.NvStatus.OK && fanCoolers.Count > 0 && fanCoolers.Count == _controls.Length) { - NvApi.NvDisplayDriverVersion driverVersion = new() { Version = (uint)NvApi.MAKE_NVAPI_VERSION(1) }; - if (NvApi.NvAPI_GetDisplayDriverVersion(_displayHandle.Value, ref driverVersion) == NvApi.NvStatus.OK) + for (int i = 0; i < fanCoolers.Count; i++) { - r.Append("Driver Version: "); - r.Append(driverVersion.DriverVersion / 100); - r.Append("."); - r.Append((driverVersion.DriverVersion % 100).ToString("00", CultureInfo.InvariantCulture)); - r.AppendLine(); - r.Append("Driver Branch: "); - r.AppendLine(driverVersion.BuildBranch); + NvApi.NvFanCoolersStatusItem item = fanCoolers.Items[i]; + + if (Array.Find(_controls, c => c.Index == item.CoolerId) is { } control) + control.Value = item.CurrentLevel; } } - - if (NvApi.NvAPI_GPU_GetPCIIdentifiers != null) + else { - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetPCIIdentifiers(_handle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); - if (status == NvApi.NvStatus.OK) - { - r.Append("DeviceID: 0x"); - r.AppendLine(deviceId.ToString("X", CultureInfo.InvariantCulture)); - r.Append("SubSystemID: 0x"); - r.AppendLine(subSystemId.ToString("X", CultureInfo.InvariantCulture)); - r.Append("RevisionID: 0x"); - r.AppendLine(revisionId.ToString("X", CultureInfo.InvariantCulture)); - r.Append("ExtDeviceID: 0x"); - r.AppendLine(extDeviceId.ToString("X", CultureInfo.InvariantCulture)); - r.AppendLine(); - } - } - - if (NvApi.NvAPI_GPU_GetThermalSettings != null) - { - NvApi.NvThermalSettings thermalSettings = GetThermalSettings(out NvApi.NvStatus status); - - r.AppendLine("Thermal Settings"); - r.AppendLine(); - - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < thermalSettings.Count; i++) - { - r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i, thermalSettings.Sensor[i].Controller, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i, thermalSettings.Sensor[i].DefaultMinTemp, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i, thermalSettings.Sensor[i].DefaultMaxTemp, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i, thermalSettings.Sensor[i].CurrentTemp, Environment.NewLine); - r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i, thermalSettings.Sensor[i].Target, Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetAllClocks != null) - { - NvApi.NvGpuClockFrequencies clocks = GetClockFrequencies(out NvApi.NvStatus status); - - r.AppendLine("Clocks"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < clocks.Clocks.Length; i++) - { - if (clocks.Clocks[i].IsPresent) - r.AppendFormat(" Clock[{0}]: {1}{2}", i, clocks.Clocks[i].Frequency, Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetTachReading != null) - { - NvApi.NvStatus status = NvApi.NvAPI_GPU_GetTachReading(_handle, out int tachValue); - - r.AppendLine("Tachometer"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine); - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx != null) - { - NvApi.NvDynamicPStatesInfo pStatesInfo = GetDynamicPstatesInfoEx(out NvApi.NvStatus status); - - r.AppendLine("P-States"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < pStatesInfo.Utilizations.Length; i++) - { - if (pStatesInfo.Utilizations[i].IsPresent) - r.AppendFormat(" Percentage[{0}]: {1}{2}", i, pStatesInfo.Utilizations[i].Percentage, Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetUsages != null) - { - NvApi.NvUsages usages = GetUsages(out NvApi.NvStatus status); - - r.AppendLine("Usages"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < usages.Entries.Length; i++) - { - if (usages.Entries[i].IsPresent > 0) - r.AppendFormat(" Usage[{0}]: {1}{2}", i, usages.Entries[i].Percentage, Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetCoolerSettings != null) - { - NvApi.NvCoolerSettings coolerSettings = GetCoolerSettings(out NvApi.NvStatus status); - r.AppendLine("Cooler Settings"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) + NvApi.NvCoolerSettings coolerSettings = GetCoolerSettings(out status); + if (status == NvApi.NvStatus.OK && coolerSettings.Count > 0) { for (int i = 0; i < coolerSettings.Count; i++) { - r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i, coolerSettings.Cooler[i].Type, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i, coolerSettings.Cooler[i].Controller, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i, coolerSettings.Cooler[i].DefaultMin, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i, coolerSettings.Cooler[i].DefaultMax, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i, coolerSettings.Cooler[i].CurrentMin, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i, coolerSettings.Cooler[i].CurrentMax, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i, coolerSettings.Cooler[i].CurrentLevel, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i, coolerSettings.Cooler[i].DefaultPolicy, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i, coolerSettings.Cooler[i].CurrentPolicy, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i, coolerSettings.Cooler[i].Target, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i, coolerSettings.Cooler[i].ControlType, Environment.NewLine); - r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i, coolerSettings.Cooler[i].Active, Environment.NewLine); + NvApi.NvCooler cooler = coolerSettings.Cooler[i]; + _controls[i].Value = cooler.CurrentLevel; } } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); } + } - if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null) + if (_loads is { Length: > 0 }) + { + NvApi.NvDynamicPStatesInfo pStatesInfo = GetDynamicPstatesInfoEx(out status); + if (status == NvApi.NvStatus.OK) { - NvApi.NvFanCoolersStatus coolers = GetFanCoolersStatus(out NvApi.NvStatus status); - - r.AppendLine("Fan Coolers Status"); - r.AppendLine(); + for (int index = 0; index < pStatesInfo.Utilizations.Length; index++) + { + NvApi.NvDynamicPState load = pStatesInfo.Utilizations[index]; + if (load.IsPresent && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) + _loads[index].Value = load.Percentage; + } + } + else + { + NvApi.NvUsages usages = GetUsages(out status); if (status == NvApi.NvStatus.OK) { - for (int i = 0; i < coolers.Count; i++) + for (int index = 0; index < usages.Entries.Length; index++) { - r.AppendFormat(" Items[{0}].CoolerId: {1}{2}", - i, - coolers.Items[i].CoolerId, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentRpm: {1}{2}", - i, - coolers.Items[i].CurrentRpm, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentMinLevel: {1}{2}", - i, - coolers.Items[i].CurrentMinLevel, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentMaxLevel: {1}{2}", - i, - coolers.Items[i].CurrentMaxLevel, - Environment.NewLine); - - r.AppendFormat(" Items[{0}].CurrentLevel: {1}{2}", - i, - coolers.Items[i].CurrentLevel, - Environment.NewLine); + NvApi.NvUsagesEntry load = usages.Entries[index]; + if (load.IsPresent > 0 && Enum.IsDefined(typeof(NvApi.NvUtilizationDomain), index)) + _loads[index].Value = load.Percentage; } } - else + } + } + + if (_powers is { Length: > 0 }) + { + NvApi.NvPowerTopology powerTopology = GetPowerTopology(out status); + if (status == NvApi.NvStatus.OK && powerTopology.Count > 0) + { + for (int i = 0; i < powerTopology.Count; i++) { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_ClientPowerTopologyGetStatus != null) - { - NvApi.NvPowerTopology powerTopology = GetPowerTopology(out NvApi.NvStatus status); - - r.AppendLine("Power Topology"); - r.AppendLine(); - - if (status == NvApi.NvStatus.OK) - { - for (int i = 0; i < powerTopology.Count; i++) - { - NvApi.NvPowerTopologyEntry entry = powerTopology.Entries[i]; - _powers[i].Value = entry.PowerUsage / 1000f; - - r.AppendFormat(" Entries[{0}].Domain: {1}{2}", i, entry.Domain, Environment.NewLine); - r.AppendFormat(" Entries[{0}].PowerUsage: {1}{2}", i, entry.PowerUsage, Environment.NewLine); - } - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (NvApi.NvAPI_GPU_GetMemoryInfo != null) - { - NvApi.NvMemoryInfo memoryInfo = GetMemoryInfo(out NvApi.NvStatus status); - - r.AppendLine("Memory Info"); - r.AppendLine(); - if (status == NvApi.NvStatus.OK) - { - r.AppendFormat(" AvailableDedicatedVideoMemory: {0}{1}", memoryInfo.AvailableDedicatedVideoMemory, Environment.NewLine); - r.AppendFormat(" DedicatedVideoMemory: {0}{1}", memoryInfo.DedicatedVideoMemory, Environment.NewLine); - r.AppendFormat(" CurrentAvailableDedicatedVideoMemory: {0}{1}", memoryInfo.CurrentAvailableDedicatedVideoMemory, Environment.NewLine); - r.AppendFormat(" SharedSystemMemory: {0}{1}", memoryInfo.SharedSystemMemory, Environment.NewLine); - r.AppendFormat(" SystemVideoMemory: {0}{1}", memoryInfo.SystemVideoMemory, Environment.NewLine); - } - else - { - r.Append(" Status: "); - r.AppendLine(status.ToString()); - } - - r.AppendLine(); - } - - if (_d3dDeviceId != null) - { - r.AppendLine("D3D"); - r.AppendLine(); - r.AppendLine(" Id: " + _d3dDeviceId); - - r.AppendLine(); - } - - return r.ToString(); - } - - private static string GetName(NvApi.NvPhysicalGpuHandle handle) - { - if (NvApi.NvAPI_GPU_GetFullName(handle, out string gpuName) == NvApi.NvStatus.OK) - { - string name = gpuName.Trim(); - return name.StartsWith("NVIDIA", StringComparison.OrdinalIgnoreCase) ? name : "NVIDIA " + name; - } - - return "NVIDIA"; - } - - private NvApi.NvMemoryInfo GetMemoryInfo(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_GetMemoryInfo == null || _displayHandle == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - NvApi.NvMemoryInfo memoryInfo = new() - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(2) - }; - - status = NvApi.NvAPI_GPU_GetMemoryInfo(_displayHandle.Value, ref memoryInfo); - return status == NvApi.NvStatus.OK ? memoryInfo : default; - } - - private NvApi.NvGpuClockFrequencies GetClockFrequencies(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_GetAllClockFrequencies == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - NvApi.NvGpuClockFrequencies clockFrequencies = new() - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(_clockVersion) - }; - - status = NvApi.NvAPI_GPU_GetAllClockFrequencies(_handle, ref clockFrequencies); - return status == NvApi.NvStatus.OK ? clockFrequencies : default; - } - - private NvApi.NvThermalSettings GetThermalSettings(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_GetThermalSettings == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - NvApi.NvThermalSettings settings = new() - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), - Count = NvApi.MAX_THERMAL_SENSORS_PER_GPU - }; - - status = NvApi.NvAPI_GPU_GetThermalSettings(_handle, (int)NvApi.NvThermalTarget.All, ref settings); - return status == NvApi.NvStatus.OK ? settings : default; - } - - private NvApi.NvThermalSensors GetThermalSensors(uint mask, out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_ThermalGetSensors == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - var thermalSensors = new NvApi.NvThermalSensors - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(2), - Mask = mask - }; - - status = NvApi.NvAPI_GPU_ThermalGetSensors(_handle, ref thermalSensors); - return status == NvApi.NvStatus.OK ? thermalSensors : default; - } - - private NvApi.NvFanCoolersStatus GetFanCoolersStatus(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - var coolers = new NvApi.NvFanCoolersStatus - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), - Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] - }; - - status = NvApi.NvAPI_GPU_ClientFanCoolersGetStatus(_handle, ref coolers); - return status == NvApi.NvStatus.OK ? coolers : default; - } - - private NvApi.NvFanCoolerControl GetFanCoolersControllers(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_ClientFanCoolersGetControl == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - var controllers = new NvApi.NvFanCoolerControl - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(1) - }; - - status = NvApi.NvAPI_GPU_ClientFanCoolersGetControl(_handle, ref controllers); - return status == NvApi.NvStatus.OK ? controllers : default; - } - - private NvApi.NvCoolerSettings GetCoolerSettings(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_GetCoolerSettings == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - NvApi.NvCoolerSettings settings = new() - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(2), - Cooler = new NvApi.NvCooler[NvApi.MAX_COOLERS_PER_GPU] - }; - - status = NvApi.NvAPI_GPU_GetCoolerSettings(_handle, NvApi.NvCoolerTarget.All, ref settings); - return status == NvApi.NvStatus.OK ? settings : default; - } - - private NvApi.NvDynamicPStatesInfo GetDynamicPstatesInfoEx(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - NvApi.NvDynamicPStatesInfo pStatesInfo = new() - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), - Utilizations = new NvApi.NvDynamicPState[NvApi.MAX_GPU_UTILIZATIONS] - }; - - status = NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx(_handle, ref pStatesInfo); - return status == NvApi.NvStatus.OK ? pStatesInfo : default; - } - - private NvApi.NvUsages GetUsages(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_GetUsages == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - NvApi.NvUsages usages = new() - { - Version = (uint)NvApi.MAKE_NVAPI_VERSION(1) - }; - - status = NvApi.NvAPI_GPU_GetUsages(_handle, ref usages); - return status == NvApi.NvStatus.OK ? usages : default; - } - - private NvApi.NvPowerTopology GetPowerTopology(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_ClientPowerTopologyGetStatus == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - NvApi.NvPowerTopology powerTopology = new() - { - Version = NvApi.MAKE_NVAPI_VERSION(1) - }; - - status = NvApi.NvAPI_GPU_ClientPowerTopologyGetStatus(_handle, ref powerTopology); - return status == NvApi.NvStatus.OK ? powerTopology : default; - } - - private int GetTachReading(out NvApi.NvStatus status) - { - if (NvApi.NvAPI_GPU_GetTachReading == null) - { - status = NvApi.NvStatus.Error; - return default; - } - - status = NvApi.NvAPI_GPU_GetTachReading(_handle, out int value); - return value; - } - - private static string GetUtilizationDomainName(NvApi.NvUtilizationDomain utilizationDomain) => utilizationDomain switch - { - NvApi.NvUtilizationDomain.Gpu => "GPU Core", - NvApi.NvUtilizationDomain.FrameBuffer => "GPU Memory Controller", - NvApi.NvUtilizationDomain.VideoEngine => "GPU Video Engine", - NvApi.NvUtilizationDomain.BusInterface => "GPU Bus", - _ => null - }; - - private void ControlModeChanged(IControl control) - { - switch (control.ControlMode) - { - case ControlMode.Default: - RestoreDefaultFanBehavior(control.Sensor.Index); - break; - case ControlMode.Software: - SoftwareControlValueChanged(control); - break; - } - } - - private void SoftwareControlValueChanged(IControl control) - { - int index = control.Sensor?.Index ?? 0; - - NvApi.NvCoolerLevels coolerLevels = new() { Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), Levels = new NvApi.NvLevel[NvApi.MAX_COOLERS_PER_GPU] }; - coolerLevels.Levels[0].Level = (int)control.SoftwareValue; - coolerLevels.Levels[0].Policy = NvApi.NvLevelPolicy.Manual; - if (NvApi.NvAPI_GPU_SetCoolerLevels(_handle, index, ref coolerLevels) == NvApi.NvStatus.OK) - return; - - NvApi.NvFanCoolerControl fanCoolersControllers = GetFanCoolersControllers(out _); - - for (int i = 0; i < fanCoolersControllers.Count; i++) - { - NvApi.NvFanCoolerControlItem nvFanCoolerControlItem = fanCoolersControllers.Items[i]; - if (nvFanCoolerControlItem.CoolerId == index) - { - nvFanCoolerControlItem.ControlMode = NvApi.NvFanControlMode.Manual; - nvFanCoolerControlItem.Level = (uint)control.SoftwareValue; - - fanCoolersControllers.Items[i] = nvFanCoolerControlItem; + NvApi.NvPowerTopologyEntry entry = powerTopology.Entries[i]; + _powers[i].Value = entry.PowerUsage / 1000f; } } - - NvApi.NvAPI_GPU_ClientFanCoolersSetControl(_handle, ref fanCoolersControllers); } - private void RestoreDefaultFanBehavior(int index) + if (_displayHandle != null) { - NvApi.NvCoolerLevels coolerLevels = new() { Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), Levels = new NvApi.NvLevel[NvApi.MAX_COOLERS_PER_GPU] }; - coolerLevels.Levels[0].Policy = NvApi.NvLevelPolicy.Auto; - if (NvApi.NvAPI_GPU_SetCoolerLevels(_handle, index, ref coolerLevels) == NvApi.NvStatus.OK) - return; - - NvApi.NvFanCoolerControl fanCoolersControllers = GetFanCoolersControllers(out _); - - for (int i = 0; i < fanCoolersControllers.Count; i++) + NvApi.NvMemoryInfo memoryInfo = GetMemoryInfo(out status); + if (status == NvApi.NvStatus.OK) { - NvApi.NvFanCoolerControlItem nvFanCoolerControlItem = fanCoolersControllers.Items[i]; - if (nvFanCoolerControlItem.CoolerId == index) - { - nvFanCoolerControlItem.ControlMode = NvApi.NvFanControlMode.Auto; - nvFanCoolerControlItem.Level = 0; + uint free = memoryInfo.CurrentAvailableDedicatedVideoMemory; + uint total = memoryInfo.DedicatedVideoMemory; - fanCoolersControllers.Items[i] = nvFanCoolerControlItem; - } + _memoryTotal.Value = total / 1024; + ActivateSensor(_memoryTotal); + + _memoryFree.Value = free / 1024; + ActivateSensor(_memoryFree); + + _memoryUsed.Value = (total - free) / 1024; + ActivateSensor(_memoryUsed); } - - NvApi.NvAPI_GPU_ClientFanCoolersSetControl(_handle, ref fanCoolersControllers); } - public override void Close() + if (NvidiaML.IsAvailable && _nvmlDevice.HasValue) { - if (_fanControls != null) + int? result = NvidiaML.NvmlDeviceGetPowerUsage(_nvmlDevice.Value); + if (result.HasValue) { - for (int i = 0; i < _fanControls.Length; i++) - { - _fanControls[i].ControlModeChanged -= ControlModeChanged; - _fanControls[i].SoftwareControlValueChanged -= SoftwareControlValueChanged; - - if (_fanControls[i].ControlMode != ControlMode.Undefined) - RestoreDefaultFanBehavior(i); - } + _powerUsage.Value = result.Value / 1000f; + ActivateSensor(_powerUsage); } - base.Close(); + // In MB/s, throughput sensors are passed as in KB/s. + uint? rx = NvidiaML.NvmlDeviceGetPcieThroughput(_nvmlDevice.Value, NvidiaML.NvmlPcieUtilCounter.RxBytes); + if (rx.HasValue) + { + _pcieThroughputRx.Value = rx * 1024; + ActivateSensor(_pcieThroughputRx); + } + + uint? tx = NvidiaML.NvmlDeviceGetPcieThroughput(_nvmlDevice.Value, NvidiaML.NvmlPcieUtilCounter.TxBytes); + if (tx.HasValue) + { + _pcieThroughputTx.Value = tx * 1024; + ActivateSensor(_pcieThroughputTx); + } } } + + public override string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("Nvidia GPU"); + r.AppendLine(); + r.AppendFormat("Name: {0}{1}", _name, Environment.NewLine); + r.AppendFormat("Index: {0}{1}", _adapterIndex, Environment.NewLine); + + if (_displayHandle.HasValue && NvApi.NvAPI_GetDisplayDriverVersion != null) + { + NvApi.NvDisplayDriverVersion driverVersion = new() { Version = (uint)NvApi.MAKE_NVAPI_VERSION(1) }; + if (NvApi.NvAPI_GetDisplayDriverVersion(_displayHandle.Value, ref driverVersion) == NvApi.NvStatus.OK) + { + r.Append("Driver Version: "); + r.Append(driverVersion.DriverVersion / 100); + r.Append("."); + r.Append((driverVersion.DriverVersion % 100).ToString("00", CultureInfo.InvariantCulture)); + r.AppendLine(); + r.Append("Driver Branch: "); + r.AppendLine(driverVersion.BuildBranch); + } + } + + if (NvApi.NvAPI_GPU_GetPCIIdentifiers != null) + { + NvApi.NvStatus status = NvApi.NvAPI_GPU_GetPCIIdentifiers(_handle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); + if (status == NvApi.NvStatus.OK) + { + r.Append("DeviceID: 0x"); + r.AppendLine(deviceId.ToString("X", CultureInfo.InvariantCulture)); + r.Append("SubSystemID: 0x"); + r.AppendLine(subSystemId.ToString("X", CultureInfo.InvariantCulture)); + r.Append("RevisionID: 0x"); + r.AppendLine(revisionId.ToString("X", CultureInfo.InvariantCulture)); + r.Append("ExtDeviceID: 0x"); + r.AppendLine(extDeviceId.ToString("X", CultureInfo.InvariantCulture)); + r.AppendLine(); + } + } + + if (NvApi.NvAPI_GPU_GetThermalSettings != null) + { + NvApi.NvThermalSettings thermalSettings = GetThermalSettings(out NvApi.NvStatus status); + + r.AppendLine("Thermal Settings"); + r.AppendLine(); + + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < thermalSettings.Count; i++) + { + r.AppendFormat(" Sensor[{0}].Controller: {1}{2}", i, thermalSettings.Sensor[i].Controller, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].DefaultMinTemp: {1}{2}", i, thermalSettings.Sensor[i].DefaultMinTemp, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].DefaultMaxTemp: {1}{2}", i, thermalSettings.Sensor[i].DefaultMaxTemp, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].CurrentTemp: {1}{2}", i, thermalSettings.Sensor[i].CurrentTemp, Environment.NewLine); + r.AppendFormat(" Sensor[{0}].Target: {1}{2}", i, thermalSettings.Sensor[i].Target, Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_GetAllClocks != null) + { + NvApi.NvGpuClockFrequencies clocks = GetClockFrequencies(out NvApi.NvStatus status); + + r.AppendLine("Clocks"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < clocks.Clocks.Length; i++) + { + if (clocks.Clocks[i].IsPresent) + r.AppendFormat(" Clock[{0}]: {1}{2}", i, clocks.Clocks[i].Frequency, Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_GetTachReading != null) + { + NvApi.NvStatus status = NvApi.NvAPI_GPU_GetTachReading(_handle, out int tachValue); + + r.AppendLine("Tachometer"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + r.AppendFormat(" Value: {0}{1}", tachValue, Environment.NewLine); + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx != null) + { + NvApi.NvDynamicPStatesInfo pStatesInfo = GetDynamicPstatesInfoEx(out NvApi.NvStatus status); + + r.AppendLine("P-States"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < pStatesInfo.Utilizations.Length; i++) + { + if (pStatesInfo.Utilizations[i].IsPresent) + r.AppendFormat(" Percentage[{0}]: {1}{2}", i, pStatesInfo.Utilizations[i].Percentage, Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_GetUsages != null) + { + NvApi.NvUsages usages = GetUsages(out NvApi.NvStatus status); + + r.AppendLine("Usages"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < usages.Entries.Length; i++) + { + if (usages.Entries[i].IsPresent > 0) + r.AppendFormat(" Usage[{0}]: {1}{2}", i, usages.Entries[i].Percentage, Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_GetCoolerSettings != null) + { + NvApi.NvCoolerSettings coolerSettings = GetCoolerSettings(out NvApi.NvStatus status); + r.AppendLine("Cooler Settings"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < coolerSettings.Count; i++) + { + r.AppendFormat(" Cooler[{0}].Type: {1}{2}", i, coolerSettings.Cooler[i].Type, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].Controller: {1}{2}", i, coolerSettings.Cooler[i].Controller, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].DefaultMin: {1}{2}", i, coolerSettings.Cooler[i].DefaultMin, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].DefaultMax: {1}{2}", i, coolerSettings.Cooler[i].DefaultMax, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CurrentMin: {1}{2}", i, coolerSettings.Cooler[i].CurrentMin, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CurrentMax: {1}{2}", i, coolerSettings.Cooler[i].CurrentMax, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CurrentLevel: {1}{2}", i, coolerSettings.Cooler[i].CurrentLevel, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].DefaultPolicy: {1}{2}", i, coolerSettings.Cooler[i].DefaultPolicy, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].CurrentPolicy: {1}{2}", i, coolerSettings.Cooler[i].CurrentPolicy, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].Target: {1}{2}", i, coolerSettings.Cooler[i].Target, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].ControlType: {1}{2}", i, coolerSettings.Cooler[i].ControlType, Environment.NewLine); + r.AppendFormat(" Cooler[{0}].Active: {1}{2}", i, coolerSettings.Cooler[i].Active, Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus != null) + { + NvApi.NvFanCoolersStatus coolers = GetFanCoolersStatus(out NvApi.NvStatus status); + + r.AppendLine("Fan Coolers Status"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < coolers.Count; i++) + { + r.AppendFormat(" Items[{0}].CoolerId: {1}{2}", + i, + coolers.Items[i].CoolerId, + Environment.NewLine); + + r.AppendFormat(" Items[{0}].CurrentRpm: {1}{2}", + i, + coolers.Items[i].CurrentRpm, + Environment.NewLine); + + r.AppendFormat(" Items[{0}].CurrentMinLevel: {1}{2}", + i, + coolers.Items[i].CurrentMinLevel, + Environment.NewLine); + + r.AppendFormat(" Items[{0}].CurrentMaxLevel: {1}{2}", + i, + coolers.Items[i].CurrentMaxLevel, + Environment.NewLine); + + r.AppendFormat(" Items[{0}].CurrentLevel: {1}{2}", + i, + coolers.Items[i].CurrentLevel, + Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_ClientPowerTopologyGetStatus != null) + { + NvApi.NvPowerTopology powerTopology = GetPowerTopology(out NvApi.NvStatus status); + + r.AppendLine("Power Topology"); + r.AppendLine(); + + if (status == NvApi.NvStatus.OK) + { + for (int i = 0; i < powerTopology.Count; i++) + { + NvApi.NvPowerTopologyEntry entry = powerTopology.Entries[i]; + _powers[i].Value = entry.PowerUsage / 1000f; + + r.AppendFormat(" Entries[{0}].Domain: {1}{2}", i, entry.Domain, Environment.NewLine); + r.AppendFormat(" Entries[{0}].PowerUsage: {1}{2}", i, entry.PowerUsage, Environment.NewLine); + } + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (NvApi.NvAPI_GPU_GetMemoryInfo != null) + { + NvApi.NvMemoryInfo memoryInfo = GetMemoryInfo(out NvApi.NvStatus status); + + r.AppendLine("Memory Info"); + r.AppendLine(); + if (status == NvApi.NvStatus.OK) + { + r.AppendFormat(" AvailableDedicatedVideoMemory: {0}{1}", memoryInfo.AvailableDedicatedVideoMemory, Environment.NewLine); + r.AppendFormat(" DedicatedVideoMemory: {0}{1}", memoryInfo.DedicatedVideoMemory, Environment.NewLine); + r.AppendFormat(" CurrentAvailableDedicatedVideoMemory: {0}{1}", memoryInfo.CurrentAvailableDedicatedVideoMemory, Environment.NewLine); + r.AppendFormat(" SharedSystemMemory: {0}{1}", memoryInfo.SharedSystemMemory, Environment.NewLine); + r.AppendFormat(" SystemVideoMemory: {0}{1}", memoryInfo.SystemVideoMemory, Environment.NewLine); + } + else + { + r.Append(" Status: "); + r.AppendLine(status.ToString()); + } + + r.AppendLine(); + } + + if (_d3dDeviceId != null) + { + r.AppendLine("D3D"); + r.AppendLine(); + r.AppendLine(" Id: " + _d3dDeviceId); + + r.AppendLine(); + } + + return r.ToString(); + } + + private static string GetName(NvApi.NvPhysicalGpuHandle handle) + { + if (NvApi.NvAPI_GPU_GetFullName(handle, out string gpuName) == NvApi.NvStatus.OK) + { + string name = gpuName.Trim(); + return name.StartsWith("NVIDIA", StringComparison.OrdinalIgnoreCase) ? name : "NVIDIA " + name; + } + + return "NVIDIA"; + } + + private NvApi.NvMemoryInfo GetMemoryInfo(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_GetMemoryInfo == null || _displayHandle == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + NvApi.NvMemoryInfo memoryInfo = new() + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(2) + }; + + status = NvApi.NvAPI_GPU_GetMemoryInfo(_displayHandle.Value, ref memoryInfo); + return status == NvApi.NvStatus.OK ? memoryInfo : default; + } + + private NvApi.NvGpuClockFrequencies GetClockFrequencies(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_GetAllClockFrequencies == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + NvApi.NvGpuClockFrequencies clockFrequencies = new() + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(_clockVersion) + }; + + status = NvApi.NvAPI_GPU_GetAllClockFrequencies(_handle, ref clockFrequencies); + return status == NvApi.NvStatus.OK ? clockFrequencies : default; + } + + private NvApi.NvThermalSettings GetThermalSettings(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_GetThermalSettings == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + NvApi.NvThermalSettings settings = new() + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), + Count = NvApi.MAX_THERMAL_SENSORS_PER_GPU + }; + + status = NvApi.NvAPI_GPU_GetThermalSettings(_handle, (int)NvApi.NvThermalTarget.All, ref settings); + return status == NvApi.NvStatus.OK ? settings : default; + } + + private NvApi.NvThermalSensors GetThermalSensors(uint mask, out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_ThermalGetSensors == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + var thermalSensors = new NvApi.NvThermalSensors + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(2), + Mask = mask + }; + + status = NvApi.NvAPI_GPU_ThermalGetSensors(_handle, ref thermalSensors); + return status == NvApi.NvStatus.OK ? thermalSensors : default; + } + + private NvApi.NvFanCoolersStatus GetFanCoolersStatus(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_ClientFanCoolersGetStatus == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + var coolers = new NvApi.NvFanCoolersStatus + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), + Items = new NvApi.NvFanCoolersStatusItem[NvApi.MAX_FAN_COOLERS_STATUS_ITEMS] + }; + + status = NvApi.NvAPI_GPU_ClientFanCoolersGetStatus(_handle, ref coolers); + return status == NvApi.NvStatus.OK ? coolers : default; + } + + private NvApi.NvFanCoolerControl GetFanCoolersControllers(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_ClientFanCoolersGetControl == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + var controllers = new NvApi.NvFanCoolerControl + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1) + }; + + status = NvApi.NvAPI_GPU_ClientFanCoolersGetControl(_handle, ref controllers); + return status == NvApi.NvStatus.OK ? controllers : default; + } + + private NvApi.NvCoolerSettings GetCoolerSettings(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_GetCoolerSettings == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + NvApi.NvCoolerSettings settings = new() + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(2), + Cooler = new NvApi.NvCooler[NvApi.MAX_COOLERS_PER_GPU] + }; + + status = NvApi.NvAPI_GPU_GetCoolerSettings(_handle, NvApi.NvCoolerTarget.All, ref settings); + return status == NvApi.NvStatus.OK ? settings : default; + } + + private NvApi.NvDynamicPStatesInfo GetDynamicPstatesInfoEx(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + NvApi.NvDynamicPStatesInfo pStatesInfo = new() + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), + Utilizations = new NvApi.NvDynamicPState[NvApi.MAX_GPU_UTILIZATIONS] + }; + + status = NvApi.NvAPI_GPU_GetDynamicPstatesInfoEx(_handle, ref pStatesInfo); + return status == NvApi.NvStatus.OK ? pStatesInfo : default; + } + + private NvApi.NvUsages GetUsages(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_GetUsages == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + NvApi.NvUsages usages = new() + { + Version = (uint)NvApi.MAKE_NVAPI_VERSION(1) + }; + + status = NvApi.NvAPI_GPU_GetUsages(_handle, ref usages); + return status == NvApi.NvStatus.OK ? usages : default; + } + + private NvApi.NvPowerTopology GetPowerTopology(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_ClientPowerTopologyGetStatus == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + NvApi.NvPowerTopology powerTopology = new() + { + Version = NvApi.MAKE_NVAPI_VERSION(1) + }; + + status = NvApi.NvAPI_GPU_ClientPowerTopologyGetStatus(_handle, ref powerTopology); + return status == NvApi.NvStatus.OK ? powerTopology : default; + } + + private int GetTachReading(out NvApi.NvStatus status) + { + if (NvApi.NvAPI_GPU_GetTachReading == null) + { + status = NvApi.NvStatus.Error; + return default; + } + + status = NvApi.NvAPI_GPU_GetTachReading(_handle, out int value); + return value; + } + + private static string GetUtilizationDomainName(NvApi.NvUtilizationDomain utilizationDomain) => utilizationDomain switch + { + NvApi.NvUtilizationDomain.Gpu => "GPU Core", + NvApi.NvUtilizationDomain.FrameBuffer => "GPU Memory Controller", + NvApi.NvUtilizationDomain.VideoEngine => "GPU Video Engine", + NvApi.NvUtilizationDomain.BusInterface => "GPU Bus", + _ => null + }; + + private void ControlModeChanged(IControl control) + { + switch (control.ControlMode) + { + case ControlMode.Default: + RestoreDefaultFanBehavior(control.Sensor.Index); + break; + case ControlMode.Software: + SoftwareControlValueChanged(control); + break; + } + } + + private void SoftwareControlValueChanged(IControl control) + { + int index = control.Sensor?.Index ?? 0; + + NvApi.NvCoolerLevels coolerLevels = new() { Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), Levels = new NvApi.NvLevel[NvApi.MAX_COOLERS_PER_GPU] }; + coolerLevels.Levels[0].Level = (int)control.SoftwareValue; + coolerLevels.Levels[0].Policy = NvApi.NvLevelPolicy.Manual; + if (NvApi.NvAPI_GPU_SetCoolerLevels(_handle, index, ref coolerLevels) == NvApi.NvStatus.OK) + return; + + NvApi.NvFanCoolerControl fanCoolersControllers = GetFanCoolersControllers(out _); + + for (int i = 0; i < fanCoolersControllers.Count; i++) + { + NvApi.NvFanCoolerControlItem nvFanCoolerControlItem = fanCoolersControllers.Items[i]; + if (nvFanCoolerControlItem.CoolerId == index) + { + nvFanCoolerControlItem.ControlMode = NvApi.NvFanControlMode.Manual; + nvFanCoolerControlItem.Level = (uint)control.SoftwareValue; + + fanCoolersControllers.Items[i] = nvFanCoolerControlItem; + } + } + + NvApi.NvAPI_GPU_ClientFanCoolersSetControl(_handle, ref fanCoolersControllers); + } + + private void RestoreDefaultFanBehavior(int index) + { + NvApi.NvCoolerLevels coolerLevels = new() { Version = (uint)NvApi.MAKE_NVAPI_VERSION(1), Levels = new NvApi.NvLevel[NvApi.MAX_COOLERS_PER_GPU] }; + coolerLevels.Levels[0].Policy = NvApi.NvLevelPolicy.Auto; + if (NvApi.NvAPI_GPU_SetCoolerLevels(_handle, index, ref coolerLevels) == NvApi.NvStatus.OK) + return; + + NvApi.NvFanCoolerControl fanCoolersControllers = GetFanCoolersControllers(out _); + + for (int i = 0; i < fanCoolersControllers.Count; i++) + { + NvApi.NvFanCoolerControlItem nvFanCoolerControlItem = fanCoolersControllers.Items[i]; + if (nvFanCoolerControlItem.CoolerId == index) + { + nvFanCoolerControlItem.ControlMode = NvApi.NvFanControlMode.Auto; + nvFanCoolerControlItem.Level = 0; + + fanCoolersControllers.Items[i] = nvFanCoolerControlItem; + } + } + + NvApi.NvAPI_GPU_ClientFanCoolersSetControl(_handle, ref fanCoolersControllers); + } + + public override void Close() + { + if (_fanControls != null) + { + for (int i = 0; i < _fanControls.Length; i++) + { + _fanControls[i].ControlModeChanged -= ControlModeChanged; + _fanControls[i].SoftwareControlValueChanged -= SoftwareControlValueChanged; + + if (_fanControls[i].ControlMode != ControlMode.Undefined) + RestoreDefaultFanBehavior(i); + } + } + + base.Close(); + } } diff --git a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs index f7a874e..1ca13ba 100644 --- a/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Gpu/NvidiaGroup.cs @@ -9,94 +9,93 @@ using System.Globalization; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Gpu +namespace LibreHardwareMonitor.Hardware.Gpu; + +internal class NvidiaGroup : IGroup { - internal class NvidiaGroup : IGroup + private readonly List _hardware = new(); + private readonly StringBuilder _report = new(); + + public NvidiaGroup(ISettings settings) { - private readonly List _hardware = new(); - private readonly StringBuilder _report = new(); + if (!NvApi.IsAvailable) + return; - public NvidiaGroup(ISettings settings) + _report.AppendLine("NvApi"); + _report.AppendLine(); + + if (NvApi.NvAPI_GetInterfaceVersionString(out string version) == NvApi.NvStatus.OK) { - if (!NvApi.IsAvailable) - return; + _report.Append("Version: "); + _report.AppendLine(version); + } - _report.AppendLine("NvApi"); + NvApi.NvPhysicalGpuHandle[] handles = new NvApi.NvPhysicalGpuHandle[NvApi.MAX_PHYSICAL_GPUS]; + if (NvApi.NvAPI_EnumPhysicalGPUs == null) + { + _report.AppendLine("Error: NvAPI_EnumPhysicalGPUs not available"); _report.AppendLine(); + return; + } - if (NvApi.NvAPI_GetInterfaceVersionString(out string version) == NvApi.NvStatus.OK) - { - _report.Append("Version: "); - _report.AppendLine(version); - } + NvApi.NvStatus status = NvApi.NvAPI_EnumPhysicalGPUs(handles, out int count); + if (status != NvApi.NvStatus.OK) + { + _report.AppendLine("Status: " + status); + _report.AppendLine(); + return; + } - NvApi.NvPhysicalGpuHandle[] handles = new NvApi.NvPhysicalGpuHandle[NvApi.MAX_PHYSICAL_GPUS]; - if (NvApi.NvAPI_EnumPhysicalGPUs == null) + IDictionary displayHandles = new Dictionary(); + if (NvApi.NvAPI_EnumNvidiaDisplayHandle != null && NvApi.NvAPI_GetPhysicalGPUsFromDisplay != null) + { + status = NvApi.NvStatus.OK; + int i = 0; + while (status == NvApi.NvStatus.OK) { - _report.AppendLine("Error: NvAPI_EnumPhysicalGPUs not available"); - _report.AppendLine(); - return; - } + NvApi.NvDisplayHandle displayHandle = new(); + status = NvApi.NvAPI_EnumNvidiaDisplayHandle(i, ref displayHandle); + i++; - NvApi.NvStatus status = NvApi.NvAPI_EnumPhysicalGPUs(handles, out int count); - if (status != NvApi.NvStatus.OK) - { - _report.AppendLine("Status: " + status); - _report.AppendLine(); - return; - } - - IDictionary displayHandles = new Dictionary(); - if (NvApi.NvAPI_EnumNvidiaDisplayHandle != null && NvApi.NvAPI_GetPhysicalGPUsFromDisplay != null) - { - status = NvApi.NvStatus.OK; - int i = 0; - while (status == NvApi.NvStatus.OK) + if (status == NvApi.NvStatus.OK) { - NvApi.NvDisplayHandle displayHandle = new(); - status = NvApi.NvAPI_EnumNvidiaDisplayHandle(i, ref displayHandle); - i++; - - if (status == NvApi.NvStatus.OK) + NvApi.NvPhysicalGpuHandle[] handlesFromDisplay = new NvApi.NvPhysicalGpuHandle[NvApi.MAX_PHYSICAL_GPUS]; + if (NvApi.NvAPI_GetPhysicalGPUsFromDisplay(displayHandle, handlesFromDisplay, out uint countFromDisplay) == NvApi.NvStatus.OK) { - NvApi.NvPhysicalGpuHandle[] handlesFromDisplay = new NvApi.NvPhysicalGpuHandle[NvApi.MAX_PHYSICAL_GPUS]; - if (NvApi.NvAPI_GetPhysicalGPUsFromDisplay(displayHandle, handlesFromDisplay, out uint countFromDisplay) == NvApi.NvStatus.OK) + for (int j = 0; j < countFromDisplay; j++) { - for (int j = 0; j < countFromDisplay; j++) - { - if (!displayHandles.ContainsKey(handlesFromDisplay[j])) - displayHandles.Add(handlesFromDisplay[j], displayHandle); - } + if (!displayHandles.ContainsKey(handlesFromDisplay[j])) + displayHandles.Add(handlesFromDisplay[j], displayHandle); } } } } - - _report.Append("Number of GPUs: "); - _report.AppendLine(count.ToString(CultureInfo.InvariantCulture)); - - for (int i = 0; i < count; i++) - { - displayHandles.TryGetValue(handles[i], out NvApi.NvDisplayHandle displayHandle); - _hardware.Add(new NvidiaGpu(i, handles[i], displayHandle, settings)); - } - - _report.AppendLine(); } - public IReadOnlyList Hardware => _hardware; + _report.Append("Number of GPUs: "); + _report.AppendLine(count.ToString(CultureInfo.InvariantCulture)); - public string GetReport() + for (int i = 0; i < count; i++) { - return _report.ToString(); + displayHandles.TryGetValue(handles[i], out NvApi.NvDisplayHandle displayHandle); + _hardware.Add(new NvidiaGpu(i, handles[i], displayHandle, settings)); } - public void Close() - { - foreach (Hardware gpu in _hardware) - gpu.Close(); - - NvidiaML.Close(); - } + _report.AppendLine(); } -} + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + return _report.ToString(); + } + + public void Close() + { + foreach (Hardware gpu in _hardware) + gpu.Close(); + + NvidiaML.Close(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/GroupAffinity.cs b/LibreHardwareMonitorLib/Hardware/GroupAffinity.cs index 8fd060b..63b6e5d 100644 --- a/LibreHardwareMonitorLib/Hardware/GroupAffinity.cs +++ b/LibreHardwareMonitorLib/Hardware/GroupAffinity.cs @@ -4,90 +4,89 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// This structure describes a group-specific affinity. +/// +public readonly struct GroupAffinity { + public static GroupAffinity Undefined = new(ushort.MaxValue, 0); + /// - /// This structure describes a group-specific affinity. + /// Initializes a new instance of the struct. /// - public readonly struct GroupAffinity + /// The group. + /// The mask. + public GroupAffinity(ushort group, ulong mask) { - public static GroupAffinity Undefined = new(ushort.MaxValue, 0); - - /// - /// Initializes a new instance of the struct. - /// - /// The group. - /// The mask. - public GroupAffinity(ushort group, ulong mask) - { - Group = group; - Mask = mask; - } - - /// - /// Gets a single group affinity. - /// - /// The group. - /// The index. - /// . - public static GroupAffinity Single(ushort group, int index) - { - return new GroupAffinity(group, 1UL << index); - } - - /// - /// Gets the group. - /// - public ushort Group { get; } - - /// - /// Gets the mask. - /// - public ulong Mask { get; } - - /// - /// Determines whether the specified is equal to this instance. - /// - /// The to compare with this instance. - /// true if the specified is equal to this instance; otherwise, false. - public override bool Equals(object o) - { - if (o == null || GetType() != o.GetType()) - return false; - - GroupAffinity a = (GroupAffinity)o; - return (Group == a.Group) && (Mask == a.Mask); - } - - /// - /// Returns a hash code for this instance. - /// - /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. - public override int GetHashCode() - { - return Group.GetHashCode() ^ Mask.GetHashCode(); - } - - /// - /// Implements the == operator. - /// - /// The a1. - /// The a2. - /// The result of the operator. - public static bool operator ==(GroupAffinity a1, GroupAffinity a2) - { - return (a1.Group == a2.Group) && (a1.Mask == a2.Mask); - } - - /// - /// Implements the != operator. - /// - /// The a1. - /// The a2. - /// The result of the operator. - public static bool operator !=(GroupAffinity a1, GroupAffinity a2) - { - return (a1.Group != a2.Group) || (a1.Mask != a2.Mask); - } + Group = group; + Mask = mask; } -} + + /// + /// Gets a single group affinity. + /// + /// The group. + /// The index. + /// . + public static GroupAffinity Single(ushort group, int index) + { + return new GroupAffinity(group, 1UL << index); + } + + /// + /// Gets the group. + /// + public ushort Group { get; } + + /// + /// Gets the mask. + /// + public ulong Mask { get; } + + /// + /// Determines whether the specified is equal to this instance. + /// + /// The to compare with this instance. + /// true if the specified is equal to this instance; otherwise, false. + public override bool Equals(object o) + { + if (o == null || GetType() != o.GetType()) + return false; + + GroupAffinity a = (GroupAffinity)o; + return (Group == a.Group) && (Mask == a.Mask); + } + + /// + /// Returns a hash code for this instance. + /// + /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. + public override int GetHashCode() + { + return Group.GetHashCode() ^ Mask.GetHashCode(); + } + + /// + /// Implements the == operator. + /// + /// The a1. + /// The a2. + /// The result of the operator. + public static bool operator ==(GroupAffinity a1, GroupAffinity a2) + { + return (a1.Group == a2.Group) && (a1.Mask == a2.Mask); + } + + /// + /// Implements the != operator. + /// + /// The a1. + /// The a2. + /// The result of the operator. + public static bool operator !=(GroupAffinity a1, GroupAffinity a2) + { + return (a1.Group != a2.Group) || (a1.Mask != a2.Mask); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Hardware.cs b/LibreHardwareMonitorLib/Hardware/Hardware.cs index 9b3051e..b96e991 100644 --- a/LibreHardwareMonitorLib/Hardware/Hardware.cs +++ b/LibreHardwareMonitorLib/Hardware/Hardware.cs @@ -8,128 +8,127 @@ using System; using System.Collections.Generic; using System.Linq; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Object representing a component of the computer. +/// +/// Individual information can be read from the . +/// +/// +public abstract class Hardware : IHardware { + protected readonly HashSet _active = new(); + protected readonly string _name; + protected readonly ISettings _settings; + private string _customName; + /// - /// Object representing a component of the computer. - /// - /// Individual information can be read from the . - /// + /// Creates a new instance based on the data provided. /// - public abstract class Hardware : IHardware + /// Component name. + /// Identifier that will be assigned to the device. Based on + /// Additional settings passed by the . + protected Hardware(string name, Identifier identifier, ISettings settings) { - protected readonly HashSet _active = new(); - protected readonly string _name; - protected readonly ISettings _settings; - private string _customName; + _settings = settings; + _name = name; + Identifier = identifier; + _customName = settings.GetValue(new Identifier(Identifier, "name").ToString(), name); + } - /// - /// Creates a new instance based on the data provided. - /// - /// Component name. - /// Identifier that will be assigned to the device. Based on - /// Additional settings passed by the . - protected Hardware(string name, Identifier identifier, ISettings settings) + /// + /// Event triggered when is closing. + /// + public event HardwareEventHandler Closing; + + /// + public abstract HardwareType HardwareType { get; } + + /// + public Identifier Identifier { get; } + + /// + public string Name + { + get { return _customName; } + set { - _settings = settings; - _name = name; - Identifier = identifier; - _customName = settings.GetValue(new Identifier(Identifier, "name").ToString(), name); + _customName = !string.IsNullOrEmpty(value) ? value : _name; + + _settings.SetValue(new Identifier(Identifier, "name").ToString(), _customName); } + } - /// - /// Event triggered when is closing. - /// - public event HardwareEventHandler Closing; + /// + public virtual IHardware Parent + { + get { return null; } + } - /// - public abstract HardwareType HardwareType { get; } + /// + public virtual IDictionary Properties => new SortedDictionary(); - /// - public Identifier Identifier { get; } + /// + public virtual ISensor[] Sensors + { + get { return _active.ToArray(); } + } - /// - public string Name - { - get { return _customName; } - set - { - _customName = !string.IsNullOrEmpty(value) ? value : _name; + /// + public IHardware[] SubHardware + { + get { return Array.Empty(); } + } - _settings.SetValue(new Identifier(Identifier, "name").ToString(), _customName); - } - } + /// + public virtual string GetReport() + { + return null; + } - /// - public virtual IHardware Parent - { - get { return null; } - } + /// + public abstract void Update(); - /// - public virtual IDictionary Properties => new SortedDictionary(); + /// + public void Accept(IVisitor visitor) + { + if (visitor == null) + throw new ArgumentNullException(nameof(visitor)); - /// - public virtual ISensor[] Sensors - { - get { return _active.ToArray(); } - } + visitor.VisitHardware(this); + } - /// - public IHardware[] SubHardware - { - get { return Array.Empty(); } - } + /// + public virtual void Traverse(IVisitor visitor) + { + foreach (ISensor sensor in _active) + sensor.Accept(visitor); + } - /// - public virtual string GetReport() - { - return null; - } + /// + protected virtual void ActivateSensor(ISensor sensor) + { + if (_active.Add(sensor)) + SensorAdded?.Invoke(sensor); + } - /// - public abstract void Update(); + /// + protected virtual void DeactivateSensor(ISensor sensor) + { + if (_active.Remove(sensor)) + SensorRemoved?.Invoke(sensor); + } - /// - public void Accept(IVisitor visitor) - { - if (visitor == null) - throw new ArgumentNullException(nameof(visitor)); - - visitor.VisitHardware(this); - } - - /// - public virtual void Traverse(IVisitor visitor) - { - foreach (ISensor sensor in _active) - sensor.Accept(visitor); - } - - /// - protected virtual void ActivateSensor(ISensor sensor) - { - if (_active.Add(sensor)) - SensorAdded?.Invoke(sensor); - } - - /// - protected virtual void DeactivateSensor(ISensor sensor) - { - if (_active.Remove(sensor)) - SensorRemoved?.Invoke(sensor); - } - - /// - public virtual void Close() - { - Closing?.Invoke(this); - } + /// + public virtual void Close() + { + Closing?.Invoke(this); + } #pragma warning disable 67 - public event SensorEventHandler SensorAdded; + public event SensorEventHandler SensorAdded; - public event SensorEventHandler SensorRemoved; + public event SensorEventHandler SensorRemoved; #pragma warning restore 67 - } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/HardwareType.cs b/LibreHardwareMonitorLib/Hardware/HardwareType.cs index 97742d0..7a64171 100644 --- a/LibreHardwareMonitorLib/Hardware/HardwareType.cs +++ b/LibreHardwareMonitorLib/Hardware/HardwareType.cs @@ -4,25 +4,24 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Collection of identifiers representing the purpose of the hardware. +/// +public enum HardwareType { - /// - /// Collection of identifiers representing the purpose of the hardware. - /// - public enum HardwareType - { - Motherboard, - SuperIO, - Cpu, - Memory, - GpuNvidia, - GpuAmd, - GpuIntel, - Storage, - Network, - Cooler, - EmbeddedController, - Psu, - Battery - } -} + Motherboard, + SuperIO, + Cpu, + Memory, + GpuNvidia, + GpuAmd, + GpuIntel, + Storage, + Network, + Cooler, + EmbeddedController, + Psu, + Battery +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IComputer.cs b/LibreHardwareMonitorLib/Hardware/IComputer.cs index 947db04..2c43a41 100644 --- a/LibreHardwareMonitorLib/Hardware/IComputer.cs +++ b/LibreHardwareMonitorLib/Hardware/IComputer.cs @@ -6,112 +6,111 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Handler that will trigger the actions assigned to it when the event occurs. +/// +/// Component returned to the assigned action(s). +public delegate void HardwareEventHandler(IHardware hardware); + +/// +/// Basic abstract with methods for the class which can store all hardware and decides which devices are to be checked and updated. +/// +public interface IComputer : IElement { /// - /// Handler that will trigger the actions assigned to it when the event occurs. + /// Triggered when a new is registered. /// - /// Component returned to the assigned action(s). - public delegate void HardwareEventHandler(IHardware hardware); + event HardwareEventHandler HardwareAdded; /// - /// Basic abstract with methods for the class which can store all hardware and decides which devices are to be checked and updated. + /// Triggered when a is removed. /// - public interface IComputer : IElement - { - /// - /// Triggered when a new is registered. - /// - event HardwareEventHandler HardwareAdded; + event HardwareEventHandler HardwareRemoved; - /// - /// Triggered when a is removed. - /// - event HardwareEventHandler HardwareRemoved; + /// + /// Gets a list of all known . + /// Can be updated by . + /// + /// List of all enabled devices. + IList Hardware { get; } - /// - /// Gets a list of all known . - /// Can be updated by . - /// - /// List of all enabled devices. - IList Hardware { 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 IsBatteryEnabled { 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 IsBatteryEnabled { 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 IsControllerEnabled { 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 IsControllerEnabled { 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 IsCpuEnabled { 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 IsCpuEnabled { get; } + /// + /// Gets or sets a value indicating whether collecting information about or devices should be enabled and updated. + /// + /// if a given category of devices is already enabled. + bool IsGpuEnabled { get; } - /// - /// Gets or sets a value indicating whether collecting information about or devices should be enabled and updated. - /// - /// 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 IsMemoryEnabled { 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 IsMemoryEnabled { 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 IsMotherboardEnabled { 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 IsMotherboardEnabled { 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 IsNetworkEnabled { 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 IsNetworkEnabled { 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 IsPsuEnabled { 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 IsPsuEnabled { 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 IsStorageEnabled { 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 IsStorageEnabled { get; } - - /// - /// Generates full LibreHardwareMonitor report for devices that have been enabled. - /// - /// A formatted text string with library, OS and hardware information. - string GetReport(); - } -} + /// + /// Generates full LibreHardwareMonitor report for devices that have been enabled. + /// + /// A formatted text string with library, OS and hardware information. + string GetReport(); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IControl.cs b/LibreHardwareMonitorLib/Hardware/IControl.cs index d8645c6..e3b6ac4 100644 --- a/LibreHardwareMonitorLib/Hardware/IControl.cs +++ b/LibreHardwareMonitorLib/Hardware/IControl.cs @@ -4,31 +4,30 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +public enum ControlMode { - public enum ControlMode - { - Undefined, - Software, - Default - } - - public interface IControl - { - ControlMode ControlMode { get; } - - Identifier Identifier { get; } - - float MaxSoftwareValue { get; } - - float MinSoftwareValue { get; } - - ISensor Sensor { get; } - - float SoftwareValue { get; } - - void SetDefault(); - - void SetSoftware(float value); - } + Undefined, + Software, + Default } + +public interface IControl +{ + ControlMode ControlMode { get; } + + Identifier Identifier { get; } + + float MaxSoftwareValue { get; } + + float MinSoftwareValue { get; } + + ISensor Sensor { get; } + + float SoftwareValue { get; } + + void SetDefault(); + + void SetSoftware(float value); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IElement.cs b/LibreHardwareMonitorLib/Hardware/IElement.cs index 34d131f..380b7de 100644 --- a/LibreHardwareMonitorLib/Hardware/IElement.cs +++ b/LibreHardwareMonitorLib/Hardware/IElement.cs @@ -4,23 +4,22 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Abstract parent with logic for the abstract class that stores data. +/// +public interface IElement { /// - /// Abstract parent with logic for the abstract class that stores data. + /// Accepts the observer for this instance. /// - public interface IElement - { - /// - /// Accepts the observer for this instance. - /// - /// Computer observer making the calls. - void Accept(IVisitor visitor); + /// Computer observer making the calls. + void Accept(IVisitor visitor); - /// - /// Call the method for all child instances (called only from visitors). - /// - /// Computer observer making the calls. - void Traverse(IVisitor visitor); - } -} + /// + /// Call the method for all child instances (called only from visitors). + /// + /// Computer observer making the calls. + void Traverse(IVisitor visitor); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IGroup.cs b/LibreHardwareMonitorLib/Hardware/IGroup.cs index dbcc4bd..863e32e 100644 --- a/LibreHardwareMonitorLib/Hardware/IGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/IGroup.cs @@ -6,27 +6,26 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// A group of devices from one category in one list. +/// +internal interface IGroup { /// - /// A group of devices from one category in one list. + /// Gets a list that stores information about in a given group. /// - internal interface IGroup - { - /// - /// Gets a list that stores information about in a given group. - /// - IReadOnlyList Hardware { get; } + IReadOnlyList Hardware { get; } - /// - /// Report containing most of the known information about all in this . - /// - /// A formatted text string with hardware information. - string GetReport(); + /// + /// Report containing most of the known information about all in this . + /// + /// A formatted text string with hardware information. + string GetReport(); - /// - /// Stop updating this group in the future. - /// - void Close(); - } -} + /// + /// Stop updating this group in the future. + /// + void Close(); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IHardware.cs b/LibreHardwareMonitorLib/Hardware/IHardware.cs index b719e17..a08086d 100644 --- a/LibreHardwareMonitorLib/Hardware/IHardware.cs +++ b/LibreHardwareMonitorLib/Hardware/IHardware.cs @@ -6,77 +6,76 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Handler that will trigger the actions assigned to it when the event occurs. +/// +/// Component returned to the assigned action(s). +public delegate void SensorEventHandler(ISensor sensor); + +/// +/// Abstract object that stores information about a device. All sensors are available as an array of . +/// +/// Can contain . +/// Type specified in . +/// +/// +public interface IHardware : IElement { /// - /// Handler that will trigger the actions assigned to it when the event occurs. + /// /// - /// Component returned to the assigned action(s). - public delegate void SensorEventHandler(ISensor sensor); + HardwareType HardwareType { get; } /// - /// Abstract object that stores information about a device. All sensors are available as an array of . - /// - /// Can contain . - /// Type specified in . - /// + /// Gets a unique hardware ID that represents its location. /// - public interface IHardware : IElement - { - /// - /// - /// - HardwareType HardwareType { get; } + Identifier Identifier { get; } - /// - /// Gets a unique hardware ID that represents its location. - /// - Identifier Identifier { get; } + /// + /// Gets or sets device name. + /// + string Name { get; set; } - /// - /// Gets or sets device name. - /// - string Name { get; set; } + /// + /// Gets the device that is the parent of the current hardware. For example, the motherboard is the parent of SuperIO. + /// + IHardware Parent { get; } - /// - /// Gets the device that is the parent of the current hardware. For example, the motherboard is the parent of SuperIO. - /// - IHardware Parent { get; } + /// + /// Gets an array of all sensors such as , , etc. + /// + ISensor[] Sensors { get; } - /// - /// Gets an array of all sensors such as , , etc. - /// - ISensor[] Sensors { get; } + /// + /// Gets child devices, e.g. of the . + /// + IHardware[] SubHardware { get; } - /// - /// Gets child devices, e.g. of the . - /// - IHardware[] SubHardware { get; } + /// + /// Report containing most of the known information about the current device. + /// + /// A formatted text string with hardware information. + string GetReport(); - /// - /// Report containing most of the known information about the current device. - /// - /// A formatted text string with hardware information. - string GetReport(); + /// + /// Refreshes the information stored in array. + /// + void Update(); - /// - /// Refreshes the information stored in array. - /// - void Update(); + /// + /// An that will be triggered when a new sensor appears. + /// + event SensorEventHandler SensorAdded; - /// - /// An that will be triggered when a new sensor appears. - /// - event SensorEventHandler SensorAdded; + /// + /// An that will be triggered when one of the sensors is removed. + /// + event SensorEventHandler SensorRemoved; - /// - /// An that will be triggered when one of the sensors is removed. - /// - event SensorEventHandler SensorRemoved; - - /// - /// Gets rarely changed hardware properties that can't be represented as sensors. - /// - IDictionary Properties { get; } - } -} + /// + /// Gets rarely changed hardware properties that can't be represented as sensors. + /// + IDictionary Properties { get; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IHardwareChanged.cs b/LibreHardwareMonitorLib/Hardware/IHardwareChanged.cs index db530ee..8808f8b 100644 --- a/LibreHardwareMonitorLib/Hardware/IHardwareChanged.cs +++ b/LibreHardwareMonitorLib/Hardware/IHardwareChanged.cs @@ -3,11 +3,10 @@ // Copyright (C) LibreHardwareMonitor and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal interface IHardwareChanged { - internal interface IHardwareChanged - { - event HardwareEventHandler HardwareAdded; - event HardwareEventHandler HardwareRemoved; - } -} + event HardwareEventHandler HardwareAdded; + event HardwareEventHandler HardwareRemoved; +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IParameter.cs b/LibreHardwareMonitorLib/Hardware/IParameter.cs index 0b72b7f..d3c1dc5 100644 --- a/LibreHardwareMonitorLib/Hardware/IParameter.cs +++ b/LibreHardwareMonitorLib/Hardware/IParameter.cs @@ -4,46 +4,45 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Abstract object that represents additional parameters included in . +/// +public interface IParameter : IElement { /// - /// Abstract object that represents additional parameters included in . + /// Gets a parameter default value defined by library. /// - public interface IParameter : IElement - { - /// - /// Gets a parameter default value defined by library. - /// - float DefaultValue { get; } + float DefaultValue { get; } - /// - /// Gets a parameter description defined by library. - /// - string Description { get; } + /// + /// Gets a parameter description defined by library. + /// + string Description { get; } - /// - /// Gets a unique parameter ID that represents its location. - /// - Identifier Identifier { get; } + /// + /// Gets a unique parameter ID that represents its location. + /// + Identifier Identifier { get; } - /// - /// Gets or sets information whether the given is the default for . - /// - bool IsDefault { get; set; } + /// + /// Gets or sets information whether the given is the default for . + /// + bool IsDefault { get; set; } - /// - /// Gets a parameter name defined by library. - /// - string Name { get; } + /// + /// Gets a parameter name defined by library. + /// + string Name { get; } - /// - /// Gets the sensor that is the data container for the given parameter. - /// - ISensor Sensor { get; } + /// + /// Gets the sensor that is the data container for the given parameter. + /// + ISensor Sensor { get; } - /// - /// Gets or sets the current value. - /// - float Value { get; set; } - } -} + /// + /// Gets or sets the current value. + /// + float Value { get; set; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/ISensor.cs b/LibreHardwareMonitorLib/Hardware/ISensor.cs index 6c0f128..528dc37 100644 --- a/LibreHardwareMonitorLib/Hardware/ISensor.cs +++ b/LibreHardwareMonitorLib/Hardware/ISensor.cs @@ -7,121 +7,120 @@ using System; using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Category of what type the selected sensor is. +/// +public enum SensorType { - /// - /// Category of what type the selected sensor is. - /// - public enum SensorType - { - Voltage, // V - Current, // A - Power, // W - Clock, // MHz - Temperature, // °C - Load, // % - Frequency, // Hz - Fan, // RPM - Flow, // L/h - Control, // % - Level, // % - Factor, // 1 - Data, // GB = 2^30 Bytes - SmallData, // MB = 2^20 Bytes - Throughput, // B/s - TimeSpan, // Seconds - Energy, // milliwatt-hour (mWh) - Noise // dBA - } - - /// - /// Stores the readed value and the time in which it was recorded. - /// - public struct SensorValue - { - /// of the sensor. - /// The time code during which the was recorded. - public SensorValue(float value, DateTime time) - { - Value = value; - Time = time; - } - - /// - /// Gets the value of the sensor - /// - public float Value { get; } - - /// - /// Gets the time code during which the was recorded. - /// - public DateTime Time { get; } - } - - /// - /// Stores information about the readed values and the time in which they were collected. - /// - public interface ISensor : IElement - { - IControl Control { get; } - - /// - /// - /// - IHardware Hardware { get; } - - Identifier Identifier { get; } - - /// - /// Gets the unique identifier of this sensor for a given . - /// - int Index { get; } - - bool IsDefaultHidden { get; } - - /// - /// Gets a maximum value recorded for the given sensor. - /// - float? Max { get; } - - /// - /// Gets a minimum value recorded for the given sensor. - /// - float? Min { get; } - - /// - /// Gets or sets a sensor name. - /// By default determined by the library. - /// - string Name { get; set; } - - IReadOnlyList Parameters { get; } - - /// - /// - /// - SensorType SensorType { get; } - - /// - /// Gets the last recorded value for the given sensor. - /// - float? Value { get; } - - /// - /// Gets a list of recorded values for the given sensor. - /// - IEnumerable Values { get; } - - TimeSpan ValuesTimeWindow { get; set; } - - /// - /// Resets a value stored in . - /// - void ResetMin(); - - /// - /// Resets a value stored in . - /// - void ResetMax(); - } + Voltage, // V + Current, // A + Power, // W + Clock, // MHz + Temperature, // °C + Load, // % + Frequency, // Hz + Fan, // RPM + Flow, // L/h + Control, // % + Level, // % + Factor, // 1 + Data, // GB = 2^30 Bytes + SmallData, // MB = 2^20 Bytes + Throughput, // B/s + TimeSpan, // Seconds + Energy, // milliwatt-hour (mWh) + Noise // dBA } + +/// +/// Stores the readed value and the time in which it was recorded. +/// +public struct SensorValue +{ + /// of the sensor. + /// The time code during which the was recorded. + public SensorValue(float value, DateTime time) + { + Value = value; + Time = time; + } + + /// + /// Gets the value of the sensor + /// + public float Value { get; } + + /// + /// Gets the time code during which the was recorded. + /// + public DateTime Time { get; } +} + +/// +/// Stores information about the readed values and the time in which they were collected. +/// +public interface ISensor : IElement +{ + IControl Control { get; } + + /// + /// + /// + IHardware Hardware { get; } + + Identifier Identifier { get; } + + /// + /// Gets the unique identifier of this sensor for a given . + /// + int Index { get; } + + bool IsDefaultHidden { get; } + + /// + /// Gets a maximum value recorded for the given sensor. + /// + float? Max { get; } + + /// + /// Gets a minimum value recorded for the given sensor. + /// + float? Min { get; } + + /// + /// Gets or sets a sensor name. + /// By default determined by the library. + /// + string Name { get; set; } + + IReadOnlyList Parameters { get; } + + /// + /// + /// + SensorType SensorType { get; } + + /// + /// Gets the last recorded value for the given sensor. + /// + float? Value { get; } + + /// + /// Gets a list of recorded values for the given sensor. + /// + IEnumerable Values { get; } + + TimeSpan ValuesTimeWindow { get; set; } + + /// + /// Resets a value stored in . + /// + void ResetMin(); + + /// + /// Resets a value stored in . + /// + void ResetMax(); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/ISensorLimits.cs b/LibreHardwareMonitorLib/Hardware/ISensorLimits.cs index 1939732..9f04cf3 100644 --- a/LibreHardwareMonitorLib/Hardware/ISensorLimits.cs +++ b/LibreHardwareMonitorLib/Hardware/ISensorLimits.cs @@ -3,37 +3,36 @@ // Copyright (C) LibreHardwareMonitor and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Abstract object that stores information about the limits of . +/// +public interface ISensorLimits { /// - /// Abstract object that stores information about the limits of . + /// Upper limit of value. /// - public interface ISensorLimits - { - /// - /// Upper limit of value. - /// - float? HighLimit { get; } - - /// - /// Lower limit of value. - /// - float? LowLimit { get; } - } + float? HighLimit { get; } /// - /// Abstract object that stores information about the critical limits of . + /// Lower limit of value. /// - public interface ICriticalSensorLimits - { - /// - /// Critical upper limit of value. - /// - float? CriticalHighLimit { get; } - - /// - /// Critical lower limit of value. - /// - float? CriticalLowLimit { get; } - } + float? LowLimit { get; } } + +/// +/// Abstract object that stores information about the critical limits of . +/// +public interface ICriticalSensorLimits +{ + /// + /// Critical upper limit of value. + /// + float? CriticalHighLimit { get; } + + /// + /// Critical lower limit of value. + /// + float? CriticalLowLimit { get; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/ISettings.cs b/LibreHardwareMonitorLib/Hardware/ISettings.cs index 91a25e1..6bdbc97 100644 --- a/LibreHardwareMonitorLib/Hardware/ISettings.cs +++ b/LibreHardwareMonitorLib/Hardware/ISettings.cs @@ -4,37 +4,36 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Abstract object that stores settings passed to , and . +/// +public interface ISettings { /// - /// Abstract object that stores settings passed to , and . + /// Returns information whether the given collection of settings contains a value assigned to the given key. /// - public interface ISettings - { - /// - /// Returns information whether the given collection of settings contains a value assigned to the given key. - /// - /// Key to which the setting value is assigned. - bool Contains(string name); + /// Key to which the setting value is assigned. + bool Contains(string name); - /// - /// Assigns a setting option to a given key. - /// - /// Key to which the setting value is assigned. - /// Text setting value. - void SetValue(string name, string value); + /// + /// Assigns a setting option to a given key. + /// + /// Key to which the setting value is assigned. + /// Text setting value. + void SetValue(string name, string value); - /// - /// Gets a setting option assigned to the given key. - /// - /// Key to which the setting value is assigned. - /// Default value. - string GetValue(string name, string value); + /// + /// Gets a setting option assigned to the given key. + /// + /// Key to which the setting value is assigned. + /// Default value. + string GetValue(string name, string value); - /// - /// Removes a setting with the specified key from the settings collection. - /// - /// Key to which the setting value is assigned. - void Remove(string name); - } -} + /// + /// Removes a setting with the specified key from the settings collection. + /// + /// Key to which the setting value is assigned. + void Remove(string name); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/IVisitor.cs b/LibreHardwareMonitorLib/Hardware/IVisitor.cs index ccae364..bdb25a0 100644 --- a/LibreHardwareMonitorLib/Hardware/IVisitor.cs +++ b/LibreHardwareMonitorLib/Hardware/IVisitor.cs @@ -4,35 +4,34 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Base interface for creating observers who call to devices. +/// +public interface IVisitor { /// - /// Base interface for creating observers who call to devices. + /// Refreshes the values of all in all on selected . /// - public interface IVisitor - { - /// - /// Refreshes the values of all in all on selected . - /// - /// Instance of the computer to be revisited. - void VisitComputer(IComputer computer); + /// Instance of the computer to be revisited. + void VisitComputer(IComputer computer); - /// - /// Refreshes the values of all on selected . - /// - /// Instance of the hardware to be revisited. - void VisitHardware(IHardware hardware); + /// + /// Refreshes the values of all on selected . + /// + /// Instance of the hardware to be revisited. + void VisitHardware(IHardware hardware); - /// - /// Refreshes the values on selected . - /// - /// Instance of the sensor to be revisited. - void VisitSensor(ISensor sensor); + /// + /// Refreshes the values on selected . + /// + /// Instance of the sensor to be revisited. + void VisitSensor(ISensor sensor); - /// - /// Refreshes the values on selected . - /// - /// Instance of the parameter to be revisited. - void VisitParameter(IParameter parameter); - } -} + /// + /// Refreshes the values on selected . + /// + /// Instance of the parameter to be revisited. + void VisitParameter(IParameter parameter); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Identifier.cs b/LibreHardwareMonitorLib/Hardware/Identifier.cs index 2ed4e73..1d92945 100644 --- a/LibreHardwareMonitorLib/Hardware/Identifier.cs +++ b/LibreHardwareMonitorLib/Hardware/Identifier.cs @@ -8,120 +8,119 @@ using System; using System.Collections.Generic; using System.Text; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Represents a unique / identifier in text format with a / separator. +/// +public class Identifier : IComparable { - /// - /// Represents a unique / identifier in text format with a / separator. - /// - public class Identifier : IComparable + private const char Separator = '/'; + private readonly string _identifier; + + public Identifier(params string[] identifiers) { - private const char Separator = '/'; - private readonly string _identifier; - - public Identifier(params string[] identifiers) + CheckIdentifiers(identifiers); + StringBuilder s = new(); + for (int i = 0; i < identifiers.Length; i++) { - CheckIdentifiers(identifiers); - StringBuilder s = new(); - for (int i = 0; i < identifiers.Length; i++) - { - s.Append(Separator); - s.Append(identifiers[i]); - } - - _identifier = s.ToString(); + s.Append(Separator); + s.Append(identifiers[i]); } - /// - /// Creates a new identifier instance based on the base and additional elements. - /// - /// Base identifier being the beginning of the new one. - /// Additional parts by which the base will be extended. - public Identifier(Identifier identifier, params string[] extensions) - { - CheckIdentifiers(extensions); - StringBuilder s = new(); - s.Append(identifier); - for (int i = 0; i < extensions.Length; i++) - { - s.Append(Separator); - s.Append(extensions[i]); - } + _identifier = s.ToString(); + } - _identifier = s.ToString(); + /// + /// Creates a new identifier instance based on the base and additional elements. + /// + /// Base identifier being the beginning of the new one. + /// Additional parts by which the base will be extended. + public Identifier(Identifier identifier, params string[] extensions) + { + CheckIdentifiers(extensions); + StringBuilder s = new(); + s.Append(identifier); + for (int i = 0; i < extensions.Length; i++) + { + s.Append(Separator); + s.Append(extensions[i]); } - /// - public int CompareTo(Identifier other) + _identifier = s.ToString(); + } + + /// + public int CompareTo(Identifier other) + { + if (other == null) + return 1; + + return string.Compare(_identifier, + other._identifier, + StringComparison.Ordinal); + } + + private static void CheckIdentifiers(IEnumerable identifiers) + { + foreach (string s in identifiers) { - if (other == null) - return 1; - - return string.Compare(_identifier, - other._identifier, - StringComparison.Ordinal); - } - - private static void CheckIdentifiers(IEnumerable identifiers) - { - foreach (string s in identifiers) - { - if (s.Contains(" ") || s.Contains(Separator.ToString())) - throw new ArgumentException("Invalid identifier"); - } - } - - /// - public override string ToString() - { - return _identifier; - } - - /// - public override bool Equals(object obj) - { - if (obj == null) - return false; - - Identifier id = obj as Identifier; - if (id == null) - return false; - - return _identifier == id._identifier; - } - - /// - public override int GetHashCode() - { - return _identifier.GetHashCode(); - } - - public static bool operator ==(Identifier id1, Identifier id2) - { - if (id1 is null && id2 is null) - return true; - - return id1 is not null && id1.Equals(id2); - } - - public static bool operator !=(Identifier id1, Identifier id2) - { - return !(id1 == id2); - } - - public static bool operator <(Identifier id1, Identifier id2) - { - if (id1 == null) - return id2 != null; - - return id1.CompareTo(id2) < 0; - } - - public static bool operator >(Identifier id1, Identifier id2) - { - if (id1 == null) - return false; - - return id1.CompareTo(id2) > 0; + if (s.Contains(" ") || s.Contains(Separator.ToString())) + throw new ArgumentException("Invalid identifier"); } } -} + + /// + public override string ToString() + { + return _identifier; + } + + /// + public override bool Equals(object obj) + { + if (obj == null) + return false; + + Identifier id = obj as Identifier; + if (id == null) + return false; + + return _identifier == id._identifier; + } + + /// + public override int GetHashCode() + { + return _identifier.GetHashCode(); + } + + public static bool operator ==(Identifier id1, Identifier id2) + { + if (id1 is null && id2 is null) + return true; + + return id1 is not null && id1.Equals(id2); + } + + public static bool operator !=(Identifier id1, Identifier id2) + { + return !(id1 == id2); + } + + public static bool operator <(Identifier id1, Identifier id2) + { + if (id1 == null) + return id2 != null; + + return id1.CompareTo(id2) < 0; + } + + public static bool operator >(Identifier id1, Identifier id2) + { + if (id1 == null) + return false; + + return id1.CompareTo(id2) > 0; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/InpOut.cs b/LibreHardwareMonitorLib/Hardware/InpOut.cs index f5df7f9..886f56e 100644 --- a/LibreHardwareMonitorLib/Hardware/InpOut.cs +++ b/LibreHardwareMonitorLib/Hardware/InpOut.cs @@ -6,205 +6,204 @@ using System.Runtime.InteropServices; using System.Threading; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal static class InpOut { - internal static class InpOut + private static string _filePath; + private static IntPtr _libraryHandle; + private static Interop.InpOut.MapPhysToLinDelegate _mapPhysToLin; + private static Interop.InpOut.UnmapPhysicalMemoryDelegate _unmapPhysicalMemory; + + public static bool IsOpen { get; private set; } + + public static bool Open() { - private static string _filePath; - private static IntPtr _libraryHandle; - private static Interop.InpOut.MapPhysToLinDelegate _mapPhysToLin; - private static Interop.InpOut.UnmapPhysicalMemoryDelegate _unmapPhysicalMemory; + if (Software.OperatingSystem.IsUnix) + return false; - public static bool IsOpen { get; private set; } + if (IsOpen) + return true; - public static bool Open() - { - if (Software.OperatingSystem.IsUnix) - return false; - - if (IsOpen) - return true; - - _filePath = GetFilePath(); - if (_filePath != null && (File.Exists(_filePath) || Extract(_filePath))) - { - _libraryHandle = Kernel32.LoadLibrary(_filePath); - if (_libraryHandle != IntPtr.Zero) - { - IntPtr mapPhysToLinAddress = Kernel32.GetProcAddress(_libraryHandle, "MapPhysToLin"); - IntPtr unmapPhysicalMemoryAddress = Kernel32.GetProcAddress(_libraryHandle, "UnmapPhysicalMemory"); - - if (mapPhysToLinAddress != IntPtr.Zero) - _mapPhysToLin = Marshal.GetDelegateForFunctionPointer(mapPhysToLinAddress); - - if (unmapPhysicalMemoryAddress != IntPtr.Zero) - _unmapPhysicalMemory = Marshal.GetDelegateForFunctionPointer(unmapPhysicalMemoryAddress); - - IsOpen = true; - } - } - - if (!IsOpen) - DeleteDll(); - - return IsOpen; - } - - public static void Close() + _filePath = GetFilePath(); + if (_filePath != null && (File.Exists(_filePath) || Extract(_filePath))) { + _libraryHandle = Kernel32.LoadLibrary(_filePath); if (_libraryHandle != IntPtr.Zero) { - Kernel32.FreeLibrary(_libraryHandle); - DeleteDll(); + IntPtr mapPhysToLinAddress = Kernel32.GetProcAddress(_libraryHandle, "MapPhysToLin"); + IntPtr unmapPhysicalMemoryAddress = Kernel32.GetProcAddress(_libraryHandle, "UnmapPhysicalMemory"); - _libraryHandle = IntPtr.Zero; + if (mapPhysToLinAddress != IntPtr.Zero) + _mapPhysToLin = Marshal.GetDelegateForFunctionPointer(mapPhysToLinAddress); + + if (unmapPhysicalMemoryAddress != IntPtr.Zero) + _unmapPhysicalMemory = Marshal.GetDelegateForFunctionPointer(unmapPhysicalMemoryAddress); + + IsOpen = true; } - - IsOpen = false; } - public static byte[] ReadMemory(IntPtr baseAddress, uint size) + if (!IsOpen) + DeleteDll(); + + return IsOpen; + } + + public static void Close() + { + if (_libraryHandle != IntPtr.Zero) { - if (_mapPhysToLin != null && _unmapPhysicalMemory != null) - { - IntPtr pdwLinAddr = _mapPhysToLin(baseAddress, size, out IntPtr pPhysicalMemoryHandle); - if (pdwLinAddr != IntPtr.Zero) - { - byte[] bytes = new byte[size]; - Marshal.Copy(pdwLinAddr, bytes, 0, bytes.Length); - _unmapPhysicalMemory(pPhysicalMemoryHandle, pdwLinAddr); + Kernel32.FreeLibrary(_libraryHandle); + DeleteDll(); - return bytes; - } - } - - return null; + _libraryHandle = IntPtr.Zero; } - private static void DeleteDll() - { - try - { - // try to delete the DLL - if (_filePath != null && File.Exists(_filePath)) - { - File.Delete(_filePath); - } + IsOpen = false; + } - _filePath = null; + public static byte[] ReadMemory(IntPtr baseAddress, uint size) + { + if (_mapPhysToLin != null && _unmapPhysicalMemory != null) + { + IntPtr pdwLinAddr = _mapPhysToLin(baseAddress, size, out IntPtr pPhysicalMemoryHandle); + if (pdwLinAddr != IntPtr.Zero) + { + byte[] bytes = new byte[size]; + Marshal.Copy(pdwLinAddr, bytes, 0, bytes.Length); + _unmapPhysicalMemory(pPhysicalMemoryHandle, pdwLinAddr); + + return bytes; } - catch - { } } - private static string GetFilePath() + return null; + } + + private static void DeleteDll() + { + try { - string filePath; - - try + // try to delete the DLL + if (_filePath != null && File.Exists(_filePath)) { - filePath = Path.GetTempFileName(); - if (!string.IsNullOrEmpty(filePath)) - return Path.ChangeExtension(filePath, ".dll"); - } - catch (IOException) - { } - - const string fileName = "inpout.dll"; - - try - { - ProcessModule processModule = Process.GetCurrentProcess().MainModule; - if (!string.IsNullOrEmpty(processModule?.FileName)) - return Path.Combine(Path.GetDirectoryName(processModule.FileName) ?? string.Empty, fileName); - } - catch - { - // Continue with the other options. + File.Delete(_filePath); } - filePath = GetPathFromAssembly(Assembly.GetExecutingAssembly()); + _filePath = null; + } + catch + { } + } + + private static string GetFilePath() + { + string filePath; + + try + { + filePath = Path.GetTempFileName(); if (!string.IsNullOrEmpty(filePath)) - return Path.Combine(Path.GetDirectoryName(filePath) ?? string.Empty, fileName); + return Path.ChangeExtension(filePath, ".dll"); + } + catch (IOException) + { } - filePath = GetPathFromAssembly(typeof(Ring0).Assembly); - if (!string.IsNullOrEmpty(filePath)) - return Path.Combine(Path.GetDirectoryName(filePath) ?? string.Empty, fileName); + const string fileName = "inpout.dll"; - return null; - - static string GetPathFromAssembly(Assembly assembly) - { - try - { - string location = assembly?.Location; - return !string.IsNullOrEmpty(location) ? location : null; - } - catch - { - return null; - } - } + try + { + ProcessModule processModule = Process.GetCurrentProcess().MainModule; + if (!string.IsNullOrEmpty(processModule?.FileName)) + return Path.Combine(Path.GetDirectoryName(processModule.FileName) ?? string.Empty, fileName); + } + catch + { + // Continue with the other options. } - private static bool Extract(string filePath) + filePath = GetPathFromAssembly(Assembly.GetExecutingAssembly()); + if (!string.IsNullOrEmpty(filePath)) + return Path.Combine(Path.GetDirectoryName(filePath) ?? string.Empty, fileName); + + filePath = GetPathFromAssembly(typeof(Ring0).Assembly); + if (!string.IsNullOrEmpty(filePath)) + return Path.Combine(Path.GetDirectoryName(filePath) ?? string.Empty, fileName); + + return null; + + static string GetPathFromAssembly(Assembly assembly) { - string resourceName = $"{nameof(LibreHardwareMonitor)}.Resources.{(Software.OperatingSystem.Is64Bit ? "inpoutx64.dll" : "inpout32.dll")}"; - - Assembly assembly = typeof(Ring0).Assembly; - - string[] names = assembly.GetManifestResourceNames(); - byte[] buffer = null; - - for (int i = 0; i < names.Length; i++) - { - if (names[i].Replace('\\', '.') == resourceName) - { - using Stream stream = assembly.GetManifestResourceStream(names[i]); - - if (stream != null) - { - buffer = new byte[stream.Length]; - stream.Read(buffer, 0, buffer.Length); - } - } - } - - if (buffer == null) - return false; - try { - using FileStream target = new(filePath, FileMode.Create); - - target.Write(buffer, 0, buffer.Length); - target.Flush(); + string location = assembly?.Location; + return !string.IsNullOrEmpty(location) ? location : null; } catch { - // for example there is not enough space on the disk - return false; + return null; } - - // make sure the file is actually written to the file system - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - while (stopwatch.ElapsedMilliseconds < 2000) - { - try - { - if (File.Exists(filePath) && new FileInfo(filePath).Length == buffer.Length) - return true; - } - catch - { } - - Thread.Sleep(1); - } - - // file still has not the right size, something is wrong - return false; } } + + private static bool Extract(string filePath) + { + string resourceName = $"{nameof(LibreHardwareMonitor)}.Resources.{(Software.OperatingSystem.Is64Bit ? "inpoutx64.dll" : "inpout32.dll")}"; + + Assembly assembly = typeof(Ring0).Assembly; + + string[] names = assembly.GetManifestResourceNames(); + byte[] buffer = null; + + for (int i = 0; i < names.Length; i++) + { + if (names[i].Replace('\\', '.') == resourceName) + { + using Stream stream = assembly.GetManifestResourceStream(names[i]); + + if (stream != null) + { + buffer = new byte[stream.Length]; + stream.Read(buffer, 0, buffer.Length); + } + } + } + + if (buffer == null) + return false; + + try + { + using FileStream target = new(filePath, FileMode.Create); + + target.Write(buffer, 0, buffer.Length); + target.Flush(); + } + catch + { + // for example there is not enough space on the disk + return false; + } + + // make sure the file is actually written to the file system + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (stopwatch.ElapsedMilliseconds < 2000) + { + try + { + if (File.Exists(filePath) && new FileInfo(filePath).Length == buffer.Length) + return true; + } + catch + { } + + Thread.Sleep(1); + } + + // file still has not the right size, something is wrong + return false; + } } diff --git a/LibreHardwareMonitorLib/Hardware/KernelDriver.cs b/LibreHardwareMonitorLib/Hardware/KernelDriver.cs index f19f433..801ea07 100644 --- a/LibreHardwareMonitorLib/Hardware/KernelDriver.cs +++ b/LibreHardwareMonitorLib/Hardware/KernelDriver.cs @@ -11,183 +11,182 @@ using System.Security.AccessControl; using LibreHardwareMonitor.Interop; using Microsoft.Win32.SafeHandles; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal class KernelDriver { - internal class KernelDriver + private readonly string _driverId; + private readonly string _serviceName; + private SafeFileHandle _device; + + public KernelDriver(string serviceName, string driverId) { - private readonly string _driverId; - private readonly string _serviceName; - private SafeFileHandle _device; + _serviceName = serviceName; + _driverId = driverId; + } - public KernelDriver(string serviceName, string driverId) + public bool IsOpen + { + get { return _device != null; } + } + + public bool Install(string path, out string errorMessage) + { + IntPtr manager = AdvApi32.OpenSCManager(null, null, AdvApi32.SC_MANAGER_ACCESS_MASK.SC_MANAGER_ALL_ACCESS); + if (manager == IntPtr.Zero) { - _serviceName = serviceName; - _driverId = driverId; + errorMessage = "OpenSCManager returned zero."; + return false; } - public bool IsOpen - { - get { return _device != null; } - } + IntPtr service = AdvApi32.CreateService(manager, + _serviceName, + _serviceName, + AdvApi32.SERVICE_ACCESS_MASK.SERVICE_ALL_ACCESS, + AdvApi32.SERVICE_TYPE.SERVICE_KERNEL_DRIVER, + AdvApi32.SERVICE_START.SERVICE_DEMAND_START, + AdvApi32.SERVICE_ERROR.SERVICE_ERROR_NORMAL, + path, + null, + null, + null, + null, + null); - public bool Install(string path, out string errorMessage) + if (service == IntPtr.Zero) { - IntPtr manager = AdvApi32.OpenSCManager(null, null, AdvApi32.SC_MANAGER_ACCESS_MASK.SC_MANAGER_ALL_ACCESS); - if (manager == IntPtr.Zero) + int error = Marshal.GetHRForLastWin32Error(); + if (error == Kernel32.ERROR_SERVICE_EXISTS) { - errorMessage = "OpenSCManager returned zero."; + errorMessage = "Service already exists"; return false; } - IntPtr service = AdvApi32.CreateService(manager, - _serviceName, - _serviceName, - AdvApi32.SERVICE_ACCESS_MASK.SERVICE_ALL_ACCESS, - AdvApi32.SERVICE_TYPE.SERVICE_KERNEL_DRIVER, - AdvApi32.SERVICE_START.SERVICE_DEMAND_START, - AdvApi32.SERVICE_ERROR.SERVICE_ERROR_NORMAL, - path, - null, - null, - null, - null, - null); + errorMessage = "CreateService returned the error: " + Marshal.GetExceptionForHR(error).Message; + AdvApi32.CloseServiceHandle(manager); + return false; + } - if (service == IntPtr.Zero) + if (!AdvApi32.StartService(service, 0, null)) + { + int error = Marshal.GetHRForLastWin32Error(); + if (error != Kernel32.ERROR_SERVICE_ALREADY_RUNNING) { - int error = Marshal.GetHRForLastWin32Error(); - if (error == Kernel32.ERROR_SERVICE_EXISTS) - { - errorMessage = "Service already exists"; - return false; - } - - errorMessage = "CreateService returned the error: " + Marshal.GetExceptionForHR(error).Message; + errorMessage = "StartService returned the error: " + Marshal.GetExceptionForHR(error).Message; + AdvApi32.CloseServiceHandle(service); AdvApi32.CloseServiceHandle(manager); return false; } - - if (!AdvApi32.StartService(service, 0, null)) - { - int error = Marshal.GetHRForLastWin32Error(); - if (error != Kernel32.ERROR_SERVICE_ALREADY_RUNNING) - { - errorMessage = "StartService returned the error: " + Marshal.GetExceptionForHR(error).Message; - AdvApi32.CloseServiceHandle(service); - AdvApi32.CloseServiceHandle(manager); - return false; - } - } - - AdvApi32.CloseServiceHandle(service); - AdvApi32.CloseServiceHandle(manager); - - try - { - // restrict the driver access to system (SY) and builtin admins (BA) - // TODO: replace with a call to IoCreateDeviceSecure in the driver - FileInfo fileInfo = new(@"\\.\" + _driverId); - FileSecurity fileSecurity = fileInfo.GetAccessControl(); - fileSecurity.SetSecurityDescriptorSddlForm("O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)"); - fileInfo.SetAccessControl(fileSecurity); - } - catch - { } - - errorMessage = null; - return true; } - public bool Open() - { - IntPtr fileHandle = Kernel32.CreateFile(@"\\.\" + _driverId, 0xC0000000, FileShare.None, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); - _device = new SafeFileHandle(fileHandle, true); - if (_device.IsInvalid) - { - _device.Close(); - _device.Dispose(); - _device = null; - } + AdvApi32.CloseServiceHandle(service); + AdvApi32.CloseServiceHandle(manager); - return _device != null; + try + { + // restrict the driver access to system (SY) and builtin admins (BA) + // TODO: replace with a call to IoCreateDeviceSecure in the driver + FileInfo fileInfo = new(@"\\.\" + _driverId); + FileSecurity fileSecurity = fileInfo.GetAccessControl(); + fileSecurity.SetSecurityDescriptorSddlForm("O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)"); + fileInfo.SetAccessControl(fileSecurity); + } + catch + { } + + errorMessage = null; + return true; + } + + public bool Open() + { + IntPtr fileHandle = Kernel32.CreateFile(@"\\.\" + _driverId, 0xC0000000, FileShare.None, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); + _device = new SafeFileHandle(fileHandle, true); + if (_device.IsInvalid) + { + _device.Close(); + _device.Dispose(); + _device = null; } - public bool DeviceIOControl(Kernel32.IOControlCode ioControlCode, object inBuffer) + return _device != null; + } + + public bool DeviceIOControl(Kernel32.IOControlCode ioControlCode, object inBuffer) + { + if (_device == null) + return false; + + return Kernel32.DeviceIoControl(_device, ioControlCode, inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), null, 0, out uint _, IntPtr.Zero); + } + + public bool DeviceIOControl(Kernel32.IOControlCode ioControlCode, object inBuffer, ref T outBuffer) + { + if (_device == null) + return false; + + object boxedOutBuffer = outBuffer; + bool b = Kernel32.DeviceIoControl(_device, + ioControlCode, + inBuffer, + inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), + boxedOutBuffer, + (uint)Marshal.SizeOf(boxedOutBuffer), + out uint _, + IntPtr.Zero); + + outBuffer = (T)boxedOutBuffer; + return b; + } + + public bool DeviceIOControl(Kernel32.IOControlCode ioControlCode, object inBuffer, ref T[] outBuffer) + { + if (_device == null) + return false; + + object boxedOutBuffer = outBuffer; + bool b = Kernel32.DeviceIoControl(_device, + ioControlCode, + inBuffer, + inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), + boxedOutBuffer, + (uint)(Marshal.SizeOf(typeof(T)) * outBuffer.Length), + out uint _, + IntPtr.Zero); + + outBuffer = (T[])boxedOutBuffer; + return b; + } + + public void Close() + { + if (_device != null) { - if (_device == null) - return false; - - return Kernel32.DeviceIoControl(_device, ioControlCode, inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), null, 0, out uint _, IntPtr.Zero); - } - - public bool DeviceIOControl(Kernel32.IOControlCode ioControlCode, object inBuffer, ref T outBuffer) - { - if (_device == null) - return false; - - object boxedOutBuffer = outBuffer; - bool b = Kernel32.DeviceIoControl(_device, - ioControlCode, - inBuffer, - inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), - boxedOutBuffer, - (uint)Marshal.SizeOf(boxedOutBuffer), - out uint _, - IntPtr.Zero); - - outBuffer = (T)boxedOutBuffer; - return b; - } - - public bool DeviceIOControl(Kernel32.IOControlCode ioControlCode, object inBuffer, ref T[] outBuffer) - { - if (_device == null) - return false; - - object boxedOutBuffer = outBuffer; - bool b = Kernel32.DeviceIoControl(_device, - ioControlCode, - inBuffer, - inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), - boxedOutBuffer, - (uint)(Marshal.SizeOf(typeof(T)) * outBuffer.Length), - out uint _, - IntPtr.Zero); - - outBuffer = (T[])boxedOutBuffer; - return b; - } - - public void Close() - { - if (_device != null) - { - _device.Close(); - _device.Dispose(); - _device = null; - } - } - - public bool Delete() - { - IntPtr manager = AdvApi32.OpenSCManager(null, null, AdvApi32.SC_MANAGER_ACCESS_MASK.SC_MANAGER_ALL_ACCESS); - if (manager == IntPtr.Zero) - return false; - - IntPtr service = AdvApi32.OpenService(manager, _serviceName, AdvApi32.SERVICE_ACCESS_MASK.SERVICE_ALL_ACCESS); - if (service == IntPtr.Zero) - { - AdvApi32.CloseServiceHandle(manager); - return true; - } - - AdvApi32.SERVICE_STATUS status = new(); - AdvApi32.ControlService(service, AdvApi32.SERVICE_CONTROL.SERVICE_CONTROL_STOP, ref status); - AdvApi32.DeleteService(service); - AdvApi32.CloseServiceHandle(service); - AdvApi32.CloseServiceHandle(manager); - - return true; + _device.Close(); + _device.Dispose(); + _device = null; } } -} + + public bool Delete() + { + IntPtr manager = AdvApi32.OpenSCManager(null, null, AdvApi32.SC_MANAGER_ACCESS_MASK.SC_MANAGER_ALL_ACCESS); + if (manager == IntPtr.Zero) + return false; + + IntPtr service = AdvApi32.OpenService(manager, _serviceName, AdvApi32.SERVICE_ACCESS_MASK.SERVICE_ALL_ACCESS); + if (service == IntPtr.Zero) + { + AdvApi32.CloseServiceHandle(manager); + return true; + } + + AdvApi32.SERVICE_STATUS status = new(); + AdvApi32.ControlService(service, AdvApi32.SERVICE_CONTROL.SERVICE_CONTROL_STOP, ref status); + AdvApi32.DeleteService(service); + AdvApi32.CloseServiceHandle(service); + AdvApi32.CloseServiceHandle(manager); + + return true; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Memory/GenericLinuxMemory.cs b/LibreHardwareMonitorLib/Hardware/Memory/GenericLinuxMemory.cs index 022c4c7..6c597f5 100644 --- a/LibreHardwareMonitorLib/Hardware/Memory/GenericLinuxMemory.cs +++ b/LibreHardwareMonitorLib/Hardware/Memory/GenericLinuxMemory.cs @@ -7,87 +7,86 @@ using System.IO; using System.Linq; -namespace LibreHardwareMonitor.Hardware.Memory +namespace LibreHardwareMonitor.Hardware.Memory; + +internal sealed class GenericLinuxMemory : Hardware { - internal sealed class GenericLinuxMemory : Hardware + private readonly Sensor _physicalMemoryAvailable; + private readonly Sensor _physicalMemoryLoad; + private readonly Sensor _physicalMemoryUsed; + private readonly Sensor _virtualMemoryAvailable; + private readonly Sensor _virtualMemoryLoad; + private readonly Sensor _virtualMemoryUsed; + + public override HardwareType HardwareType => HardwareType.Memory; + + public GenericLinuxMemory(string name, ISettings settings) : base(name, new Identifier("ram"), settings) { - private readonly Sensor _physicalMemoryAvailable; - private readonly Sensor _physicalMemoryLoad; - private readonly Sensor _physicalMemoryUsed; - private readonly Sensor _virtualMemoryAvailable; - private readonly Sensor _virtualMemoryLoad; - private readonly Sensor _virtualMemoryUsed; + _physicalMemoryUsed = new Sensor("Memory Used", 0, SensorType.Data, this, settings); + ActivateSensor(_physicalMemoryUsed); - public override HardwareType HardwareType => HardwareType.Memory; + _physicalMemoryAvailable = new Sensor("Memory Available", 1, SensorType.Data, this, settings); + ActivateSensor(_physicalMemoryAvailable); - public GenericLinuxMemory(string name, ISettings settings) : base(name, new Identifier("ram"), settings) + _physicalMemoryLoad = new Sensor("Memory", 0, SensorType.Load, this, settings); + ActivateSensor(_physicalMemoryLoad); + + _virtualMemoryUsed = new Sensor("Virtual Memory Used", 2, SensorType.Data, this, settings); + ActivateSensor(_virtualMemoryUsed); + + _virtualMemoryAvailable = new Sensor("Virtual Memory Available", 3, SensorType.Data, this, settings); + ActivateSensor(_virtualMemoryAvailable); + + _virtualMemoryLoad = new Sensor("Virtual Memory", 1, SensorType.Load, this, settings); + ActivateSensor(_virtualMemoryLoad); + } + + public override void Update() + { + try { - _physicalMemoryUsed = new Sensor("Memory Used", 0, SensorType.Data, this, settings); - ActivateSensor(_physicalMemoryUsed); + string[] memoryInfo = File.ReadAllLines("/proc/meminfo"); - _physicalMemoryAvailable = new Sensor("Memory Available", 1, SensorType.Data, this, settings); - ActivateSensor(_physicalMemoryAvailable); - - _physicalMemoryLoad = new Sensor("Memory", 0, SensorType.Load, this, settings); - ActivateSensor(_physicalMemoryLoad); - - _virtualMemoryUsed = new Sensor("Virtual Memory Used", 2, SensorType.Data, this, settings); - ActivateSensor(_virtualMemoryUsed); - - _virtualMemoryAvailable = new Sensor("Virtual Memory Available", 3, SensorType.Data, this, settings); - ActivateSensor(_virtualMemoryAvailable); - - _virtualMemoryLoad = new Sensor("Virtual Memory", 1, SensorType.Load, this, settings); - ActivateSensor(_virtualMemoryLoad); - } - - public override void Update() - { - try { - string[] memoryInfo = File.ReadAllLines("/proc/meminfo"); + float totalMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("MemTotal:"))) / 1024.0f / 1024.0f; + float freeMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("MemFree:"))) / 1024.0f / 1024.0f; + float cachedMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("Cached:"))) / 1024.0f / 1024.0f; - { - float totalMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("MemTotal:"))) / 1024.0f / 1024.0f; - float freeMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("MemFree:"))) / 1024.0f / 1024.0f; - float cachedMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("Cached:"))) / 1024.0f / 1024.0f; + float usedMemory_GB = totalMemory_GB - freeMemory_GB - cachedMemory_GB; - float usedMemory_GB = totalMemory_GB - freeMemory_GB - cachedMemory_GB; - - _physicalMemoryUsed.Value = usedMemory_GB; - _physicalMemoryAvailable.Value = totalMemory_GB; - _physicalMemoryLoad.Value = 100.0f * (usedMemory_GB / totalMemory_GB); - } - { - float totalSwapMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("SwapTotal"))) / 1024.0f / 1024.0f; - float freeSwapMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("SwapFree"))) / 1024.0f / 1024.0f; - float usedSwapMemory_GB = totalSwapMemory_GB - freeSwapMemory_GB; - - _virtualMemoryUsed.Value = usedSwapMemory_GB; - _virtualMemoryAvailable.Value = totalSwapMemory_GB; - _virtualMemoryLoad.Value = 100.0f * (usedSwapMemory_GB / totalSwapMemory_GB); - } + _physicalMemoryUsed.Value = usedMemory_GB; + _physicalMemoryAvailable.Value = totalMemory_GB; + _physicalMemoryLoad.Value = 100.0f * (usedMemory_GB / totalMemory_GB); } - catch { - _physicalMemoryUsed.Value = null; - _physicalMemoryAvailable.Value = null; - _physicalMemoryLoad.Value = null; + float totalSwapMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("SwapTotal"))) / 1024.0f / 1024.0f; + float freeSwapMemory_GB = GetMemInfoValue(memoryInfo.First(entry => entry.StartsWith("SwapFree"))) / 1024.0f / 1024.0f; + float usedSwapMemory_GB = totalSwapMemory_GB - freeSwapMemory_GB; - _virtualMemoryUsed.Value = null; - _virtualMemoryAvailable.Value = null; - _virtualMemoryLoad.Value = null; + _virtualMemoryUsed.Value = usedSwapMemory_GB; + _virtualMemoryAvailable.Value = totalSwapMemory_GB; + _virtualMemoryLoad.Value = 100.0f * (usedSwapMemory_GB / totalSwapMemory_GB); } } - - private static long GetMemInfoValue(string line) + catch { - // Example: "MemTotal: 32849676 kB" + _physicalMemoryUsed.Value = null; + _physicalMemoryAvailable.Value = null; + _physicalMemoryLoad.Value = null; - string valueWithUnit = line.Split(':').Skip(1).First().Trim(); - string valueAsString = valueWithUnit.Split(' ').First(); - - return long.Parse(valueAsString); + _virtualMemoryUsed.Value = null; + _virtualMemoryAvailable.Value = null; + _virtualMemoryLoad.Value = null; } } + + private static long GetMemInfoValue(string line) + { + // Example: "MemTotal: 32849676 kB" + + string valueWithUnit = line.Split(':').Skip(1).First().Trim(); + string valueAsString = valueWithUnit.Split(' ').First(); + + return long.Parse(valueAsString); + } } diff --git a/LibreHardwareMonitorLib/Hardware/Memory/GenericWindowsMemory.cs b/LibreHardwareMonitorLib/Hardware/Memory/GenericWindowsMemory.cs index 3cbc329..0d41066 100644 --- a/LibreHardwareMonitorLib/Hardware/Memory/GenericWindowsMemory.cs +++ b/LibreHardwareMonitorLib/Hardware/Memory/GenericWindowsMemory.cs @@ -7,57 +7,56 @@ using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Memory +namespace LibreHardwareMonitor.Hardware.Memory; + +internal sealed class GenericWindowsMemory : Hardware { - internal sealed class GenericWindowsMemory : Hardware + private readonly Sensor _physicalMemoryAvailable; + private readonly Sensor _physicalMemoryLoad; + private readonly Sensor _physicalMemoryUsed; + private readonly Sensor _virtualMemoryAvailable; + private readonly Sensor _virtualMemoryLoad; + private readonly Sensor _virtualMemoryUsed; + + public GenericWindowsMemory(string name, ISettings settings) : base(name, new Identifier("ram"), settings) { - private readonly Sensor _physicalMemoryAvailable; - private readonly Sensor _physicalMemoryLoad; - private readonly Sensor _physicalMemoryUsed; - private readonly Sensor _virtualMemoryAvailable; - private readonly Sensor _virtualMemoryLoad; - private readonly Sensor _virtualMemoryUsed; + _physicalMemoryUsed = new Sensor("Memory Used", 0, SensorType.Data, this, settings); + ActivateSensor(_physicalMemoryUsed); - public GenericWindowsMemory(string name, ISettings settings) : base(name, new Identifier("ram"), settings) - { - _physicalMemoryUsed = new Sensor("Memory Used", 0, SensorType.Data, this, settings); - ActivateSensor(_physicalMemoryUsed); + _physicalMemoryAvailable = new Sensor("Memory Available", 1, SensorType.Data, this, settings); + ActivateSensor(_physicalMemoryAvailable); - _physicalMemoryAvailable = new Sensor("Memory Available", 1, SensorType.Data, this, settings); - ActivateSensor(_physicalMemoryAvailable); + _physicalMemoryLoad = new Sensor("Memory", 0, SensorType.Load, this, settings); + ActivateSensor(_physicalMemoryLoad); - _physicalMemoryLoad = new Sensor("Memory", 0, SensorType.Load, this, settings); - ActivateSensor(_physicalMemoryLoad); + _virtualMemoryUsed = new Sensor("Virtual Memory Used", 2, SensorType.Data, this, settings); + ActivateSensor(_virtualMemoryUsed); - _virtualMemoryUsed = new Sensor("Virtual Memory Used", 2, SensorType.Data, this, settings); - ActivateSensor(_virtualMemoryUsed); + _virtualMemoryAvailable = new Sensor("Virtual Memory Available", 3, SensorType.Data, this, settings); + ActivateSensor(_virtualMemoryAvailable); - _virtualMemoryAvailable = new Sensor("Virtual Memory Available", 3, SensorType.Data, this, settings); - ActivateSensor(_virtualMemoryAvailable); - - _virtualMemoryLoad = new Sensor("Virtual Memory", 1, SensorType.Load, this, settings); - ActivateSensor(_virtualMemoryLoad); - } - - public override HardwareType HardwareType - { - get { return HardwareType.Memory; } - } - - public override void Update() - { - Kernel32.MEMORYSTATUSEX status = new() { dwLength = (uint)Marshal.SizeOf() }; - - if (!Kernel32.GlobalMemoryStatusEx(ref status)) - return; - - _physicalMemoryUsed.Value = (float)(status.ullTotalPhys - status.ullAvailPhys) / (1024 * 1024 * 1024); - _physicalMemoryAvailable.Value = (float)status.ullAvailPhys / (1024 * 1024 * 1024); - _physicalMemoryLoad.Value = 100.0f - ((100.0f * status.ullAvailPhys) / status.ullTotalPhys); - - _virtualMemoryUsed.Value = (float)(status.ullTotalPageFile - status.ullAvailPageFile) / (1024 * 1024 * 1024); - _virtualMemoryAvailable.Value = (float)status.ullAvailPageFile / (1024 * 1024 * 1024); - _virtualMemoryLoad.Value = 100.0f - ((100.0f * status.ullAvailPageFile) / status.ullTotalPageFile); - } + _virtualMemoryLoad = new Sensor("Virtual Memory", 1, SensorType.Load, this, settings); + ActivateSensor(_virtualMemoryLoad); } -} + + public override HardwareType HardwareType + { + get { return HardwareType.Memory; } + } + + public override void Update() + { + Kernel32.MEMORYSTATUSEX status = new() { dwLength = (uint)Marshal.SizeOf() }; + + if (!Kernel32.GlobalMemoryStatusEx(ref status)) + return; + + _physicalMemoryUsed.Value = (float)(status.ullTotalPhys - status.ullAvailPhys) / (1024 * 1024 * 1024); + _physicalMemoryAvailable.Value = (float)status.ullAvailPhys / (1024 * 1024 * 1024); + _physicalMemoryLoad.Value = 100.0f - ((100.0f * status.ullAvailPhys) / status.ullTotalPhys); + + _virtualMemoryUsed.Value = (float)(status.ullTotalPageFile - status.ullAvailPageFile) / (1024 * 1024 * 1024); + _virtualMemoryAvailable.Value = (float)status.ullAvailPageFile / (1024 * 1024 * 1024); + _virtualMemoryLoad.Value = 100.0f - ((100.0f * status.ullAvailPageFile) / status.ullTotalPageFile); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs b/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs index ce9cb6c..c437635 100644 --- a/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Memory/MemoryGroup.cs @@ -6,28 +6,27 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Memory +namespace LibreHardwareMonitor.Hardware.Memory; + +internal class MemoryGroup : IGroup { - internal class MemoryGroup : IGroup + private readonly Hardware[] _hardware; + + public MemoryGroup(ISettings settings) { - private readonly Hardware[] _hardware; + _hardware = new Hardware[] { Software.OperatingSystem.IsUnix ? new GenericLinuxMemory("Generic Memory", settings) : new GenericWindowsMemory("Generic Memory", settings) }; + } - public MemoryGroup(ISettings settings) - { - _hardware = new Hardware[] { Software.OperatingSystem.IsUnix ? new GenericLinuxMemory("Generic Memory", settings) : new GenericWindowsMemory("Generic Memory", settings) }; - } + public string GetReport() + { + return null; + } - public string GetReport() - { - return null; - } + public IReadOnlyList Hardware => _hardware; - public IReadOnlyList Hardware => _hardware; - - public void Close() - { - foreach (Hardware ram in _hardware) - ram.Close(); - } + public void Close() + { + foreach (Hardware ram in _hardware) + ram.Close(); } } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs index af7854d..d496544 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Identification.cs @@ -6,369 +6,368 @@ using System; -namespace LibreHardwareMonitor.Hardware.Motherboard -{ - internal class Identification - { - public static Manufacturer GetManufacturer(string name) - { - switch (name) - { - case var _ when name.IndexOf("abit.com.tw", StringComparison.OrdinalIgnoreCase) > -1: - return Manufacturer.Acer; - case var _ when name.StartsWith("Acer", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Acer; - case var _ when name.StartsWith("AMD", StringComparison.OrdinalIgnoreCase): - return Manufacturer.AMD; - case var _ when name.Equals("Alienware", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Alienware; - case var _ when name.StartsWith("AOpen", StringComparison.OrdinalIgnoreCase): - return Manufacturer.AOpen; - case var _ when name.StartsWith("Apple", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Apple; - case var _ when name.Equals("ASRock", StringComparison.OrdinalIgnoreCase): - return Manufacturer.ASRock; - case var _ when name.StartsWith("ASUSTeK", StringComparison.OrdinalIgnoreCase): - case var _ when name.StartsWith("ASUS ", StringComparison.OrdinalIgnoreCase): - return Manufacturer.ASUS; - case var _ when name.StartsWith("Biostar", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Biostar; - case var _ when name.StartsWith("Clevo", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Clevo; - case var _ when name.StartsWith("Dell", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Dell; - case var _ when name.Equals("DFI", StringComparison.OrdinalIgnoreCase): - case var _ when name.StartsWith("DFI Inc", StringComparison.OrdinalIgnoreCase): - return Manufacturer.DFI; - case var _ when name.Equals("ECS", StringComparison.OrdinalIgnoreCase): - case var _ when name.StartsWith("ELITEGROUP", StringComparison.OrdinalIgnoreCase): - return Manufacturer.ECS; - case var _ when name.Equals("EPoX COMPUTER CO., LTD", StringComparison.OrdinalIgnoreCase): - return Manufacturer.EPoX; - case var _ when name.StartsWith("EVGA", StringComparison.OrdinalIgnoreCase): - return Manufacturer.EVGA; - case var _ when name.Equals("FIC", StringComparison.OrdinalIgnoreCase): - case var _ when name.StartsWith("First International Computer", StringComparison.OrdinalIgnoreCase): - return Manufacturer.FIC; - case var _ when name.Equals("Foxconn", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Foxconn; - case var _ when name.StartsWith("Fujitsu", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Fujitsu; - case var _ when name.StartsWith("Gigabyte", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Gigabyte; - case var _ when name.StartsWith("Hewlett-Packard", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("HP", StringComparison.OrdinalIgnoreCase): - return Manufacturer.HP; - case var _ when name.Equals("IBM", StringComparison.OrdinalIgnoreCase): - return Manufacturer.IBM; - case var _ when name.Equals("Intel", StringComparison.OrdinalIgnoreCase): - case var _ when name.StartsWith("Intel Corp", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Intel; - case var _ when name.StartsWith("Jetway", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Jetway; - case var _ when name.StartsWith("Lenovo", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Lenovo; - case var _ when name.Equals("LattePanda", StringComparison.OrdinalIgnoreCase): - return Manufacturer.LattePanda; - case var _ when name.StartsWith("Medion", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Medion; - case var _ when name.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Microsoft; - case var _ when name.StartsWith("Micro-Star International", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("MSI", StringComparison.OrdinalIgnoreCase): - return Manufacturer.MSI; - case var _ when name.StartsWith("NEC ", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("NEC", StringComparison.OrdinalIgnoreCase): - return Manufacturer.NEC; - case var _ when name.StartsWith("Pegatron", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Pegatron; - case var _ when name.StartsWith("Samsung", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Samsung; - case var _ when name.StartsWith("Sapphire", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Sapphire; - case var _ when name.StartsWith("Shuttle", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Shuttle; - case var _ when name.StartsWith("Sony", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Sony; - case var _ when name.StartsWith("Supermicro", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Supermicro; - case var _ when name.StartsWith("Toshiba", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Toshiba; - case var _ when name.Equals("XFX", StringComparison.OrdinalIgnoreCase): - return Manufacturer.XFX; - case var _ when name.StartsWith("Zotac", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Zotac; - case var _ when name.Equals("To be filled by O.E.M.", StringComparison.OrdinalIgnoreCase): - return Manufacturer.Unknown; - default: - return Manufacturer.Unknown; - } - } +namespace LibreHardwareMonitor.Hardware.Motherboard; - public static Model GetModel(string name) +internal class Identification +{ + public static Manufacturer GetManufacturer(string name) + { + switch (name) { - switch (name) - { - case var _ when name.Equals("880GMH/USB3", StringComparison.OrdinalIgnoreCase): - return Model._880GMH_USB3; - case var _ when name.Equals("B85M-DGS", StringComparison.OrdinalIgnoreCase): - return Model.B85M_DGS; - case var _ when name.Equals("ASRock AOD790GX/128M", StringComparison.OrdinalIgnoreCase): - return Model.AOD790GX_128M; - case var _ when name.Equals("AB350 Pro4", StringComparison.OrdinalIgnoreCase): - return Model.AB350_Pro4; - case var _ when name.Equals("AB350M Pro4", StringComparison.OrdinalIgnoreCase): - return Model.AB350M_Pro4; - case var _ when name.Equals("AB350M", StringComparison.OrdinalIgnoreCase): - return Model.AB350M; - case var _ when name.Equals("B450 Steel Legend", StringComparison.OrdinalIgnoreCase): - return Model.B450_Steel_Legend; - case var _ when name.Equals("B450M Steel Legend", StringComparison.OrdinalIgnoreCase): - return Model.B450M_Steel_Legend; - case var _ when name.Equals("B450 Pro4", StringComparison.OrdinalIgnoreCase): - return Model.B450_Pro4; - case var _ when name.Equals("B450M Pro4", StringComparison.OrdinalIgnoreCase): - return Model.B450M_Pro4; - case var _ when name.Equals("Fatal1ty AB350 Gaming K4", StringComparison.OrdinalIgnoreCase): - return Model.Fatal1ty_AB350_Gaming_K4; - case var _ when name.Equals("AB350M-HDV", StringComparison.OrdinalIgnoreCase): - return Model.AB350M_HDV; - case var _ when name.Equals("X399 Phantom Gaming 6", StringComparison.OrdinalIgnoreCase): - return Model.X399_Phantom_Gaming_6; - case var _ when name.Equals("A320M-HDV", StringComparison.OrdinalIgnoreCase): - return Model.A320M_HDV; - case var _ when name.Equals("P55 Deluxe", StringComparison.OrdinalIgnoreCase): - return Model.P55_Deluxe; - case var _ when name.Equals("Crosshair III Formula", StringComparison.OrdinalIgnoreCase): - return Model.CROSSHAIR_III_FORMULA; - case var _ when name.Equals("ROG CROSSHAIR VIII HERO", StringComparison.OrdinalIgnoreCase): - return Model.ROG_CROSSHAIR_VIII_HERO; - case var _ when name.Equals("ROG CROSSHAIR VIII HERO (WI-FI)", StringComparison.OrdinalIgnoreCase): - return Model.ROG_CROSSHAIR_VIII_HERO_WIFI; - case var _ when name.Equals("ROG CROSSHAIR VIII DARK HERO", StringComparison.OrdinalIgnoreCase): - return Model.ROG_CROSSHAIR_VIII_DARK_HERO; - case var _ when name.Equals("ROG CROSSHAIR VIII FORMULA", StringComparison.OrdinalIgnoreCase): - return Model.ROG_CROSSHAIR_VIII_FORMULA; - case var _ when name.Equals("ROG CROSSHAIR VIII IMPACT", StringComparison.OrdinalIgnoreCase): - return Model.ROG_CROSSHAIR_VIII_IMPACT; - case var _ when name.Equals("M2N-SLI DELUXE", StringComparison.OrdinalIgnoreCase): - return Model.M2N_SLI_Deluxe; - case var _ when name.Equals("M4A79XTD EVO", StringComparison.OrdinalIgnoreCase): - return Model.M4A79XTD_EVO; - case var _ when name.Equals("P5W DH Deluxe", StringComparison.OrdinalIgnoreCase): - return Model.P5W_DH_Deluxe; - case var _ when name.Equals("P6T", StringComparison.OrdinalIgnoreCase): - return Model.P6T; - case var _ when name.Equals("P6X58D-E", StringComparison.OrdinalIgnoreCase): - return Model.P6X58D_E; - case var _ when name.Equals("P8P67", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("P8P67 REV 3.1", StringComparison.OrdinalIgnoreCase): - return Model.P8P67; - case var _ when name.Equals("P8P67 EVO", StringComparison.OrdinalIgnoreCase): - return Model.P8P67_EVO; - case var _ when name.Equals("P8P67 PRO", StringComparison.OrdinalIgnoreCase): - return Model.P8P67_PRO; - case var _ when name.Equals("P8P67-M PRO", StringComparison.OrdinalIgnoreCase): - return Model.P8P67_M_PRO; - case var _ when name.Equals("P8Z77-V", StringComparison.OrdinalIgnoreCase): - return Model.P8Z77_V; - case var _ when name.Equals("P9X79", StringComparison.OrdinalIgnoreCase): - return Model.P9X79; - case var _ when name.Equals("Rampage Extreme", StringComparison.OrdinalIgnoreCase): - return Model.RAMPAGE_EXTREME; - case var _ when name.Equals("Rampage II GENE", StringComparison.OrdinalIgnoreCase): - return Model.RAMPAGE_II_GENE; - case var _ when name.Equals("LP BI P45-T2RS Elite", StringComparison.OrdinalIgnoreCase): - return Model.LP_BI_P45_T2RS_Elite; - case var _ when name.Equals("ROG STRIX B550-F GAMING (WI-FI)", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_B550_F_GAMING_WIFI; - case var _ when name.Equals("ROG STRIX X470-I GAMING", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_X470_I; - case var _ when name.Equals("ROG STRIX B550-E GAMING", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_B550_E_GAMING; - case var _ when name.Equals("ROG STRIX B550-I GAMING", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_B550_I_GAMING; - case var _ when name.Equals("ROG STRIX X570-E GAMING", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_X570_E_GAMING; - case var _ when name.Equals("ROG STRIX X570-I GAMING", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_X570_I_GAMING; - case var _ when name.Equals("ROG STRIX X570-F GAMING", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_X570_F_GAMING; - case var _ when name.Equals("LP DK P55-T3eH9", StringComparison.OrdinalIgnoreCase): - return Model.LP_DK_P55_T3EH9; - case var _ when name.Equals("A890GXM-A", StringComparison.OrdinalIgnoreCase): - return Model.A890GXM_A; - case var _ when name.Equals("X58 SLI Classified", StringComparison.OrdinalIgnoreCase): - return Model.X58_SLI_Classified; - case var _ when name.Equals("965P-S3", StringComparison.OrdinalIgnoreCase): - return Model._965P_S3; - case var _ when name.Equals("EP45-DS3R", StringComparison.OrdinalIgnoreCase): - return Model.EP45_DS3R; - case var _ when name.Equals("EP45-UD3R", StringComparison.OrdinalIgnoreCase): - return Model.EP45_UD3R; - case var _ when name.Equals("EX58-EXTREME", StringComparison.OrdinalIgnoreCase): - return Model.EX58_EXTREME; - case var _ when name.Equals("EX58-UD3R", StringComparison.OrdinalIgnoreCase): - return Model.EX58_UD3R; - case var _ when name.Equals("G41M-Combo", StringComparison.OrdinalIgnoreCase): - return Model.G41M_COMBO; - case var _ when name.Equals("G41MT-S2", StringComparison.OrdinalIgnoreCase): - return Model.G41MT_S2; - case var _ when name.Equals("G41MT-S2P", StringComparison.OrdinalIgnoreCase): - return Model.G41MT_S2P; - case var _ when name.Equals("GA-970A-UD3", StringComparison.OrdinalIgnoreCase): - return Model._970A_UD3; - case var _ when name.Equals("GA-MA770T-UD3", StringComparison.OrdinalIgnoreCase): - return Model.MA770T_UD3; - case var _ when name.Equals("GA-MA770T-UD3P", StringComparison.OrdinalIgnoreCase): - return Model.MA770T_UD3P; - case var _ when name.Equals("GA-MA785GM-US2H", StringComparison.OrdinalIgnoreCase): - return Model.MA785GM_US2H; - case var _ when name.Equals("GA-MA785GMT-UD2H", StringComparison.OrdinalIgnoreCase): - return Model.MA785GMT_UD2H; - case var _ when name.Equals("GA-MA78LM-S2H", StringComparison.OrdinalIgnoreCase): - return Model.MA78LM_S2H; - case var _ when name.Equals("GA-MA790X-UD3P", StringComparison.OrdinalIgnoreCase): - return Model.MA790X_UD3P; - case var _ when name.Equals("H55-USB3", StringComparison.OrdinalIgnoreCase): - return Model.H55_USB3; - case var _ when name.Equals("H55N-USB3", StringComparison.OrdinalIgnoreCase): - return Model.H55N_USB3; - case var _ when name.Equals("H61M-DS2 REV 1.2", StringComparison.OrdinalIgnoreCase): - return Model.H61M_DS2_REV_1_2; - case var _ when name.Equals("H61M-USB3-B3 REV 2.0", StringComparison.OrdinalIgnoreCase): - return Model.H61M_USB3_B3_REV_2_0; - case var _ when name.Equals("H67A-UD3H-B3", StringComparison.OrdinalIgnoreCase): - return Model.H67A_UD3H_B3; - case var _ when name.Equals("H67A-USB3-B3", StringComparison.OrdinalIgnoreCase): - return Model.H67A_USB3_B3; - case var _ when name.Equals("H81M-HD3", StringComparison.OrdinalIgnoreCase): - return Model.H81M_HD3; - case var _ when name.Equals("P35-DS3", StringComparison.OrdinalIgnoreCase): - return Model.P35_DS3; - case var _ when name.Equals("P35-DS3L", StringComparison.OrdinalIgnoreCase): - return Model.P35_DS3L; - case var _ when name.Equals("P55-UD4", StringComparison.OrdinalIgnoreCase): - return Model.P55_UD4; - case var _ when name.Equals("P55A-UD3", StringComparison.OrdinalIgnoreCase): - return Model.P55A_UD3; - case var _ when name.Equals("P55M-UD4", StringComparison.OrdinalIgnoreCase): - return Model.P55M_UD4; - case var _ when name.Equals("P67A-UD3-B3", StringComparison.OrdinalIgnoreCase): - return Model.P67A_UD3_B3; - case var _ when name.Equals("P67A-UD3R-B3", StringComparison.OrdinalIgnoreCase): - return Model.P67A_UD3R_B3; - case var _ when name.Equals("P67A-UD4-B3", StringComparison.OrdinalIgnoreCase): - return Model.P67A_UD4_B3; - case var _ when name.Equals("P8Z68-V PRO", StringComparison.OrdinalIgnoreCase): - return Model.P8Z68_V_PRO; - case var _ when name.Equals("X38-DS5", StringComparison.OrdinalIgnoreCase): - return Model.X38_DS5; - case var _ when name.Equals("X58A-UD3R", StringComparison.OrdinalIgnoreCase): - return Model.X58A_UD3R; - case var _ when name.Equals("Z270 PC MATE", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("Z270 PC MATE (MS-7A72)", StringComparison.OrdinalIgnoreCase): - return Model.Z270_PC_MATE; - case var _ when name.Equals("X79-UD3", StringComparison.OrdinalIgnoreCase): - return Model.X79_UD3; - case var _ when name.Equals("Z68A-D3H-B3", StringComparison.OrdinalIgnoreCase): - return Model.Z68A_D3H_B3; - case var _ when name.Equals("Z68AP-D3", StringComparison.OrdinalIgnoreCase): - return Model.Z68AP_D3; - case var _ when name.Equals("Z68X-UD3H-B3", StringComparison.OrdinalIgnoreCase): - return Model.Z68X_UD3H_B3; - case var _ when name.Equals("Z68X-UD7-B3", StringComparison.OrdinalIgnoreCase): - return Model.Z68X_UD7_B3; - case var _ when name.Equals("Z68XP-UD3R", StringComparison.OrdinalIgnoreCase): - return Model.Z68XP_UD3R; - case var _ when name.Equals("Z170N-WIFI-CF", StringComparison.OrdinalIgnoreCase): - return Model.Z170N_WIFI; - case var _ when name.Equals("Z390 M GAMING-CF", StringComparison.OrdinalIgnoreCase): - return Model.Z390_M_GAMING; - case var _ when name.Equals("Z390 AORUS ULTRA", StringComparison.OrdinalIgnoreCase): - return Model.Z390_AORUS_ULTRA; - case var _ when name.Equals("Z390 AORUS PRO-CF", StringComparison.OrdinalIgnoreCase): - return Model.Z390_AORUS_PRO; - case var _ when name.Equals("Z390 UD", StringComparison.OrdinalIgnoreCase): - return Model.Z390_UD; - case var _ when name.Equals("Z690 AORUS PRO", StringComparison.OrdinalIgnoreCase): - return Model.Z690_AORUS_PRO; - case var _ when name.Equals("Z690 GAMING X DDR4", StringComparison.OrdinalIgnoreCase): - return Model.Z690_GAMING_X_DDR4; - case var _ when name.Equals("FH67", StringComparison.OrdinalIgnoreCase): - return Model.FH67; - case var _ when name.Equals("AX370-Gaming K7", StringComparison.OrdinalIgnoreCase): - return Model.AX370_Gaming_K7; - case var _ when name.Equals("PRIME X370-PRO", StringComparison.OrdinalIgnoreCase): - return Model.PRIME_X370_PRO; - case var _ when name.Equals("PRIME X470-PRO", StringComparison.OrdinalIgnoreCase): - return Model.PRIME_X470_PRO; - case var _ when name.Equals("PRIME X570-PRO", StringComparison.OrdinalIgnoreCase): - return Model.PRIME_X570_PRO; - case var _ when name.Equals("ProArt X570-CREATOR WIFI", StringComparison.OrdinalIgnoreCase): - return Model.PROART_X570_CREATOR_WIFI; - case var _ when name.Equals("Pro WS X570-ACE", StringComparison.OrdinalIgnoreCase): - return Model.PRO_WS_X570_ACE; - case var _ when name.Equals("ROG MAXIMUS X APEX", StringComparison.OrdinalIgnoreCase): - return Model.ROG_MAXIMUS_X_APEX; - case var _ when name.Equals("AB350-Gaming 3-CF", StringComparison.OrdinalIgnoreCase): - return Model.AB350_Gaming_3; - case var _ when name.Equals("X399 AORUS Gaming 7", StringComparison.OrdinalIgnoreCase): - return Model.X399_AORUS_Gaming_7; - case var _ when name.Equals("ROG ZENITH EXTREME", StringComparison.OrdinalIgnoreCase): - return Model.ROG_ZENITH_EXTREME; - case var _ when name.Equals("ROG ZENITH II EXTREME", StringComparison.OrdinalIgnoreCase): - return Model.ROG_ZENITH_II_EXTREME; - case var _ when name.Equals("Z170-A", StringComparison.OrdinalIgnoreCase): - return Model.Z170_A; - case var _ when name.Equals("Z77 Pro4-M", StringComparison.OrdinalIgnoreCase): - return Model.Z77Pro4M; - case var _ when name.Equals("X570 Pro4", StringComparison.OrdinalIgnoreCase): - return Model.X570_Pro4; - case var _ when name.Equals("X570 Taichi", StringComparison.OrdinalIgnoreCase): - return Model.X570_Taichi; - case var _ when name.Equals("X570 Phantom Gaming-ITX/TB3", StringComparison.OrdinalIgnoreCase): - return Model.X570_Phantom_Gaming_ITX; - case var _ when name.Equals("AX370-Gaming 5", StringComparison.OrdinalIgnoreCase): - return Model.AX370_Gaming_5; - case var _ when name.Equals("TUF X470-PLUS GAMING", StringComparison.OrdinalIgnoreCase): - return Model.TUF_X470_PLUS_GAMING; - case var _ when name.Equals("B360M PRO-VDH (MS-7B24)", StringComparison.OrdinalIgnoreCase): - return Model.B360M_PRO_VDH; - case var _ when name.Equals("B450-A PRO (MS-7B86)", StringComparison.OrdinalIgnoreCase): - return Model.B450A_PRO; - case var _ when name.Equals("B350 GAMING PLUS (MS-7A34)", StringComparison.OrdinalIgnoreCase): - return Model.B350_Gaming_Plus; - case var _ when name.Equals("X470 AORUS GAMING 7 WIFI-CF", StringComparison.OrdinalIgnoreCase): - return Model.X470_AORUS_GAMING_7_WIFI; - case var _ when name.Equals("X570 AORUS MASTER", StringComparison.OrdinalIgnoreCase): - return Model.X570_AORUS_MASTER; - case var _ when name.Equals("X570 AORUS ULTRA", StringComparison.OrdinalIgnoreCase): - return Model.X570_AORUS_ULTRA; - case var _ when name.Equals("X570 GAMING X", StringComparison.OrdinalIgnoreCase): - return Model.X570_GAMING_X; - case var _ when name.Equals("TUF GAMING B550M-PLUS (WI-FI)", StringComparison.OrdinalIgnoreCase): - return Model.TUF_GAMING_B550M_PLUS_WIFI; - case var _ when name.Equals("B360 AORUS GAMING 3 WIFI-CF", StringComparison.OrdinalIgnoreCase): - return Model.B360_AORUS_GAMING_3_WIFI_CF; - case var _ when name.Equals("B560M AORUS ELITE", StringComparison.OrdinalIgnoreCase): - return Model.B560M_AORUS_ELITE; - case var _ when name.Equals("B560M AORUS PRO", StringComparison.OrdinalIgnoreCase): - return Model.B560M_AORUS_PRO; - case var _ when name.Equals("B560M AORUS PRO AX", StringComparison.OrdinalIgnoreCase): - return Model.B560M_AORUS_PRO_AX; - case var _ when name.Equals("ROG STRIX Z690-A GAMING WIFI D4", StringComparison.OrdinalIgnoreCase): - return Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4; - case var _ when name.Equals("ROG MAXIMUS Z690 EXTREME GLACIAL", StringComparison.OrdinalIgnoreCase): - return Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL; - case var _ when name.Equals("B660GTN", StringComparison.OrdinalIgnoreCase): - return Model.B660GTN; - case var _ when name.Equals("Base Board Product Name", StringComparison.OrdinalIgnoreCase): - case var _ when name.Equals("To be filled by O.E.M.", StringComparison.OrdinalIgnoreCase): - return Model.Unknown; - default: - return Model.Unknown; - } + case var _ when name.IndexOf("abit.com.tw", StringComparison.OrdinalIgnoreCase) > -1: + return Manufacturer.Acer; + case var _ when name.StartsWith("Acer", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Acer; + case var _ when name.StartsWith("AMD", StringComparison.OrdinalIgnoreCase): + return Manufacturer.AMD; + case var _ when name.Equals("Alienware", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Alienware; + case var _ when name.StartsWith("AOpen", StringComparison.OrdinalIgnoreCase): + return Manufacturer.AOpen; + case var _ when name.StartsWith("Apple", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Apple; + case var _ when name.Equals("ASRock", StringComparison.OrdinalIgnoreCase): + return Manufacturer.ASRock; + case var _ when name.StartsWith("ASUSTeK", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("ASUS ", StringComparison.OrdinalIgnoreCase): + return Manufacturer.ASUS; + case var _ when name.StartsWith("Biostar", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Biostar; + case var _ when name.StartsWith("Clevo", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Clevo; + case var _ when name.StartsWith("Dell", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Dell; + case var _ when name.Equals("DFI", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("DFI Inc", StringComparison.OrdinalIgnoreCase): + return Manufacturer.DFI; + case var _ when name.Equals("ECS", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("ELITEGROUP", StringComparison.OrdinalIgnoreCase): + return Manufacturer.ECS; + case var _ when name.Equals("EPoX COMPUTER CO., LTD", StringComparison.OrdinalIgnoreCase): + return Manufacturer.EPoX; + case var _ when name.StartsWith("EVGA", StringComparison.OrdinalIgnoreCase): + return Manufacturer.EVGA; + case var _ when name.Equals("FIC", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("First International Computer", StringComparison.OrdinalIgnoreCase): + return Manufacturer.FIC; + case var _ when name.Equals("Foxconn", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Foxconn; + case var _ when name.StartsWith("Fujitsu", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Fujitsu; + case var _ when name.StartsWith("Gigabyte", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Gigabyte; + case var _ when name.StartsWith("Hewlett-Packard", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("HP", StringComparison.OrdinalIgnoreCase): + return Manufacturer.HP; + case var _ when name.Equals("IBM", StringComparison.OrdinalIgnoreCase): + return Manufacturer.IBM; + case var _ when name.Equals("Intel", StringComparison.OrdinalIgnoreCase): + case var _ when name.StartsWith("Intel Corp", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Intel; + case var _ when name.StartsWith("Jetway", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Jetway; + case var _ when name.StartsWith("Lenovo", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Lenovo; + case var _ when name.Equals("LattePanda", StringComparison.OrdinalIgnoreCase): + return Manufacturer.LattePanda; + case var _ when name.StartsWith("Medion", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Medion; + case var _ when name.StartsWith("Microsoft", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Microsoft; + case var _ when name.StartsWith("Micro-Star International", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("MSI", StringComparison.OrdinalIgnoreCase): + return Manufacturer.MSI; + case var _ when name.StartsWith("NEC ", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("NEC", StringComparison.OrdinalIgnoreCase): + return Manufacturer.NEC; + case var _ when name.StartsWith("Pegatron", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Pegatron; + case var _ when name.StartsWith("Samsung", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Samsung; + case var _ when name.StartsWith("Sapphire", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Sapphire; + case var _ when name.StartsWith("Shuttle", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Shuttle; + case var _ when name.StartsWith("Sony", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Sony; + case var _ when name.StartsWith("Supermicro", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Supermicro; + case var _ when name.StartsWith("Toshiba", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Toshiba; + case var _ when name.Equals("XFX", StringComparison.OrdinalIgnoreCase): + return Manufacturer.XFX; + case var _ when name.StartsWith("Zotac", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Zotac; + case var _ when name.Equals("To be filled by O.E.M.", StringComparison.OrdinalIgnoreCase): + return Manufacturer.Unknown; + default: + return Manufacturer.Unknown; } } -} + + public static Model GetModel(string name) + { + switch (name) + { + case var _ when name.Equals("880GMH/USB3", StringComparison.OrdinalIgnoreCase): + return Model._880GMH_USB3; + case var _ when name.Equals("B85M-DGS", StringComparison.OrdinalIgnoreCase): + return Model.B85M_DGS; + case var _ when name.Equals("ASRock AOD790GX/128M", StringComparison.OrdinalIgnoreCase): + return Model.AOD790GX_128M; + case var _ when name.Equals("AB350 Pro4", StringComparison.OrdinalIgnoreCase): + return Model.AB350_Pro4; + case var _ when name.Equals("AB350M Pro4", StringComparison.OrdinalIgnoreCase): + return Model.AB350M_Pro4; + case var _ when name.Equals("AB350M", StringComparison.OrdinalIgnoreCase): + return Model.AB350M; + case var _ when name.Equals("B450 Steel Legend", StringComparison.OrdinalIgnoreCase): + return Model.B450_Steel_Legend; + case var _ when name.Equals("B450M Steel Legend", StringComparison.OrdinalIgnoreCase): + return Model.B450M_Steel_Legend; + case var _ when name.Equals("B450 Pro4", StringComparison.OrdinalIgnoreCase): + return Model.B450_Pro4; + case var _ when name.Equals("B450M Pro4", StringComparison.OrdinalIgnoreCase): + return Model.B450M_Pro4; + case var _ when name.Equals("Fatal1ty AB350 Gaming K4", StringComparison.OrdinalIgnoreCase): + return Model.Fatal1ty_AB350_Gaming_K4; + case var _ when name.Equals("AB350M-HDV", StringComparison.OrdinalIgnoreCase): + return Model.AB350M_HDV; + case var _ when name.Equals("X399 Phantom Gaming 6", StringComparison.OrdinalIgnoreCase): + return Model.X399_Phantom_Gaming_6; + case var _ when name.Equals("A320M-HDV", StringComparison.OrdinalIgnoreCase): + return Model.A320M_HDV; + case var _ when name.Equals("P55 Deluxe", StringComparison.OrdinalIgnoreCase): + return Model.P55_Deluxe; + case var _ when name.Equals("Crosshair III Formula", StringComparison.OrdinalIgnoreCase): + return Model.CROSSHAIR_III_FORMULA; + case var _ when name.Equals("ROG CROSSHAIR VIII HERO", StringComparison.OrdinalIgnoreCase): + return Model.ROG_CROSSHAIR_VIII_HERO; + case var _ when name.Equals("ROG CROSSHAIR VIII HERO (WI-FI)", StringComparison.OrdinalIgnoreCase): + return Model.ROG_CROSSHAIR_VIII_HERO_WIFI; + case var _ when name.Equals("ROG CROSSHAIR VIII DARK HERO", StringComparison.OrdinalIgnoreCase): + return Model.ROG_CROSSHAIR_VIII_DARK_HERO; + case var _ when name.Equals("ROG CROSSHAIR VIII FORMULA", StringComparison.OrdinalIgnoreCase): + return Model.ROG_CROSSHAIR_VIII_FORMULA; + case var _ when name.Equals("ROG CROSSHAIR VIII IMPACT", StringComparison.OrdinalIgnoreCase): + return Model.ROG_CROSSHAIR_VIII_IMPACT; + case var _ when name.Equals("M2N-SLI DELUXE", StringComparison.OrdinalIgnoreCase): + return Model.M2N_SLI_Deluxe; + case var _ when name.Equals("M4A79XTD EVO", StringComparison.OrdinalIgnoreCase): + return Model.M4A79XTD_EVO; + case var _ when name.Equals("P5W DH Deluxe", StringComparison.OrdinalIgnoreCase): + return Model.P5W_DH_Deluxe; + case var _ when name.Equals("P6T", StringComparison.OrdinalIgnoreCase): + return Model.P6T; + case var _ when name.Equals("P6X58D-E", StringComparison.OrdinalIgnoreCase): + return Model.P6X58D_E; + case var _ when name.Equals("P8P67", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("P8P67 REV 3.1", StringComparison.OrdinalIgnoreCase): + return Model.P8P67; + case var _ when name.Equals("P8P67 EVO", StringComparison.OrdinalIgnoreCase): + return Model.P8P67_EVO; + case var _ when name.Equals("P8P67 PRO", StringComparison.OrdinalIgnoreCase): + return Model.P8P67_PRO; + case var _ when name.Equals("P8P67-M PRO", StringComparison.OrdinalIgnoreCase): + return Model.P8P67_M_PRO; + case var _ when name.Equals("P8Z77-V", StringComparison.OrdinalIgnoreCase): + return Model.P8Z77_V; + case var _ when name.Equals("P9X79", StringComparison.OrdinalIgnoreCase): + return Model.P9X79; + case var _ when name.Equals("Rampage Extreme", StringComparison.OrdinalIgnoreCase): + return Model.RAMPAGE_EXTREME; + case var _ when name.Equals("Rampage II GENE", StringComparison.OrdinalIgnoreCase): + return Model.RAMPAGE_II_GENE; + case var _ when name.Equals("LP BI P45-T2RS Elite", StringComparison.OrdinalIgnoreCase): + return Model.LP_BI_P45_T2RS_Elite; + case var _ when name.Equals("ROG STRIX B550-F GAMING (WI-FI)", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_B550_F_GAMING_WIFI; + case var _ when name.Equals("ROG STRIX X470-I GAMING", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_X470_I; + case var _ when name.Equals("ROG STRIX B550-E GAMING", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_B550_E_GAMING; + case var _ when name.Equals("ROG STRIX B550-I GAMING", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_B550_I_GAMING; + case var _ when name.Equals("ROG STRIX X570-E GAMING", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_X570_E_GAMING; + case var _ when name.Equals("ROG STRIX X570-I GAMING", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_X570_I_GAMING; + case var _ when name.Equals("ROG STRIX X570-F GAMING", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_X570_F_GAMING; + case var _ when name.Equals("LP DK P55-T3eH9", StringComparison.OrdinalIgnoreCase): + return Model.LP_DK_P55_T3EH9; + case var _ when name.Equals("A890GXM-A", StringComparison.OrdinalIgnoreCase): + return Model.A890GXM_A; + case var _ when name.Equals("X58 SLI Classified", StringComparison.OrdinalIgnoreCase): + return Model.X58_SLI_Classified; + case var _ when name.Equals("965P-S3", StringComparison.OrdinalIgnoreCase): + return Model._965P_S3; + case var _ when name.Equals("EP45-DS3R", StringComparison.OrdinalIgnoreCase): + return Model.EP45_DS3R; + case var _ when name.Equals("EP45-UD3R", StringComparison.OrdinalIgnoreCase): + return Model.EP45_UD3R; + case var _ when name.Equals("EX58-EXTREME", StringComparison.OrdinalIgnoreCase): + return Model.EX58_EXTREME; + case var _ when name.Equals("EX58-UD3R", StringComparison.OrdinalIgnoreCase): + return Model.EX58_UD3R; + case var _ when name.Equals("G41M-Combo", StringComparison.OrdinalIgnoreCase): + return Model.G41M_COMBO; + case var _ when name.Equals("G41MT-S2", StringComparison.OrdinalIgnoreCase): + return Model.G41MT_S2; + case var _ when name.Equals("G41MT-S2P", StringComparison.OrdinalIgnoreCase): + return Model.G41MT_S2P; + case var _ when name.Equals("GA-970A-UD3", StringComparison.OrdinalIgnoreCase): + return Model._970A_UD3; + case var _ when name.Equals("GA-MA770T-UD3", StringComparison.OrdinalIgnoreCase): + return Model.MA770T_UD3; + case var _ when name.Equals("GA-MA770T-UD3P", StringComparison.OrdinalIgnoreCase): + return Model.MA770T_UD3P; + case var _ when name.Equals("GA-MA785GM-US2H", StringComparison.OrdinalIgnoreCase): + return Model.MA785GM_US2H; + case var _ when name.Equals("GA-MA785GMT-UD2H", StringComparison.OrdinalIgnoreCase): + return Model.MA785GMT_UD2H; + case var _ when name.Equals("GA-MA78LM-S2H", StringComparison.OrdinalIgnoreCase): + return Model.MA78LM_S2H; + case var _ when name.Equals("GA-MA790X-UD3P", StringComparison.OrdinalIgnoreCase): + return Model.MA790X_UD3P; + case var _ when name.Equals("H55-USB3", StringComparison.OrdinalIgnoreCase): + return Model.H55_USB3; + case var _ when name.Equals("H55N-USB3", StringComparison.OrdinalIgnoreCase): + return Model.H55N_USB3; + case var _ when name.Equals("H61M-DS2 REV 1.2", StringComparison.OrdinalIgnoreCase): + return Model.H61M_DS2_REV_1_2; + case var _ when name.Equals("H61M-USB3-B3 REV 2.0", StringComparison.OrdinalIgnoreCase): + return Model.H61M_USB3_B3_REV_2_0; + case var _ when name.Equals("H67A-UD3H-B3", StringComparison.OrdinalIgnoreCase): + return Model.H67A_UD3H_B3; + case var _ when name.Equals("H67A-USB3-B3", StringComparison.OrdinalIgnoreCase): + return Model.H67A_USB3_B3; + case var _ when name.Equals("H81M-HD3", StringComparison.OrdinalIgnoreCase): + return Model.H81M_HD3; + case var _ when name.Equals("P35-DS3", StringComparison.OrdinalIgnoreCase): + return Model.P35_DS3; + case var _ when name.Equals("P35-DS3L", StringComparison.OrdinalIgnoreCase): + return Model.P35_DS3L; + case var _ when name.Equals("P55-UD4", StringComparison.OrdinalIgnoreCase): + return Model.P55_UD4; + case var _ when name.Equals("P55A-UD3", StringComparison.OrdinalIgnoreCase): + return Model.P55A_UD3; + case var _ when name.Equals("P55M-UD4", StringComparison.OrdinalIgnoreCase): + return Model.P55M_UD4; + case var _ when name.Equals("P67A-UD3-B3", StringComparison.OrdinalIgnoreCase): + return Model.P67A_UD3_B3; + case var _ when name.Equals("P67A-UD3R-B3", StringComparison.OrdinalIgnoreCase): + return Model.P67A_UD3R_B3; + case var _ when name.Equals("P67A-UD4-B3", StringComparison.OrdinalIgnoreCase): + return Model.P67A_UD4_B3; + case var _ when name.Equals("P8Z68-V PRO", StringComparison.OrdinalIgnoreCase): + return Model.P8Z68_V_PRO; + case var _ when name.Equals("X38-DS5", StringComparison.OrdinalIgnoreCase): + return Model.X38_DS5; + case var _ when name.Equals("X58A-UD3R", StringComparison.OrdinalIgnoreCase): + return Model.X58A_UD3R; + case var _ when name.Equals("Z270 PC MATE", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("Z270 PC MATE (MS-7A72)", StringComparison.OrdinalIgnoreCase): + return Model.Z270_PC_MATE; + case var _ when name.Equals("X79-UD3", StringComparison.OrdinalIgnoreCase): + return Model.X79_UD3; + case var _ when name.Equals("Z68A-D3H-B3", StringComparison.OrdinalIgnoreCase): + return Model.Z68A_D3H_B3; + case var _ when name.Equals("Z68AP-D3", StringComparison.OrdinalIgnoreCase): + return Model.Z68AP_D3; + case var _ when name.Equals("Z68X-UD3H-B3", StringComparison.OrdinalIgnoreCase): + return Model.Z68X_UD3H_B3; + case var _ when name.Equals("Z68X-UD7-B3", StringComparison.OrdinalIgnoreCase): + return Model.Z68X_UD7_B3; + case var _ when name.Equals("Z68XP-UD3R", StringComparison.OrdinalIgnoreCase): + return Model.Z68XP_UD3R; + case var _ when name.Equals("Z170N-WIFI-CF", StringComparison.OrdinalIgnoreCase): + return Model.Z170N_WIFI; + case var _ when name.Equals("Z390 M GAMING-CF", StringComparison.OrdinalIgnoreCase): + return Model.Z390_M_GAMING; + case var _ when name.Equals("Z390 AORUS ULTRA", StringComparison.OrdinalIgnoreCase): + return Model.Z390_AORUS_ULTRA; + case var _ when name.Equals("Z390 AORUS PRO-CF", StringComparison.OrdinalIgnoreCase): + return Model.Z390_AORUS_PRO; + case var _ when name.Equals("Z390 UD", StringComparison.OrdinalIgnoreCase): + return Model.Z390_UD; + case var _ when name.Equals("Z690 AORUS PRO", StringComparison.OrdinalIgnoreCase): + return Model.Z690_AORUS_PRO; + case var _ when name.Equals("Z690 GAMING X DDR4", StringComparison.OrdinalIgnoreCase): + return Model.Z690_GAMING_X_DDR4; + case var _ when name.Equals("FH67", StringComparison.OrdinalIgnoreCase): + return Model.FH67; + case var _ when name.Equals("AX370-Gaming K7", StringComparison.OrdinalIgnoreCase): + return Model.AX370_Gaming_K7; + case var _ when name.Equals("PRIME X370-PRO", StringComparison.OrdinalIgnoreCase): + return Model.PRIME_X370_PRO; + case var _ when name.Equals("PRIME X470-PRO", StringComparison.OrdinalIgnoreCase): + return Model.PRIME_X470_PRO; + case var _ when name.Equals("PRIME X570-PRO", StringComparison.OrdinalIgnoreCase): + return Model.PRIME_X570_PRO; + case var _ when name.Equals("ProArt X570-CREATOR WIFI", StringComparison.OrdinalIgnoreCase): + return Model.PROART_X570_CREATOR_WIFI; + case var _ when name.Equals("Pro WS X570-ACE", StringComparison.OrdinalIgnoreCase): + return Model.PRO_WS_X570_ACE; + case var _ when name.Equals("ROG MAXIMUS X APEX", StringComparison.OrdinalIgnoreCase): + return Model.ROG_MAXIMUS_X_APEX; + case var _ when name.Equals("AB350-Gaming 3-CF", StringComparison.OrdinalIgnoreCase): + return Model.AB350_Gaming_3; + case var _ when name.Equals("X399 AORUS Gaming 7", StringComparison.OrdinalIgnoreCase): + return Model.X399_AORUS_Gaming_7; + case var _ when name.Equals("ROG ZENITH EXTREME", StringComparison.OrdinalIgnoreCase): + return Model.ROG_ZENITH_EXTREME; + case var _ when name.Equals("ROG ZENITH II EXTREME", StringComparison.OrdinalIgnoreCase): + return Model.ROG_ZENITH_II_EXTREME; + case var _ when name.Equals("Z170-A", StringComparison.OrdinalIgnoreCase): + return Model.Z170_A; + case var _ when name.Equals("Z77 Pro4-M", StringComparison.OrdinalIgnoreCase): + return Model.Z77Pro4M; + case var _ when name.Equals("X570 Pro4", StringComparison.OrdinalIgnoreCase): + return Model.X570_Pro4; + case var _ when name.Equals("X570 Taichi", StringComparison.OrdinalIgnoreCase): + return Model.X570_Taichi; + case var _ when name.Equals("X570 Phantom Gaming-ITX/TB3", StringComparison.OrdinalIgnoreCase): + return Model.X570_Phantom_Gaming_ITX; + case var _ when name.Equals("AX370-Gaming 5", StringComparison.OrdinalIgnoreCase): + return Model.AX370_Gaming_5; + case var _ when name.Equals("TUF X470-PLUS GAMING", StringComparison.OrdinalIgnoreCase): + return Model.TUF_X470_PLUS_GAMING; + case var _ when name.Equals("B360M PRO-VDH (MS-7B24)", StringComparison.OrdinalIgnoreCase): + return Model.B360M_PRO_VDH; + case var _ when name.Equals("B450-A PRO (MS-7B86)", StringComparison.OrdinalIgnoreCase): + return Model.B450A_PRO; + case var _ when name.Equals("B350 GAMING PLUS (MS-7A34)", StringComparison.OrdinalIgnoreCase): + return Model.B350_Gaming_Plus; + case var _ when name.Equals("X470 AORUS GAMING 7 WIFI-CF", StringComparison.OrdinalIgnoreCase): + return Model.X470_AORUS_GAMING_7_WIFI; + case var _ when name.Equals("X570 AORUS MASTER", StringComparison.OrdinalIgnoreCase): + return Model.X570_AORUS_MASTER; + case var _ when name.Equals("X570 AORUS ULTRA", StringComparison.OrdinalIgnoreCase): + return Model.X570_AORUS_ULTRA; + case var _ when name.Equals("X570 GAMING X", StringComparison.OrdinalIgnoreCase): + return Model.X570_GAMING_X; + case var _ when name.Equals("TUF GAMING B550M-PLUS (WI-FI)", StringComparison.OrdinalIgnoreCase): + return Model.TUF_GAMING_B550M_PLUS_WIFI; + case var _ when name.Equals("B360 AORUS GAMING 3 WIFI-CF", StringComparison.OrdinalIgnoreCase): + return Model.B360_AORUS_GAMING_3_WIFI_CF; + case var _ when name.Equals("B560M AORUS ELITE", StringComparison.OrdinalIgnoreCase): + return Model.B560M_AORUS_ELITE; + case var _ when name.Equals("B560M AORUS PRO", StringComparison.OrdinalIgnoreCase): + return Model.B560M_AORUS_PRO; + case var _ when name.Equals("B560M AORUS PRO AX", StringComparison.OrdinalIgnoreCase): + return Model.B560M_AORUS_PRO_AX; + case var _ when name.Equals("ROG STRIX Z690-A GAMING WIFI D4", StringComparison.OrdinalIgnoreCase): + return Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4; + case var _ when name.Equals("ROG MAXIMUS Z690 EXTREME GLACIAL", StringComparison.OrdinalIgnoreCase): + return Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL; + case var _ when name.Equals("B660GTN", StringComparison.OrdinalIgnoreCase): + return Model.B660GTN; + case var _ when name.Equals("Base Board Product Name", StringComparison.OrdinalIgnoreCase): + case var _ when name.Equals("To be filled by O.E.M.", StringComparison.OrdinalIgnoreCase): + return Model.Unknown; + default: + return Model.Unknown; + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs index b6c5fb1..f09e9e9 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Chip.cs @@ -6,142 +6,141 @@ using System.Diagnostics.CodeAnalysis; -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +internal enum Chip : ushort { - [SuppressMessage("ReSharper", "InconsistentNaming")] - internal enum Chip : ushort + Unknown = 0, + + ATK0110 = 0x0110, + + F71808E = 0x0901, + F71811 = 0x1007, + F71858 = 0x0507, + F71862 = 0x0601, + F71869 = 0x0814, + F71869A = 0x1007, + F71878AD = 0x1106, + F71882 = 0x0541, + F71889AD = 0x1005, + F71889ED = 0x0909, + F71889F = 0x0723, + + IT8613E = 0x8613, + IT8620E = 0x8620, + IT8628E = 0x8628, + IT8631E = 0x8631, + IT8655E = 0x8655, + IT8665E = 0x8665, + IT8686E = 0x8686, + IT8688E = 0x8688, + IT8689E = 0x8689, + IT8695E = 0x8695, + IT8705F = 0x8705, + IT8712F = 0x8712, + IT8716F = 0x8716, + IT8718F = 0x8718, + IT8720F = 0x8720, + IT8721F = 0x8721, + IT8726F = 0x8726, + IT8728F = 0x8728, + IT8771E = 0x8771, + IT8772E = 0x8772, + IT879XE = 0x8733, + + NCT610XD = 0xC452, + NCT6771F = 0xB470, + NCT6776F = 0xC330, + NCT6779D = 0xC560, + NCT6791D = 0xC803, + NCT6792D = 0xC911, + NCT6792DA = 0xC913, + NCT6793D = 0xD121, + NCT6795D = 0xD352, + NCT6796D = 0xD423, + NCT6796DR = 0xD42A, + NCT6797D = 0xD451, + NCT6798D = 0xD42B, + NCT6687D = 0xD592, + NCT6683D = 0xc732, + + W83627DHG = 0xA020, + W83627DHGP = 0xB070, + W83627EHF = 0x8800, + W83627HF = 0x5200, + W83627THF = 0x8280, + W83667HG = 0xA510, + W83667HGB = 0xB350, + W83687THF = 0x8541 +} + +internal class ChipName +{ + public static string GetName(Chip chip) { - Unknown = 0, - - ATK0110 = 0x0110, - - F71808E = 0x0901, - F71811 = 0x1007, - F71858 = 0x0507, - F71862 = 0x0601, - F71869 = 0x0814, - F71869A = 0x1007, - F71878AD = 0x1106, - F71882 = 0x0541, - F71889AD = 0x1005, - F71889ED = 0x0909, - F71889F = 0x0723, - - IT8613E = 0x8613, - IT8620E = 0x8620, - IT8628E = 0x8628, - IT8631E = 0x8631, - IT8655E = 0x8655, - IT8665E = 0x8665, - IT8686E = 0x8686, - IT8688E = 0x8688, - IT8689E = 0x8689, - IT8695E = 0x8695, - IT8705F = 0x8705, - IT8712F = 0x8712, - IT8716F = 0x8716, - IT8718F = 0x8718, - IT8720F = 0x8720, - IT8721F = 0x8721, - IT8726F = 0x8726, - IT8728F = 0x8728, - IT8771E = 0x8771, - IT8772E = 0x8772, - IT879XE = 0x8733, - - NCT610XD = 0xC452, - NCT6771F = 0xB470, - NCT6776F = 0xC330, - NCT6779D = 0xC560, - NCT6791D = 0xC803, - NCT6792D = 0xC911, - NCT6792DA = 0xC913, - NCT6793D = 0xD121, - NCT6795D = 0xD352, - NCT6796D = 0xD423, - NCT6796DR = 0xD42A, - NCT6797D = 0xD451, - NCT6798D = 0xD42B, - NCT6687D = 0xD592, - NCT6683D = 0xc732, - - W83627DHG = 0xA020, - W83627DHGP = 0xB070, - W83627EHF = 0x8800, - W83627HF = 0x5200, - W83627THF = 0x8280, - W83667HG = 0xA510, - W83667HGB = 0xB350, - W83687THF = 0x8541 - } - - internal class ChipName - { - public static string GetName(Chip chip) + switch (chip) { - switch (chip) - { - case Chip.ATK0110: return "Asus ATK0110"; + case Chip.ATK0110: return "Asus ATK0110"; - case Chip.F71858: return "Fintek F71858"; - case Chip.F71862: return "Fintek F71862"; - case Chip.F71869: return "Fintek F71869"; - case Chip.F71878AD: return "Fintek F71878AD"; - case Chip.F71869A: return "Fintek F71869A/F71811"; - case Chip.F71882: return "Fintek F71882"; - case Chip.F71889AD: return "Fintek F71889AD"; - case Chip.F71889ED: return "Fintek F71889ED"; - case Chip.F71889F: return "Fintek F71889F"; - case Chip.F71808E: return "Fintek F71808E"; - case Chip.IT8613E: return "ITE IT8613E"; - case Chip.IT8620E: return "ITE IT8620E"; - case Chip.IT8628E: return "ITE IT8628E"; - case Chip.IT8631E: return "ITE IT8631E"; - case Chip.IT8655E: return "ITE IT8655E"; - case Chip.IT8665E: return "ITE IT8665E"; - case Chip.IT8686E: return "ITE IT8686E"; - case Chip.IT8688E: return "ITE IT8688E"; - case Chip.IT8689E: return "ITE IT8689E"; - case Chip.IT8695E: return "ITE IT8695E"; - case Chip.IT8705F: return "ITE IT8705F"; - case Chip.IT8712F: return "ITE IT8712F"; - case Chip.IT8716F: return "ITE IT8716F"; - case Chip.IT8718F: return "ITE IT8718F"; - case Chip.IT8720F: return "ITE IT8720F"; - case Chip.IT8721F: return "ITE IT8721F"; - case Chip.IT8726F: return "ITE IT8726F"; - case Chip.IT8728F: return "ITE IT8728F"; - case Chip.IT8771E: return "ITE IT8771E"; - case Chip.IT8772E: return "ITE IT8772E"; - case Chip.IT879XE: return "ITE IT8792E/IT8795E"; + case Chip.F71858: return "Fintek F71858"; + case Chip.F71862: return "Fintek F71862"; + case Chip.F71869: return "Fintek F71869"; + case Chip.F71878AD: return "Fintek F71878AD"; + case Chip.F71869A: return "Fintek F71869A/F71811"; + case Chip.F71882: return "Fintek F71882"; + case Chip.F71889AD: return "Fintek F71889AD"; + case Chip.F71889ED: return "Fintek F71889ED"; + case Chip.F71889F: return "Fintek F71889F"; + case Chip.F71808E: return "Fintek F71808E"; + case Chip.IT8613E: return "ITE IT8613E"; + case Chip.IT8620E: return "ITE IT8620E"; + case Chip.IT8628E: return "ITE IT8628E"; + case Chip.IT8631E: return "ITE IT8631E"; + case Chip.IT8655E: return "ITE IT8655E"; + case Chip.IT8665E: return "ITE IT8665E"; + case Chip.IT8686E: return "ITE IT8686E"; + case Chip.IT8688E: return "ITE IT8688E"; + case Chip.IT8689E: return "ITE IT8689E"; + case Chip.IT8695E: return "ITE IT8695E"; + case Chip.IT8705F: return "ITE IT8705F"; + case Chip.IT8712F: return "ITE IT8712F"; + case Chip.IT8716F: return "ITE IT8716F"; + case Chip.IT8718F: return "ITE IT8718F"; + case Chip.IT8720F: return "ITE IT8720F"; + case Chip.IT8721F: return "ITE IT8721F"; + case Chip.IT8726F: return "ITE IT8726F"; + case Chip.IT8728F: return "ITE IT8728F"; + case Chip.IT8771E: return "ITE IT8771E"; + case Chip.IT8772E: return "ITE IT8772E"; + case Chip.IT879XE: return "ITE IT8792E/IT8795E"; - case Chip.NCT610XD: return "Nuvoton NCT6102D/NCT6104D/NCT6106D"; - case Chip.NCT6771F: return "Nuvoton NCT6771F"; - case Chip.NCT6776F: return "Nuvoton NCT6776F"; - case Chip.NCT6779D: return "Nuvoton NCT6779D"; - case Chip.NCT6791D: return "Nuvoton NCT6791D"; - case Chip.NCT6792D: return "Nuvoton NCT6792D"; - case Chip.NCT6792DA: return "Nuvoton NCT6792D-A"; - case Chip.NCT6793D: return "Nuvoton NCT6793D"; - case Chip.NCT6795D: return "Nuvoton NCT6795D"; - case Chip.NCT6796D: return "Nuvoton NCT6796D"; - case Chip.NCT6796DR: return "Nuvoton NCT6796D-R"; - case Chip.NCT6797D: return "Nuvoton NCT6797D"; - case Chip.NCT6798D: return "Nuvoton NCT6798D"; - case Chip.NCT6687D: return "Nuvoton NCT6687D"; - case Chip.NCT6683D: return "Nuvoton NCT6683D"; + case Chip.NCT610XD: return "Nuvoton NCT6102D/NCT6104D/NCT6106D"; + case Chip.NCT6771F: return "Nuvoton NCT6771F"; + case Chip.NCT6776F: return "Nuvoton NCT6776F"; + case Chip.NCT6779D: return "Nuvoton NCT6779D"; + case Chip.NCT6791D: return "Nuvoton NCT6791D"; + case Chip.NCT6792D: return "Nuvoton NCT6792D"; + case Chip.NCT6792DA: return "Nuvoton NCT6792D-A"; + case Chip.NCT6793D: return "Nuvoton NCT6793D"; + case Chip.NCT6795D: return "Nuvoton NCT6795D"; + case Chip.NCT6796D: return "Nuvoton NCT6796D"; + case Chip.NCT6796DR: return "Nuvoton NCT6796D-R"; + case Chip.NCT6797D: return "Nuvoton NCT6797D"; + case Chip.NCT6798D: return "Nuvoton NCT6798D"; + case Chip.NCT6687D: return "Nuvoton NCT6687D"; + case Chip.NCT6683D: return "Nuvoton NCT6683D"; - case Chip.W83627DHG: return "Winbond W83627DHG"; - case Chip.W83627DHGP: return "Winbond W83627DHG-P"; - case Chip.W83627EHF: return "Winbond W83627EHF"; - case Chip.W83627HF: return "Winbond W83627HF"; - case Chip.W83627THF: return "Winbond W83627THF"; - case Chip.W83667HG: return "Winbond W83667HG"; - case Chip.W83667HGB: return "Winbond W83667HG-B"; - case Chip.W83687THF: return "Winbond W83687THF"; + case Chip.W83627DHG: return "Winbond W83627DHG"; + case Chip.W83627DHGP: return "Winbond W83627DHG-P"; + case Chip.W83627EHF: return "Winbond W83627EHF"; + case Chip.W83627HF: return "Winbond W83627HF"; + case Chip.W83627THF: return "Winbond W83627THF"; + case Chip.W83667HG: return "Winbond W83667HG"; + case Chip.W83667HGB: return "Winbond W83667HG-B"; + case Chip.W83687THF: return "Winbond W83687THF"; - default: return "Unknown"; - } + default: return "Unknown"; } } } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs index 75bd9cd..35edd55 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedController.cs @@ -9,455 +9,454 @@ using System.Globalization; using System.Linq; using System.Text; -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC; + +public abstract class EmbeddedController : Hardware { - public abstract class EmbeddedController : Hardware + // If you are updating board information, please consider sharing your changes with the corresponding Linux driver. + // You can do that at https://github.com/zeule/asus-ec-sensors or contribute directly to Linux HWMON. + // If you are adding a new board, please share DSDT table for the board at https://github.com/zeule/asus-ec-sensors. + // https://dortania.github.io/Getting-Started-With-ACPI/Manual/dump.html + private static readonly BoardInfo[] _boards = + { + new(Model.PRIME_X470_PRO, + BoardFamily.Amd400, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempVrm, + ECSensor.TempVrm, + ECSensor.FanCPUOpt, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(Model.PRIME_X570_PRO, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempVrm, + ECSensor.TempTSensor, + ECSensor.FanChipset), + new(Model.PROART_X570_CREATOR_WIFI, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempVrm, + ECSensor.TempTSensor, + ECSensor.FanCPUOpt, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(Model.PRO_WS_X570_ACE, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempVrm, + ECSensor.FanChipset, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(new[] { Model.ROG_CROSSHAIR_VIII_HERO, Model.ROG_CROSSHAIR_VIII_HERO_WIFI, Model.ROG_CROSSHAIR_VIII_FORMULA }, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempTSensor, + ECSensor.TempVrm, + ECSensor.TempWaterIn, + ECSensor.TempWaterOut, + ECSensor.FanCPUOpt, + ECSensor.FanChipset, + ECSensor.FanWaterFlow, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(Model.ROG_CROSSHAIR_VIII_DARK_HERO, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempTSensor, + ECSensor.TempVrm, + ECSensor.TempWaterIn, + ECSensor.TempWaterOut, + ECSensor.FanCPUOpt, + ECSensor.FanWaterFlow, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(Model.ROG_CROSSHAIR_VIII_IMPACT, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempTSensor, + ECSensor.TempVrm, + ECSensor.FanChipset, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(Model.ROG_STRIX_B550_E_GAMING, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempTSensor, + ECSensor.TempVrm, + ECSensor.FanCPUOpt), + new(Model.ROG_STRIX_B550_I_GAMING, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempTSensor, + ECSensor.TempVrm, + ECSensor.FanVrmHS, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(Model.ROG_STRIX_X570_E_GAMING, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempTSensor, + ECSensor.TempVrm, + ECSensor.FanChipset, + ECSensor.CurrCPU, + ECSensor.VoltageCPU), + new(Model.ROG_STRIX_X570_F_GAMING, + BoardFamily.Amd500, + ECSensor.TempChipset, + ECSensor.TempCPU, + ECSensor.TempMB, + ECSensor.TempTSensor, + ECSensor.FanChipset), + new(Model.ROG_STRIX_X570_I_GAMING, + BoardFamily.Amd500, + ECSensor.TempTSensor, + ECSensor.FanVrmHS, + ECSensor.FanChipset, + ECSensor.CurrCPU, + ECSensor.VoltageCPU, + ECSensor.TempChipset, + ECSensor.TempVrm), + new(Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4, + BoardFamily.Intel600, + ECSensor.TempTSensor, + ECSensor.TempVrm), + new(Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL, + BoardFamily.Intel600, + ECSensor.TempVrm, + ECSensor.TempWaterIn, + ECSensor.TempWaterOut, + ECSensor.TempWaterBlockIn, + ECSensor.FanWaterFlow), + new(Model.Z170_A, + BoardFamily.Intel100, + ECSensor.TempTSensor, + ECSensor.TempChipset, + ECSensor.FanWaterPump, + ECSensor.CurrCPU, + ECSensor.VoltageCPU) + }; + + private static readonly Dictionary> _knownSensors = new() { - // If you are updating board information, please consider sharing your changes with the corresponding Linux driver. - // You can do that at https://github.com/zeule/asus-ec-sensors or contribute directly to Linux HWMON. - // If you are adding a new board, please share DSDT table for the board at https://github.com/zeule/asus-ec-sensors. - // https://dortania.github.io/Getting-Started-With-ACPI/Manual/dump.html - private static readonly BoardInfo[] _boards = { - new(Model.PRIME_X470_PRO, - BoardFamily.Amd400, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempVrm, - ECSensor.TempVrm, - ECSensor.FanCPUOpt, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(Model.PRIME_X570_PRO, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempVrm, - ECSensor.TempTSensor, - ECSensor.FanChipset), - new(Model.PROART_X570_CREATOR_WIFI, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempVrm, - ECSensor.TempTSensor, - ECSensor.FanCPUOpt, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(Model.PRO_WS_X570_ACE, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempVrm, - ECSensor.FanChipset, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(new[] { Model.ROG_CROSSHAIR_VIII_HERO, Model.ROG_CROSSHAIR_VIII_HERO_WIFI, Model.ROG_CROSSHAIR_VIII_FORMULA }, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempTSensor, - ECSensor.TempVrm, - ECSensor.TempWaterIn, - ECSensor.TempWaterOut, - ECSensor.FanCPUOpt, - ECSensor.FanChipset, - ECSensor.FanWaterFlow, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(Model.ROG_CROSSHAIR_VIII_DARK_HERO, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempTSensor, - ECSensor.TempVrm, - ECSensor.TempWaterIn, - ECSensor.TempWaterOut, - ECSensor.FanCPUOpt, - ECSensor.FanWaterFlow, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(Model.ROG_CROSSHAIR_VIII_IMPACT, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempTSensor, - ECSensor.TempVrm, - ECSensor.FanChipset, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(Model.ROG_STRIX_B550_E_GAMING, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempTSensor, - ECSensor.TempVrm, - ECSensor.FanCPUOpt), - new(Model.ROG_STRIX_B550_I_GAMING, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempTSensor, - ECSensor.TempVrm, - ECSensor.FanVrmHS, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(Model.ROG_STRIX_X570_E_GAMING, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempTSensor, - ECSensor.TempVrm, - ECSensor.FanChipset, - ECSensor.CurrCPU, - ECSensor.VoltageCPU), - new(Model.ROG_STRIX_X570_F_GAMING, - BoardFamily.Amd500, - ECSensor.TempChipset, - ECSensor.TempCPU, - ECSensor.TempMB, - ECSensor.TempTSensor, - ECSensor.FanChipset), - new(Model.ROG_STRIX_X570_I_GAMING, - BoardFamily.Amd500, - ECSensor.TempTSensor, - ECSensor.FanVrmHS, - ECSensor.FanChipset, - ECSensor.CurrCPU, - ECSensor.VoltageCPU, - ECSensor.TempChipset, - ECSensor.TempVrm), - new(Model.ROG_STRIX_Z690_A_GAMING_WIFI_D4, - BoardFamily.Intel600, - ECSensor.TempTSensor, - ECSensor.TempVrm), - new(Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL, - BoardFamily.Intel600, - ECSensor.TempVrm, - ECSensor.TempWaterIn, - ECSensor.TempWaterOut, - ECSensor.TempWaterBlockIn, - ECSensor.FanWaterFlow), - new(Model.Z170_A, - BoardFamily.Intel100, - ECSensor.TempTSensor, - ECSensor.TempChipset, - ECSensor.FanWaterPump, - ECSensor.CurrCPU, - ECSensor.VoltageCPU) - }; - - private static readonly Dictionary> _knownSensors = new() + BoardFamily.Amd400, new Dictionary() // no chipset fans in this generation + { + { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, + { ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) }, + { ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) }, + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, + { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }, + { ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00bc, 2) }, + { ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) }, + { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00b4, 2, factor: 1.0f / 42f * 60f) }, + { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, + { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x010d, blank: -40) }, + { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x010b, blank: -40) } + } + }, { + BoardFamily.Amd500, new Dictionary { - BoardFamily.Amd400, new Dictionary() // no chipset fans in this generation - { - { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, - { ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) }, - { ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) }, - { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, - { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, - { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }, - { ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00bc, 2) }, - { ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) }, - { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00b4, 2, factor: 1.0f / 42f * 60f) }, - { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, - { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x010d, blank: -40) }, - { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x010b, blank: -40) } - } - }, - { - BoardFamily.Amd500, new Dictionary - { - { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, - { ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) }, - { ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) }, - { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, - { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, - { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }, - { ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) }, - { ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) }, - { ECSensor.FanChipset, new EmbeddedControllerSource("Chipset Fan", SensorType.Fan, 0x00b4, 2) }, - // TODO: "why 42?" is a silly question, I know, but still, why? On the serious side, it might be 41.6(6) - { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00bc, 2, factor: 1.0f / 42f * 60f) }, - { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, - { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) }, - { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) } - } - }, - { - BoardFamily.Intel100, new Dictionary - { - { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, - { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, - { ECSensor.FanWaterPump, new EmbeddedControllerSource("Water Pump", SensorType.Fan, 0x00bc, 2) }, - { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, - { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) } - } - }, - { - BoardFamily.Intel600, new Dictionary - { - { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, - { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, - { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) }, - { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }, - { ECSensor.TempWaterBlockIn, new EmbeddedControllerSource("Water Block In", SensorType.Temperature, 0x0102, blank: -40) }, - { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) } // todo: need validation for this calculation - } + { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, + { ECSensor.TempCPU, new EmbeddedControllerSource("CPU", SensorType.Temperature, 0x003b) }, + { ECSensor.TempMB, new EmbeddedControllerSource("Motherboard", SensorType.Temperature, 0x003c) }, + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, + { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) }, + { ECSensor.FanCPUOpt, new EmbeddedControllerSource("CPU Optional Fan", SensorType.Fan, 0x00b0, 2) }, + { ECSensor.FanVrmHS, new EmbeddedControllerSource("VRM Heat Sink Fan", SensorType.Fan, 0x00b2, 2) }, + { ECSensor.FanChipset, new EmbeddedControllerSource("Chipset Fan", SensorType.Fan, 0x00b4, 2) }, + // TODO: "why 42?" is a silly question, I know, but still, why? On the serious side, it might be 41.6(6) + { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water flow", SensorType.Flow, 0x00bc, 2, factor: 1.0f / 42f * 60f) }, + { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, + { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) }, + { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) } } - }; - - private readonly byte[] _data; - private readonly ushort[] _registers; - private readonly List _sensors; - - private readonly IReadOnlyList _sources; - - protected EmbeddedController(IEnumerable sources, ISettings settings) : base("Embedded Controller", new Identifier("lpc", "ec"), settings) + }, { - // sorting by address, which implies sorting by bank, for optimized EC access - var sourcesList = sources.ToList(); - sourcesList.Sort((left, right) => left.Register.CompareTo(right.Register)); - _sources = sourcesList; - var indices = new Dictionary(); - foreach (SensorType t in Enum.GetValues(typeof(SensorType))) + BoardFamily.Intel100, new Dictionary { - indices.Add(t, 0); + { ECSensor.TempChipset, new EmbeddedControllerSource("Chipset", SensorType.Temperature, 0x003a) }, + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.FanWaterPump, new EmbeddedControllerSource("Water Pump", SensorType.Fan, 0x00bc, 2) }, + { ECSensor.CurrCPU, new EmbeddedControllerSource("CPU", SensorType.Current, 0x00f4) }, + { ECSensor.VoltageCPU, new EmbeddedControllerSource("CPU Core", SensorType.Voltage, 0x00a2, 2, factor: 1e-3f) } } - - _sensors = new List(); - List registers = new(); - foreach (EmbeddedControllerSource s in _sources) + }, + { + BoardFamily.Intel600, new Dictionary { - int index = indices[s.Type]; - indices[s.Type] = index + 1; - _sensors.Add(new Sensor(s.Name, index, s.Type, this, settings)); - for (int i = 0; i < s.Size; ++i) - { - registers.Add((ushort)(s.Register + i)); - } - - ActivateSensor(_sensors[_sensors.Count - 1]); + { ECSensor.TempTSensor, new EmbeddedControllerSource("T Sensor", SensorType.Temperature, 0x003d, blank: -40) }, + { ECSensor.TempVrm, new EmbeddedControllerSource("VRM", SensorType.Temperature, 0x003e) }, + { ECSensor.TempWaterIn, new EmbeddedControllerSource("Water In", SensorType.Temperature, 0x0100, blank: -40) }, + { ECSensor.TempWaterOut, new EmbeddedControllerSource("Water Out", SensorType.Temperature, 0x0101, blank: -40) }, + { ECSensor.TempWaterBlockIn, new EmbeddedControllerSource("Water Block In", SensorType.Temperature, 0x0102, blank: -40) }, + { ECSensor.FanWaterFlow, new EmbeddedControllerSource("Water Flow", SensorType.Flow, 0x00be, 2, factor: 1.0f / 42f * 60f) } // todo: need validation for this calculation } + } + }; - _registers = registers.ToArray(); - _data = new byte[_registers.Length]; + private readonly byte[] _data; + private readonly ushort[] _registers; + private readonly List _sensors; + + private readonly IReadOnlyList _sources; + + protected EmbeddedController(IEnumerable sources, ISettings settings) : base("Embedded Controller", new Identifier("lpc", "ec"), settings) + { + // sorting by address, which implies sorting by bank, for optimized EC access + var sourcesList = sources.ToList(); + sourcesList.Sort((left, right) => left.Register.CompareTo(right.Register)); + _sources = sourcesList; + var indices = new Dictionary(); + foreach (SensorType t in Enum.GetValues(typeof(SensorType))) + { + indices.Add(t, 0); } - public override HardwareType HardwareType => HardwareType.EmbeddedController; - - internal static EmbeddedController Create(Model model, ISettings settings) + _sensors = new List(); + List registers = new(); + foreach (EmbeddedControllerSource s in _sources) { - var boards = _boards.Where(b => b.Models.Contains(model)).ToList(); - switch (boards.Count) + int index = indices[s.Type]; + indices[s.Type] = index + 1; + _sensors.Add(new Sensor(s.Name, index, s.Type, this, settings)); + for (int i = 0; i < s.Size; ++i) { - case 0: - return null; - case > 1: - throw new MultipleBoardRecordsFoundException(model.ToString()); + registers.Add((ushort)(s.Register + i)); } - BoardInfo board = boards[0]; - IEnumerable sources = board.Sensors.Select(ecs => _knownSensors[board.Family][ecs]); + ActivateSensor(_sensors[_sensors.Count - 1]); + } - return Environment.OSVersion.Platform switch + _registers = registers.ToArray(); + _data = new byte[_registers.Length]; + } + + public override HardwareType HardwareType => HardwareType.EmbeddedController; + + internal static EmbeddedController Create(Model model, ISettings settings) + { + var boards = _boards.Where(b => b.Models.Contains(model)).ToList(); + switch (boards.Count) + { + case 0: + return null; + case > 1: + throw new MultipleBoardRecordsFoundException(model.ToString()); + } + + BoardInfo board = boards[0]; + IEnumerable sources = board.Sensors.Select(ecs => _knownSensors[board.Family][ecs]); + + return Environment.OSVersion.Platform switch + { + PlatformID.Win32NT => new WindowsEmbeddedController(sources, settings), + _ => null + }; + } + + public override void Update() + { + if (!TryUpdateData()) + { + // just skip this update cycle? + return; + } + + int readRegister = 0; + for (int si = 0; si < _sensors.Count; ++si) + { + int val = _sources[si].Size switch { - PlatformID.Win32NT => new WindowsEmbeddedController(sources, settings), - _ => null + 1 => unchecked((sbyte)_data[readRegister]), + 2 => unchecked((short)((_data[readRegister] << 8) + _data[readRegister + 1])), + _ => 0 }; - } - public override void Update() - { - if (!TryUpdateData()) - { - // just skip this update cycle? - return; - } + readRegister += _sources[si].Size; - int readRegister = 0; - for (int si = 0; si < _sensors.Count; ++si) - { - int val = _sources[si].Size switch - { - 1 => unchecked((sbyte)_data[readRegister]), - 2 => unchecked((short)((_data[readRegister] << 8) + _data[readRegister + 1])), - _ => 0 - }; - - readRegister += _sources[si].Size; - - _sensors[si].Value = val != _sources[si].Blank ? val * _sources[si].Factor : null; - } - } - - public override string GetReport() - { - StringBuilder r = new(); - - r.AppendLine("EC " + GetType().Name); - r.AppendLine("Embedded Controller Registers"); - r.AppendLine(); - r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - r.AppendLine(); - - try - { - using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface(); - ushort[] src = new ushort[0x100]; - byte[] data = new byte[0x100]; - for (ushort i = 0; i < src.Length; ++i) - { - src[i] = i; - } - - embeddedControllerIO.Read(src, data); - for (int i = 0; i <= 0xF; ++i) - { - r.Append(" "); - r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); - r.Append(" "); - for (int j = 0; j <= 0xF; ++j) - { - byte address = (byte)(i << 4 | j); - r.Append(" "); - r.Append(data[address].ToString("X2", CultureInfo.InvariantCulture)); - } - - r.AppendLine(); - } - } - catch (IOException e) - { - r.AppendLine(e.Message); - } - - return r.ToString(); - } - - protected abstract IEmbeddedControllerIO AcquireIOInterface(); - - private bool TryUpdateData() - { - try - { - using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface(); - embeddedControllerIO.Read(_registers, _data); - return true; - } - catch (IOException) - { - return false; - } - } - - private enum ECSensor - { - /// Chipset temperature [℃] - TempChipset, - - /// CPU temperature [℃] - TempCPU, - - /// motherboard temperature [℃] - TempMB, - - /// "T_Sensor" temperature sensor reading [℃] - TempTSensor, - - /// VRM temperature [℃] - TempVrm, - - /// CPU Core voltage [mV] - VoltageCPU, - - /// CPU_Opt fan [RPM] - FanCPUOpt, - - /// VRM heat sink fan [RPM] - FanVrmHS, - - /// Chipset fan [RPM] - FanChipset, - - /// Water Pump [RPM] - FanWaterPump, - - /// Water flow sensor reading [RPM] - FanWaterFlow, - - /// CPU current [A] - CurrCPU, - - /// "Water_In" temperature sensor reading [℃] - TempWaterIn, - - /// "Water_Out" temperature sensor reading [℃] - TempWaterOut, - - /// Water block temperature sensor reading [℃] - TempWaterBlockIn, - Max - } - - private enum BoardFamily - { - Amd400, - Amd500, - Intel100, - Intel600 - } - - private struct BoardInfo - { - public BoardInfo(Model[] models, BoardFamily family, params ECSensor[] sensors) - { - Models = models; - Family = family; - Sensors = sensors; - } - - public BoardInfo(Model model, BoardFamily family, params ECSensor[] sensors) - { - Models = new[] { model }; - Family = family; - Sensors = sensors; - } - - public Model[] Models { get; } - - public BoardFamily Family { get; } - - public ECSensor[] Sensors { get; } - } - - public class IOException : System.IO.IOException - { - public IOException(string message) : base($"ACPI embedded controller I/O error: {message}") - { } - } - - public class BadConfigurationException : Exception - { - public BadConfigurationException(string message) : base(message) - { } - } - - public class MultipleBoardRecordsFoundException : BadConfigurationException - { - public MultipleBoardRecordsFoundException(string model) : base($"Multiple board records refer to the same model '{model}'") - { } + _sensors[si].Value = val != _sources[si].Blank ? val * _sources[si].Factor : null; } } + + public override string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("EC " + GetType().Name); + r.AppendLine("Embedded Controller Registers"); + r.AppendLine(); + r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); + r.AppendLine(); + + try + { + using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface(); + ushort[] src = new ushort[0x100]; + byte[] data = new byte[0x100]; + for (ushort i = 0; i < src.Length; ++i) + { + src[i] = i; + } + + embeddedControllerIO.Read(src, data); + for (int i = 0; i <= 0xF; ++i) + { + r.Append(" "); + r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); + r.Append(" "); + for (int j = 0; j <= 0xF; ++j) + { + byte address = (byte)(i << 4 | j); + r.Append(" "); + r.Append(data[address].ToString("X2", CultureInfo.InvariantCulture)); + } + + r.AppendLine(); + } + } + catch (IOException e) + { + r.AppendLine(e.Message); + } + + return r.ToString(); + } + + protected abstract IEmbeddedControllerIO AcquireIOInterface(); + + private bool TryUpdateData() + { + try + { + using IEmbeddedControllerIO embeddedControllerIO = AcquireIOInterface(); + embeddedControllerIO.Read(_registers, _data); + return true; + } + catch (IOException) + { + return false; + } + } + + private enum ECSensor + { + /// Chipset temperature [℃] + TempChipset, + + /// CPU temperature [℃] + TempCPU, + + /// motherboard temperature [℃] + TempMB, + + /// "T_Sensor" temperature sensor reading [℃] + TempTSensor, + + /// VRM temperature [℃] + TempVrm, + + /// CPU Core voltage [mV] + VoltageCPU, + + /// CPU_Opt fan [RPM] + FanCPUOpt, + + /// VRM heat sink fan [RPM] + FanVrmHS, + + /// Chipset fan [RPM] + FanChipset, + + /// Water Pump [RPM] + FanWaterPump, + + /// Water flow sensor reading [RPM] + FanWaterFlow, + + /// CPU current [A] + CurrCPU, + + /// "Water_In" temperature sensor reading [℃] + TempWaterIn, + + /// "Water_Out" temperature sensor reading [℃] + TempWaterOut, + + /// Water block temperature sensor reading [℃] + TempWaterBlockIn, + Max + } + + private enum BoardFamily + { + Amd400, + Amd500, + Intel100, + Intel600 + } + + private struct BoardInfo + { + public BoardInfo(Model[] models, BoardFamily family, params ECSensor[] sensors) + { + Models = models; + Family = family; + Sensors = sensors; + } + + public BoardInfo(Model model, BoardFamily family, params ECSensor[] sensors) + { + Models = new[] { model }; + Family = family; + Sensors = sensors; + } + + public Model[] Models { get; } + + public BoardFamily Family { get; } + + public ECSensor[] Sensors { get; } + } + + public class IOException : System.IO.IOException + { + public IOException(string message) : base($"ACPI embedded controller I/O error: {message}") + { } + } + + public class BadConfigurationException : Exception + { + public BadConfigurationException(string message) : base(message) + { } + } + + public class MultipleBoardRecordsFoundException : BadConfigurationException + { + public MultipleBoardRecordsFoundException(string model) : base($"Multiple board records refer to the same model '{model}'") + { } + } } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerReader.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerReader.cs index 344980c..3fdc311 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerReader.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerReader.cs @@ -3,7 +3,6 @@ // Copyright (C) LibreHardwareMonitor and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC -{ - public delegate float EmbeddedControllerReader(IEmbeddedControllerIO ecIO, ushort register); -} +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC; + +public delegate float EmbeddedControllerReader(IEmbeddedControllerIO ecIO, ushort register); \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerSource.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerSource.cs index a605bd2..bd0574a 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerSource.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/EmbeddedControllerSource.cs @@ -3,30 +3,29 @@ // Copyright (C) LibreHardwareMonitor and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC; + +public class EmbeddedControllerSource { - public class EmbeddedControllerSource + public EmbeddedControllerSource(string name, SensorType type, ushort register, byte size = 1, float factor = 1.0f, int blank = int.MaxValue) { - public EmbeddedControllerSource(string name, SensorType type, ushort register, byte size = 1, float factor = 1.0f, int blank = int.MaxValue) - { - Name = name; + Name = name; - Register = register; - Size = size; - Type = type; - Factor = factor; - Blank = blank; - } - - public string Name { get; } - public ushort Register { get; } - public byte Size { get; } - public float Factor { get; } - - public int Blank { get; } - - public EmbeddedControllerReader Reader { get; } - - public SensorType Type { get; } + Register = register; + Size = size; + Type = type; + Factor = factor; + Blank = blank; } -} + + public string Name { get; } + public ushort Register { get; } + public byte Size { get; } + public float Factor { get; } + + public int Blank { get; } + + public EmbeddedControllerReader Reader { get; } + + public SensorType Type { get; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/IEmbeddedControllerIO.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/IEmbeddedControllerIO.cs index 3149b6b..2d535b0 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/IEmbeddedControllerIO.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/IEmbeddedControllerIO.cs @@ -5,10 +5,9 @@ using System; -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC; + +public interface IEmbeddedControllerIO : IDisposable { - public interface IEmbeddedControllerIO : IDisposable - { - void Read(ushort[] registers, byte[] data); - } -} + void Read(ushort[] registers, byte[] data); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedController.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedController.cs index a49bf6e..206bcf0 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedController.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedController.cs @@ -5,16 +5,15 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC -{ - public class WindowsEmbeddedController : EmbeddedController - { - public WindowsEmbeddedController(IEnumerable sources, ISettings settings) : base(sources, settings) - { } +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC; - protected override IEmbeddedControllerIO AcquireIOInterface() - { - return new WindowsEmbeddedControllerIO(); - } +public class WindowsEmbeddedController : EmbeddedController +{ + public WindowsEmbeddedController(IEnumerable sources, ISettings settings) : base(sources, settings) + { } + + protected override IEmbeddedControllerIO AcquireIOInterface() + { + return new WindowsEmbeddedControllerIO(); } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedControllerIO.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedControllerIO.cs index 5295429..4939f1c 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedControllerIO.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/EC/WindowsEmbeddedControllerIO.cs @@ -7,243 +7,242 @@ using System; using System.Diagnostics; using System.Threading; -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC; + +/// +/// An unsafe but universal implementation for the ACPI Embedded Controller IO interface for Windows +/// +/// +/// It is unsafe because of possible race condition between this application and the PC firmware when +/// writing to the EC registers. For a safe approach ACPI/WMI methods have to be used, but those are +/// different for each motherboard model. +/// +public class WindowsEmbeddedControllerIO : IEmbeddedControllerIO { - /// - /// An unsafe but universal implementation for the ACPI Embedded Controller IO interface for Windows - /// - /// - /// It is unsafe because of possible race condition between this application and the PC firmware when - /// writing to the EC registers. For a safe approach ACPI/WMI methods have to be used, but those are - /// different for each motherboard model. - /// - public class WindowsEmbeddedControllerIO : IEmbeddedControllerIO + private const int FailuresBeforeSkip = 20; + private const int MaxRetries = 5; + + // implementation + private const int WaitSpins = 50; + private bool _disposed; + + private int _waitReadFailures; + + public WindowsEmbeddedControllerIO() { - private const int FailuresBeforeSkip = 20; - private const int MaxRetries = 5; - - // implementation - private const int WaitSpins = 50; - private bool _disposed; - - private int _waitReadFailures; - - public WindowsEmbeddedControllerIO() + if (!Ring0.WaitEcMutex(10)) { - if (!Ring0.WaitEcMutex(10)) + throw new BusMutexLockingFailedException(); + } + } + + public void Read(ushort[] registers, byte[] data) + { + Trace.Assert(registers.Length <= data.Length, + "data buffer length has to be greater or equal to the registers array length"); + + byte bank = 0; + byte prevBank = SwitchBank(bank); + + // oops... somebody else is working with the EC too + Trace.WriteLineIf(prevBank != 0, "Concurrent access to the ACPI EC detected.\nRace condition possible."); + + // read registers minimizing bank switches. + for (int i = 0; i < registers.Length; i++) + { + byte regBank = (byte)(registers[i] >> 8); + byte regIndex = (byte)(registers[i] & 0xFF); + // registers are sorted by bank + if (regBank > bank) { - throw new BusMutexLockingFailedException(); + bank = SwitchBank(regBank); + } + data[i] = ReadByte(regIndex); + } + + SwitchBank(prevBank); + } + + private byte ReadByte(byte register) + { + return ReadLoop(register, ReadByteOp); + } + + private void WriteByte(byte register, byte value) + { + WriteLoop(register, value, WriteByteOp); + } + + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + Ring0.ReleaseEcMutex(); + } + } + + private byte SwitchBank(byte bank) + { + byte previous = ReadByte(0xFF); + WriteByte(0xFF, bank); + return previous; + } + + private TResult ReadLoop(byte register, ReadOp op) where TResult : new() + { + TResult result = new(); + + for (int i = 0; i < MaxRetries; i++) + { + if (op(register, out result)) + { + return result; } } - public void Read(ushort[] registers, byte[] data) + return result; + } + + private void WriteLoop(byte register, TValue value, WriteOp op) + { + for (int i = 0; i < MaxRetries; i++) { - Trace.Assert(registers.Length <= data.Length, - "data buffer length has to be greater or equal to the registers array length"); - - byte bank = 0; - byte prevBank = SwitchBank(bank); - - // oops... somebody else is working with the EC too - Trace.WriteLineIf(prevBank != 0, "Concurrent access to the ACPI EC detected.\nRace condition possible."); - - // read registers minimizing bank switches. - for (int i = 0; i < registers.Length; i++) + if (op(register, value)) { - byte regBank = (byte)(registers[i] >> 8); - byte regIndex = (byte)(registers[i] & 0xFF); - // registers are sorted by bank - if (regBank > bank) - { - bank = SwitchBank(regBank); - } - data[i] = ReadByte(regIndex); - } - - SwitchBank(prevBank); - } - - private byte ReadByte(byte register) - { - return ReadLoop(register, ReadByteOp); - } - - private void WriteByte(byte register, byte value) - { - WriteLoop(register, value, WriteByteOp); - } - - public void Dispose() - { - if (!_disposed) - { - _disposed = true; - Ring0.ReleaseEcMutex(); - } - } - - private byte SwitchBank(byte bank) - { - byte previous = ReadByte(0xFF); - WriteByte(0xFF, bank); - return previous; - } - - private TResult ReadLoop(byte register, ReadOp op) where TResult : new() - { - TResult result = new(); - - for (int i = 0; i < MaxRetries; i++) - { - if (op(register, out result)) - { - return result; - } - } - - return result; - } - - private void WriteLoop(byte register, TValue value, WriteOp op) - { - for (int i = 0; i < MaxRetries; i++) - { - if (op(register, value)) - { - return; - } - } - } - - private bool WaitForStatus(Status status, bool isSet) - { - for (int i = 0; i < WaitSpins; i++) - { - byte value = ReadIOPort(Port.Command); - - if (((byte)status & (!isSet ? value : (byte)~value)) == 0) + return; + } + } + } + + private bool WaitForStatus(Status status, bool isSet) + { + for (int i = 0; i < WaitSpins; i++) + { + byte value = ReadIOPort(Port.Command); + + if (((byte)status & (!isSet ? value : (byte)~value)) == 0) + { + return true; + } + + Thread.Sleep(1); + } + + return false; + } + + private bool WaitRead() + { + if (_waitReadFailures > FailuresBeforeSkip) + { + return true; + } + + if (WaitForStatus(Status.OutputBufferFull, true)) + { + _waitReadFailures = 0; + return true; + } + + _waitReadFailures++; + return false; + } + + private bool WaitWrite() + { + return WaitForStatus(Status.InputBufferFull, false); + } + + private byte ReadIOPort(Port port) + { + return Ring0.ReadIoPort((uint)port); + } + + private void WriteIOPort(Port port, byte datum) + { + Ring0.WriteIoPort((uint)port, datum); + } + + public class BusMutexLockingFailedException : EmbeddedController.IOException + { + public BusMutexLockingFailedException() + : base("could not lock ISA bus mutex") + { } + } + + private delegate bool ReadOp(byte register, out TParam p); + + private delegate bool WriteOp(byte register, TParam p); + + // see the ACPI specification chapter 12 + private enum Port : byte + { + Command = 0x66, + Data = 0x62 + } + + private enum Command : byte + { + Read = 0x80, // RD_EC + Write = 0x81, // WR_EC + BurstEnable = 0x82, // BE_EC + BurstDisable = 0x83, // BD_EC + Query = 0x84 // QR_EC + } + + private enum Status : byte + { + OutputBufferFull = 0x01, // EC_OBF + InputBufferFull = 0x02, // EC_IBF + Command = 0x08, // CMD + BurstMode = 0x10, // BURST + SciEventPending = 0x20, // SCI_EVT + SmiEventPending = 0x40 // SMI_EVT + } + + #region Read/Write ops + + protected bool ReadByteOp(byte register, out byte value) + { + if (WaitWrite()) + { + WriteIOPort(Port.Command, (byte)Command.Read); + + if (WaitWrite()) + { + WriteIOPort(Port.Data, register); + + if (WaitWrite() && WaitRead()) { + value = ReadIOPort(Port.Data); return true; } - - Thread.Sleep(1); } - - return false; } - private bool WaitRead() - { - if (_waitReadFailures > FailuresBeforeSkip) - { - return true; - } - - if (WaitForStatus(Status.OutputBufferFull, true)) - { - _waitReadFailures = 0; - return true; - } - - _waitReadFailures++; - return false; - } - - private bool WaitWrite() - { - return WaitForStatus(Status.InputBufferFull, false); - } - - private byte ReadIOPort(Port port) - { - return Ring0.ReadIoPort((uint)port); - } - - private void WriteIOPort(Port port, byte datum) - { - Ring0.WriteIoPort((uint)port, datum); - } - - public class BusMutexLockingFailedException : EmbeddedController.IOException - { - public BusMutexLockingFailedException() - : base("could not lock ISA bus mutex") - { } - } - - private delegate bool ReadOp(byte register, out TParam p); - - private delegate bool WriteOp(byte register, TParam p); - - // see the ACPI specification chapter 12 - private enum Port : byte - { - Command = 0x66, - Data = 0x62 - } - - private enum Command : byte - { - Read = 0x80, // RD_EC - Write = 0x81, // WR_EC - BurstEnable = 0x82, // BE_EC - BurstDisable = 0x83, // BD_EC - Query = 0x84 // QR_EC - } - - private enum Status : byte - { - OutputBufferFull = 0x01, // EC_OBF - InputBufferFull = 0x02, // EC_IBF - Command = 0x08, // CMD - BurstMode = 0x10, // BURST - SciEventPending = 0x20, // SCI_EVT - SmiEventPending = 0x40 // SMI_EVT - } - -#region Read/Write ops - - protected bool ReadByteOp(byte register, out byte value) - { - if (WaitWrite()) - { - WriteIOPort(Port.Command, (byte)Command.Read); - - if (WaitWrite()) - { - WriteIOPort(Port.Data, register); - - if (WaitWrite() && WaitRead()) - { - value = ReadIOPort(Port.Data); - return true; - } - } - } - - value = 0; - return false; - } - - protected bool WriteByteOp(byte register, byte value) - { - if (WaitWrite()) - { - WriteIOPort(Port.Command, (byte)Command.Write); - if (WaitWrite()) - { - WriteIOPort(Port.Data, register); - if (WaitWrite()) - { - WriteIOPort(Port.Data, value); - return true; - } - } - } - - return false; - } - -#endregion + value = 0; + return false; } -} + + protected bool WriteByteOp(byte register, byte value) + { + if (WaitWrite()) + { + WriteIOPort(Port.Command, (byte)Command.Write); + if (WaitWrite()) + { + WriteIOPort(Port.Data, register); + if (WaitWrite()) + { + WriteIOPort(Port.Data, value); + return true; + } + } + } + + return false; + } + + #endregion +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/F718XX.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/F718XX.cs index 2f3a8bb..4f53aab 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/F718XX.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/F718XX.cs @@ -10,127 +10,127 @@ using System.Text; // ReSharper disable once InconsistentNaming -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal class F718XX : ISuperIO { - internal class F718XX : ISuperIO + private readonly ushort _address; + private readonly byte[] _initialFanPwmControl = new byte[4]; + private readonly bool[] _restoreDefaultFanPwmControlRequired = new bool[4]; + + public F718XX(Chip chip, ushort address) { - private readonly ushort _address; - private readonly byte[] _initialFanPwmControl = new byte[4]; - private readonly bool[] _restoreDefaultFanPwmControlRequired = new bool[4]; + _address = address; + Chip = chip; - public F718XX(Chip chip, ushort address) + Voltages = new float?[chip == Chip.F71858 ? 3 : 9]; + Temperatures = new float?[chip == Chip.F71808E ? 2 : 3]; + Fans = new float?[chip is Chip.F71882 or Chip.F71858 ? 4 : 3]; + Controls = new float?[chip == Chip.F71878AD ? 3 : 0]; + } + + public Chip Chip { get; } + + public float?[] Controls { get; } + + public float?[] Fans { get; } + + public float?[] Temperatures { get; } + + public float?[] Voltages { get; } + + public byte? ReadGpio(int index) + { + return null; + } + + public void WriteGpio(int index, byte value) + { } + + public void SetControl(int index, byte? value) + { + if (index < 0 || index >= Controls.Length) + throw new ArgumentOutOfRangeException(nameof(index)); + + if (!Ring0.WaitIsaBusMutex(10)) + return; + + if (value.HasValue) { - _address = address; - Chip = chip; + SaveDefaultFanPwmControl(index); - Voltages = new float?[chip == Chip.F71858 ? 3 : 9]; - Temperatures = new float?[chip == Chip.F71808E ? 2 : 3]; - Fans = new float?[chip is Chip.F71882 or Chip.F71858 ? 4 : 3]; - Controls = new float?[chip == Chip.F71878AD ? 3 : 0]; + WriteByte(FAN_PWM_REG[index], value.Value); + } + else + { + RestoreDefaultFanPwmControl(index); } - public Chip Chip { get; } + Ring0.ReleaseIsaBusMutex(); + } - public float?[] Controls { get; } + public string GetReport() + { + StringBuilder r = new(); - public float?[] Fans { get; } + r.AppendLine("LPC " + GetType().Name); + r.AppendLine(); + r.Append("Base Address: 0x"); + r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture)); + r.AppendLine(); - public float?[] Temperatures { get; } + if (!Ring0.WaitIsaBusMutex(100)) + return r.ToString(); - public float?[] Voltages { get; } - - public byte? ReadGpio(int index) + r.AppendLine("Hardware Monitor Registers"); + r.AppendLine(); + r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); + r.AppendLine(); + for (int i = 0; i <= 0xF; i++) { - return null; - } - - public void WriteGpio(int index, byte value) - { } - - public void SetControl(int index, byte? value) - { - if (index < 0 || index >= Controls.Length) - throw new ArgumentOutOfRangeException(nameof(index)); - - if (!Ring0.WaitIsaBusMutex(10)) - return; - - if (value.HasValue) + r.Append(" "); + r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); + r.Append(" "); + for (int j = 0; j <= 0xF; j++) { - SaveDefaultFanPwmControl(index); + r.Append(" "); + r.Append(ReadByte((byte)((i << 4) | j)).ToString("X2", + CultureInfo.InvariantCulture)); + } - WriteByte(FAN_PWM_REG[index], value.Value); + r.AppendLine(); + } + + r.AppendLine(); + + Ring0.ReleaseIsaBusMutex(); + return r.ToString(); + } + + public void Update() + { + if (!Ring0.WaitIsaBusMutex(10)) + return; + + for (int i = 0; i < Voltages.Length; i++) + { + if (Chip == Chip.F71808E && i == 6) + { + // 0x26 is reserved on F71808E + Voltages[i] = 0; } else { - RestoreDefaultFanPwmControl(index); + int value = ReadByte((byte)(VOLTAGE_BASE_REG + i)); + Voltages[i] = 0.008f * value; } - - Ring0.ReleaseIsaBusMutex(); } - public string GetReport() + for (int i = 0; i < Temperatures.Length; i++) { - StringBuilder r = new(); - - r.AppendLine("LPC " + GetType().Name); - r.AppendLine(); - r.Append("Base Address: 0x"); - r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture)); - r.AppendLine(); - - if (!Ring0.WaitIsaBusMutex(100)) - return r.ToString(); - - r.AppendLine("Hardware Monitor Registers"); - r.AppendLine(); - r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - r.AppendLine(); - for (int i = 0; i <= 0xF; i++) + switch (Chip) { - r.Append(" "); - r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); - r.Append(" "); - for (int j = 0; j <= 0xF; j++) - { - r.Append(" "); - r.Append(ReadByte((byte)((i << 4) | j)).ToString("X2", - CultureInfo.InvariantCulture)); - } - - r.AppendLine(); - } - - r.AppendLine(); - - Ring0.ReleaseIsaBusMutex(); - return r.ToString(); - } - - public void Update() - { - if (!Ring0.WaitIsaBusMutex(10)) - return; - - for (int i = 0; i < Voltages.Length; i++) - { - if (Chip == Chip.F71808E && i == 6) - { - // 0x26 is reserved on F71808E - Voltages[i] = 0; - } - else - { - int value = ReadByte((byte)(VOLTAGE_BASE_REG + i)); - Voltages[i] = 0.008f * value; - } - } - - for (int i = 0; i < Temperatures.Length; i++) - { - switch (Chip) - { - case Chip.F71858: + case Chip.F71858: { int tableMode = 0x3 & ReadByte(TEMPERATURE_CONFIG_REG); int high = ReadByte((byte)(TEMPERATURE_BASE_REG + (2 * i))); @@ -164,8 +164,8 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc } } - break; - default: + break; + default: { sbyte value = (sbyte)ReadByte((byte)(TEMPERATURE_BASE_REG + (2 * (i + 1)))); if (value is < sbyte.MaxValue and > 0) @@ -174,73 +174,72 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc Temperatures[i] = null; } - break; - } + break; } - - for (int i = 0; i < Fans.Length; i++) - { - int value = ReadByte(FAN_TACHOMETER_REG[i]) << 8; - value |= ReadByte((byte)(FAN_TACHOMETER_REG[i] + 1)); - - if (value > 0) - Fans[i] = value < 0x0fff ? 1.5e6f / value : 0; - else - Fans[i] = null; - } - - for (int i = 0; i < Controls.Length; i++) - { - Controls[i] = ReadByte((byte)(PWM_VALUES_OFFSET + i)) * 100.0f / 0xFF; - } - - Ring0.ReleaseIsaBusMutex(); } - private void SaveDefaultFanPwmControl(int index) + for (int i = 0; i < Fans.Length; i++) { - if (!_restoreDefaultFanPwmControlRequired[index]) - { - _initialFanPwmControl[index] = ReadByte(FAN_PWM_REG[index]); - _restoreDefaultFanPwmControlRequired[index] = true; - } + int value = ReadByte(FAN_TACHOMETER_REG[i]) << 8; + value |= ReadByte((byte)(FAN_TACHOMETER_REG[i] + 1)); + + if (value > 0) + Fans[i] = value < 0x0fff ? 1.5e6f / value : 0; + else + Fans[i] = null; } - private void RestoreDefaultFanPwmControl(int index) + for (int i = 0; i < Controls.Length; i++) { - if (_restoreDefaultFanPwmControlRequired[index]) - { - WriteByte(FAN_PWM_REG[index], _initialFanPwmControl[index]); - _restoreDefaultFanPwmControlRequired[index] = false; - } + Controls[i] = ReadByte((byte)(PWM_VALUES_OFFSET + i)) * 100.0f / 0xFF; } - private byte ReadByte(byte register) + Ring0.ReleaseIsaBusMutex(); + } + + private void SaveDefaultFanPwmControl(int index) + { + if (!_restoreDefaultFanPwmControlRequired[index]) { - Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); - return Ring0.ReadIoPort((ushort)(_address + DATA_REGISTER_OFFSET)); + _initialFanPwmControl[index] = ReadByte(FAN_PWM_REG[index]); + _restoreDefaultFanPwmControlRequired[index] = true; } + } - private void WriteByte(byte register, byte value) + private void RestoreDefaultFanPwmControl(int index) + { + if (_restoreDefaultFanPwmControlRequired[index]) { - Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); - Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), value); + WriteByte(FAN_PWM_REG[index], _initialFanPwmControl[index]); + _restoreDefaultFanPwmControlRequired[index] = false; } + } - // ReSharper disable InconsistentNaming + private byte ReadByte(byte register) + { + Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); + return Ring0.ReadIoPort((ushort)(_address + DATA_REGISTER_OFFSET)); + } + + private void WriteByte(byte register, byte value) + { + Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); + Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), value); + } + + // ReSharper disable InconsistentNaming #pragma warning disable IDE1006 // Naming Styles - private const byte ADDRESS_REGISTER_OFFSET = 0x05; - private const byte DATA_REGISTER_OFFSET = 0x06; - private const byte PWM_VALUES_OFFSET = 0x2D; - private const byte TEMPERATURE_BASE_REG = 0x70; - private const byte TEMPERATURE_CONFIG_REG = 0x69; + private const byte ADDRESS_REGISTER_OFFSET = 0x05; + private const byte DATA_REGISTER_OFFSET = 0x06; + private const byte PWM_VALUES_OFFSET = 0x2D; + private const byte TEMPERATURE_BASE_REG = 0x70; + private const byte TEMPERATURE_CONFIG_REG = 0x69; - private const byte VOLTAGE_BASE_REG = 0x20; - private readonly byte[] FAN_PWM_REG = { 0xA3, 0xB3, 0xC3, 0xD3 }; - private readonly byte[] FAN_TACHOMETER_REG = { 0xA0, 0xB0, 0xC0, 0xD0 }; + private const byte VOLTAGE_BASE_REG = 0x20; + private readonly byte[] FAN_PWM_REG = { 0xA3, 0xB3, 0xC3, 0xD3 }; + private readonly byte[] FAN_TACHOMETER_REG = { 0xA0, 0xB0, 0xC0, 0xD0 }; - // ReSharper restore InconsistentNaming + // ReSharper restore InconsistentNaming #pragma warning restore IDE1006 // Naming Styles - } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/ISuperIO.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/ISuperIO.cs index 1c04208..845864d 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/ISuperIO.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/ISuperIO.cs @@ -4,31 +4,30 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal interface ISuperIO { - internal interface ISuperIO - { - Chip Chip { get; } + Chip Chip { get; } - float?[] Controls { get; } + float?[] Controls { get; } - float?[] Fans { get; } + float?[] Fans { get; } - float?[] Temperatures { get; } + float?[] Temperatures { get; } - // get voltage, temperature, fan and control channel values - float?[] Voltages { get; } + // get voltage, temperature, fan and control channel values + float?[] Voltages { get; } - // set control value, null = auto - void SetControl(int index, byte? value); + // set control value, null = auto + void SetControl(int index, byte? value); - // read and write GPIO - byte? ReadGpio(int index); + // read and write GPIO + byte? ReadGpio(int index); - void WriteGpio(int index, byte value); + void WriteGpio(int index, byte value); - string GetReport(); + string GetReport(); - void Update(); - } -} + void Update(); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs index 12f7def..f05a200 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/IT87XX.cs @@ -10,557 +10,556 @@ using System.Text; // ReSharper disable once InconsistentNaming -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal class IT87XX : ISuperIO { - internal class IT87XX : ISuperIO + private const int MaxFanHeaders = 6; + private readonly ushort _address; + private readonly ushort _addressReg; + private readonly int _bankCount; + private readonly ushort _dataReg; + private readonly bool[] _fansDisabled = Array.Empty(); + private readonly ushort _gpioAddress; + private readonly int _gpioCount; + private readonly bool _has16BitFanCounter; + private readonly bool _hasExtReg; + private readonly bool[] _initialFanOutputModeEnabled = new bool[3]; // Initial Fan Controller Main Control Register value. + private readonly byte[] _initialFanPwmControl = new byte[MaxFanHeaders]; // This will also store the 2nd control register value. + private readonly byte[] _initialFanPwmControlExt = new byte[MaxFanHeaders]; + private readonly bool[] _restoreDefaultFanPwmControlRequired = new bool[MaxFanHeaders]; + private readonly byte _version; + private readonly float _voltageGain; + + private bool SupportsMultipleBanks => _bankCount > 1; + + public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) { - private const int MaxFanHeaders = 6; - private readonly ushort _address; - private readonly ushort _addressReg; - private readonly int _bankCount; - private readonly ushort _dataReg; - private readonly bool[] _fansDisabled = Array.Empty(); - private readonly ushort _gpioAddress; - private readonly int _gpioCount; - private readonly bool _has16BitFanCounter; - private readonly bool _hasExtReg; - private readonly bool[] _initialFanOutputModeEnabled = new bool[3]; // Initial Fan Controller Main Control Register value. - private readonly byte[] _initialFanPwmControl = new byte[MaxFanHeaders]; // This will also store the 2nd control register value. - private readonly byte[] _initialFanPwmControlExt = new byte[MaxFanHeaders]; - private readonly bool[] _restoreDefaultFanPwmControlRequired = new bool[MaxFanHeaders]; - private readonly byte _version; - private readonly float _voltageGain; + _address = address; + _version = version; + _addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET); + _dataReg = (ushort)(address + DATA_REGISTER_OFFSET); + _gpioAddress = gpioAddress; - private bool SupportsMultipleBanks => _bankCount > 1; + Chip = chip; - public IT87XX(Chip chip, ushort address, ushort gpioAddress, byte version) + // Check vendor id + byte vendorId = ReadByte(VENDOR_ID_REGISTER, out bool valid); + if (!valid) + return; + + bool hasMatchingVendorId = false; + foreach (byte iteVendorId in ITE_VENDOR_IDS) { - _address = address; - _version = version; - _addressReg = (ushort)(address + ADDRESS_REGISTER_OFFSET); - _dataReg = (ushort)(address + DATA_REGISTER_OFFSET); - _gpioAddress = gpioAddress; + if (iteVendorId == vendorId) + { + hasMatchingVendorId = true; + break; + } + } - Chip = chip; + if (!hasMatchingVendorId) + return; + + // Bit 0x10 of the configuration register should always be 1 + byte configuration = ReadByte(CONFIGURATION_REGISTER, out valid); + if (!valid || ((configuration & 0x10) == 0 && chip != Chip.IT8655E && chip != Chip.IT8665E)) + return; + + FAN_PWM_CTRL_REG = chip == Chip.IT8665E + ? new byte[] { 0x15, 0x16, 0x17, 0x1e, 0x1f } + : new byte[] { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf }; + + _bankCount = chip switch + { + Chip.IT8689E => 4, + _ => 1 + }; + + _hasExtReg = chip is Chip.IT8721F or + Chip.IT8728F or + Chip.IT8665E or + Chip.IT8686E or + Chip.IT8688E or + Chip.IT8689E or + Chip.IT8695E or + Chip.IT8628E or + Chip.IT8620E or + Chip.IT8613E or + Chip.IT879XE or + Chip.IT8655E or + Chip.IT8631E; + + switch (chip) + { + case Chip.IT8613E: + Voltages = new float?[10]; + Temperatures = new float?[4]; + Fans = new float?[5]; + Controls = new float?[4]; + break; + + case Chip.IT8628E: + Voltages = new float?[10]; + Temperatures = new float?[6]; + Fans = new float?[4]; + Controls = new float?[4]; + break; + + case Chip.IT8631E: + Voltages = new float?[9]; + Temperatures = new float?[2]; + Fans = new float?[2]; + Controls = new float?[2]; + break; + + case Chip.IT8665E: + case Chip.IT8686E: + Voltages = new float?[10]; + Temperatures = new float?[6]; + Fans = new float?[6]; + Controls = new float?[5]; + break; + + case Chip.IT8688E: + Voltages = new float?[11]; + Temperatures = new float?[6]; + Fans = new float?[6]; + Controls = new float?[5]; + break; + + case Chip.IT8689E: + Voltages = new float?[10]; + Temperatures = new float?[6]; + Fans = new float?[6]; + Controls = new float?[6]; + break; + + case Chip.IT8695E: + Voltages = new float?[6]; + Temperatures = new float?[3]; + Fans = new float?[3]; + Controls = new float?[3]; + break; + + case Chip.IT8655E: + Voltages = new float?[9]; + Temperatures = new float?[6]; + Fans = new float?[3]; + Controls = new float?[3]; + break; + + case Chip.IT879XE: + Voltages = new float?[9]; + Temperatures = new float?[3]; + Fans = new float?[3]; + Controls = new float?[3]; + break; + + case Chip.IT8705F: + Voltages = new float?[9]; + Temperatures = new float?[3]; + Fans = new float?[3]; + Controls = new float?[3]; + break; + + default: + Voltages = new float?[9]; + Temperatures = new float?[3]; + Fans = new float?[5]; + Controls = new float?[3]; + break; + } + + _fansDisabled = new bool[Fans.Length]; + + // IT8620E, IT8628E, IT8721F, IT8728F, IT8772E and IT8686E use a 12mV resolution. + // All others 16mV. + _voltageGain = chip switch + { + Chip.IT8613E or Chip.IT8620E or Chip.IT8628E or Chip.IT8631E or Chip.IT8721F or Chip.IT8728F or Chip.IT8771E or Chip.IT8772E or Chip.IT8686E or Chip.IT8688E or Chip.IT8689E => 0.012f, + Chip.IT8695E => 11f / 1000f, + Chip.IT8655E or Chip.IT8665E or Chip.IT879XE => 0.0109f, + _ => 0.016f + }; + + // Older IT8705F and IT8721F revisions do not have 16-bit fan counters. + _has16BitFanCounter = (chip != Chip.IT8705F || version >= 3) && (chip != Chip.IT8712F || version >= 8); + + // Disable any fans that aren't set with 16-bit fan counters + if (_has16BitFanCounter) + { + int modes = ReadByte(FAN_TACHOMETER_16BIT_REGISTER, out valid); - // Check vendor id - byte vendorId = ReadByte(VENDOR_ID_REGISTER, out bool valid); if (!valid) return; - bool hasMatchingVendorId = false; - foreach (byte iteVendorId in ITE_VENDOR_IDS) + if (Fans.Length >= 5) { - if (iteVendorId == vendorId) - { - hasMatchingVendorId = true; - break; - } + _fansDisabled[3] = (modes & (1 << 4)) == 0; + _fansDisabled[4] = (modes & (1 << 5)) == 0; } - if (!hasMatchingVendorId) - return; + if (Fans.Length >= 6) + _fansDisabled[5] = (modes & (1 << 2)) == 0; + } - // Bit 0x10 of the configuration register should always be 1 - byte configuration = ReadByte(CONFIGURATION_REGISTER, out valid); - if (!valid || ((configuration & 0x10) == 0 && chip != Chip.IT8655E && chip != Chip.IT8665E)) - return; + // Set the number of GPIO sets + _gpioCount = chip switch + { + Chip.IT8712F or Chip.IT8716F or Chip.IT8718F or Chip.IT8726F => 5, + Chip.IT8720F or Chip.IT8721F => 8, + _ => 0 + }; + } - FAN_PWM_CTRL_REG = chip == Chip.IT8665E - ? new byte[] { 0x15, 0x16, 0x17, 0x1e, 0x1f } - : new byte[] { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf }; + public Chip Chip { get; } - _bankCount = chip switch + public float?[] Controls { get; } = Array.Empty(); + + public float?[] Fans { get; } = Array.Empty(); + + public float?[] Temperatures { get; } = Array.Empty(); + + public float?[] Voltages { get; } = Array.Empty(); + + public byte? ReadGpio(int index) + { + if (index >= _gpioCount) + return null; + + return Ring0.ReadIoPort((ushort)(_gpioAddress + index)); + } + + public void WriteGpio(int index, byte value) + { + if (index >= _gpioCount) + return; + + Ring0.WriteIoPort((ushort)(_gpioAddress + index), value); + } + + public void SetControl(int index, byte? value) + { + if (index < 0 || index >= Controls.Length) + throw new ArgumentOutOfRangeException(nameof(index)); + + if (!Ring0.WaitIsaBusMutex(10)) + return; + + if (value.HasValue) + { + SaveDefaultFanPwmControl(index); + + if (index < 3 && !_initialFanOutputModeEnabled[index]) + WriteByte(FAN_MAIN_CTRL_REG, (byte)(ReadByte(FAN_MAIN_CTRL_REG, out _) | (1 << index))); + + if (_hasExtReg) { - Chip.IT8689E => 4, - _ => 1 - }; - - _hasExtReg = chip is Chip.IT8721F or - Chip.IT8728F or - Chip.IT8665E or - Chip.IT8686E or - Chip.IT8688E or - Chip.IT8689E or - Chip.IT8695E or - Chip.IT8628E or - Chip.IT8620E or - Chip.IT8613E or - Chip.IT879XE or - Chip.IT8655E or - Chip.IT8631E; - - switch (chip) - { - case Chip.IT8613E: - Voltages = new float?[10]; - Temperatures = new float?[4]; - Fans = new float?[5]; - Controls = new float?[4]; - break; - - case Chip.IT8628E: - Voltages = new float?[10]; - Temperatures = new float?[6]; - Fans = new float?[4]; - Controls = new float?[4]; - break; - - case Chip.IT8631E: - Voltages = new float?[9]; - Temperatures = new float?[2]; - Fans = new float?[2]; - Controls = new float?[2]; - break; - - case Chip.IT8665E: - case Chip.IT8686E: - Voltages = new float?[10]; - Temperatures = new float?[6]; - Fans = new float?[6]; - Controls = new float?[5]; - break; - - case Chip.IT8688E: - Voltages = new float?[11]; - Temperatures = new float?[6]; - Fans = new float?[6]; - Controls = new float?[5]; - break; - - case Chip.IT8689E: - Voltages = new float?[10]; - Temperatures = new float?[6]; - Fans = new float?[6]; - Controls = new float?[6]; - break; - - case Chip.IT8695E: - Voltages = new float?[6]; - Temperatures = new float?[3]; - Fans = new float?[3]; - Controls = new float?[3]; - break; - - case Chip.IT8655E: - Voltages = new float?[9]; - Temperatures = new float?[6]; - Fans = new float?[3]; - Controls = new float?[3]; - break; - - case Chip.IT879XE: - Voltages = new float?[9]; - Temperatures = new float?[3]; - Fans = new float?[3]; - Controls = new float?[3]; - break; - - case Chip.IT8705F: - Voltages = new float?[9]; - Temperatures = new float?[3]; - Fans = new float?[3]; - Controls = new float?[3]; - break; - - default: - Voltages = new float?[9]; - Temperatures = new float?[3]; - Fans = new float?[5]; - Controls = new float?[3]; - break; - } - - _fansDisabled = new bool[Fans.Length]; - - // IT8620E, IT8628E, IT8721F, IT8728F, IT8772E and IT8686E use a 12mV resolution. - // All others 16mV. - _voltageGain = chip switch - { - Chip.IT8613E or Chip.IT8620E or Chip.IT8628E or Chip.IT8631E or Chip.IT8721F or Chip.IT8728F or Chip.IT8771E or Chip.IT8772E or Chip.IT8686E or Chip.IT8688E or Chip.IT8689E => 0.012f, - Chip.IT8695E => 11f / 1000f, - Chip.IT8655E or Chip.IT8665E or Chip.IT879XE => 0.0109f, - _ => 0.016f - }; - - // Older IT8705F and IT8721F revisions do not have 16-bit fan counters. - _has16BitFanCounter = (chip != Chip.IT8705F || version >= 3) && (chip != Chip.IT8712F || version >= 8); - - // Disable any fans that aren't set with 16-bit fan counters - if (_has16BitFanCounter) - { - int modes = ReadByte(FAN_TACHOMETER_16BIT_REGISTER, out valid); - - if (!valid) - return; - - if (Fans.Length >= 5) + if (Chip == Chip.IT8689E) { - _fansDisabled[3] = (modes & (1 << 4)) == 0; - _fansDisabled[4] = (modes & (1 << 5)) == 0; - } - - if (Fans.Length >= 6) - _fansDisabled[5] = (modes & (1 << 2)) == 0; - } - - // Set the number of GPIO sets - _gpioCount = chip switch - { - Chip.IT8712F or Chip.IT8716F or Chip.IT8718F or Chip.IT8726F => 5, - Chip.IT8720F or Chip.IT8721F => 8, - _ => 0 - }; - } - - public Chip Chip { get; } - - public float?[] Controls { get; } = Array.Empty(); - - public float?[] Fans { get; } = Array.Empty(); - - public float?[] Temperatures { get; } = Array.Empty(); - - public float?[] Voltages { get; } = Array.Empty(); - - public byte? ReadGpio(int index) - { - if (index >= _gpioCount) - return null; - - return Ring0.ReadIoPort((ushort)(_gpioAddress + index)); - } - - public void WriteGpio(int index, byte value) - { - if (index >= _gpioCount) - return; - - Ring0.WriteIoPort((ushort)(_gpioAddress + index), value); - } - - public void SetControl(int index, byte? value) - { - if (index < 0 || index >= Controls.Length) - throw new ArgumentOutOfRangeException(nameof(index)); - - if (!Ring0.WaitIsaBusMutex(10)) - return; - - if (value.HasValue) - { - SaveDefaultFanPwmControl(index); - - if (index < 3 && !_initialFanOutputModeEnabled[index]) - WriteByte(FAN_MAIN_CTRL_REG, (byte)(ReadByte(FAN_MAIN_CTRL_REG, out _) | (1 << index))); - - if (_hasExtReg) - { - if (Chip == Chip.IT8689E) - { - WriteByte(FAN_PWM_CTRL_REG[index], 0x7F); - } - else - { - WriteByte(FAN_PWM_CTRL_REG[index], (byte)(_initialFanPwmControl[index] & 0x7F)); - } - WriteByte(FAN_PWM_CTRL_EXT_REG[index], value.Value); + WriteByte(FAN_PWM_CTRL_REG[index], 0x7F); } else { - WriteByte(FAN_PWM_CTRL_REG[index], (byte)(value.Value >> 1)); + WriteByte(FAN_PWM_CTRL_REG[index], (byte)(_initialFanPwmControl[index] & 0x7F)); } + WriteByte(FAN_PWM_CTRL_EXT_REG[index], value.Value); } else { - RestoreDefaultFanPwmControl(index); + WriteByte(FAN_PWM_CTRL_REG[index], (byte)(value.Value >> 1)); } - - Ring0.ReleaseIsaBusMutex(); + } + else + { + RestoreDefaultFanPwmControl(index); } - public string GetReport() + Ring0.ReleaseIsaBusMutex(); + } + + public string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("LPC " + GetType().Name); + r.AppendLine(); + r.Append("Chip ID: 0x"); + r.AppendLine(Chip.ToString("X")); + r.Append("Chip Version: 0x"); + r.AppendLine(_version.ToString("X", CultureInfo.InvariantCulture)); + r.Append("Base Address: 0x"); + r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture)); + r.Append("GPIO Address: 0x"); + r.AppendLine(_gpioAddress.ToString("X4", CultureInfo.InvariantCulture)); + r.AppendLine(); + + if (!Ring0.WaitIsaBusMutex(100)) + return r.ToString(); + + // dump memory of all banks if supported by chip + for (byte b = 0; b < _bankCount; b++) { - StringBuilder r = new(); - - r.AppendLine("LPC " + GetType().Name); - r.AppendLine(); - r.Append("Chip ID: 0x"); - r.AppendLine(Chip.ToString("X")); - r.Append("Chip Version: 0x"); - r.AppendLine(_version.ToString("X", CultureInfo.InvariantCulture)); - r.Append("Base Address: 0x"); - r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture)); - r.Append("GPIO Address: 0x"); - r.AppendLine(_gpioAddress.ToString("X4", CultureInfo.InvariantCulture)); - r.AppendLine(); - - if (!Ring0.WaitIsaBusMutex(100)) - return r.ToString(); - - // dump memory of all banks if supported by chip - for (byte b = 0; b < _bankCount; b++) + if (SupportsMultipleBanks && b > 0) { - if (SupportsMultipleBanks && b > 0) - { - SelectBank(b); - } - r.AppendLine($"Environment Controller Registers Bank {b}"); - r.AppendLine(); - r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - r.AppendLine(); - for (int i = 0; i <= 0xA; i++) - { - r.Append(" "); - r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); - r.Append(" "); - for (int j = 0; j <= 0xF; j++) - { - r.Append(" "); - byte value = ReadByte((byte)((i << 4) | j), out bool valid); - r.Append(valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??"); - } - - r.AppendLine(); - } - - r.AppendLine(); + SelectBank(b); } - - if (SupportsMultipleBanks) - { - SelectBank(0); - } - + r.AppendLine($"Environment Controller Registers Bank {b}"); r.AppendLine(); - - r.AppendLine("GPIO Registers"); + r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); r.AppendLine(); - for (int i = 0; i < _gpioCount; i++) + for (int i = 0; i <= 0xA; i++) { r.Append(" "); - r.Append(ReadGpio(i)?.ToString("X2", CultureInfo.InvariantCulture)); + r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); + r.Append(" "); + for (int j = 0; j <= 0xF; j++) + { + r.Append(" "); + byte value = ReadByte((byte)((i << 4) | j), out bool valid); + r.Append(valid ? value.ToString("X2", CultureInfo.InvariantCulture) : "??"); + } + + r.AppendLine(); } r.AppendLine(); - r.AppendLine(); - Ring0.ReleaseIsaBusMutex(); - return r.ToString(); } - /// - /// Selects another bank. Memory from 0x10-0xAF swaps to data from new bank. - /// Beware to select the default bank 0 after changing. - /// Bank selection is reset after power cycle. - /// - /// New bank index. Can be a value of 0-3. - private void SelectBank(byte bankIndex) + if (SupportsMultipleBanks) { - if (bankIndex >= _bankCount) - return; // current chip does not support that many banks - - // hard cap SelectBank to 2 bit values. If we ever have chips with more bank bits rewrite this method. - bankIndex &= 0x3; - - byte value = ReadByte(BANK_REGISTER, out bool valid); - if (valid) - { - value &= 0x9F; - value |= (byte)(bankIndex << 5); - WriteByte(BANK_REGISTER, value); - } + SelectBank(0); } - public void Update() + r.AppendLine(); + + r.AppendLine("GPIO Registers"); + r.AppendLine(); + for (int i = 0; i < _gpioCount; i++) { - if (!Ring0.WaitIsaBusMutex(10)) - return; + r.Append(" "); + r.Append(ReadGpio(i)?.ToString("X2", CultureInfo.InvariantCulture)); + } - for (int i = 0; i < Voltages.Length; i++) + r.AppendLine(); + r.AppendLine(); + Ring0.ReleaseIsaBusMutex(); + return r.ToString(); + } + + /// + /// Selects another bank. Memory from 0x10-0xAF swaps to data from new bank. + /// Beware to select the default bank 0 after changing. + /// Bank selection is reset after power cycle. + /// + /// New bank index. Can be a value of 0-3. + private void SelectBank(byte bankIndex) + { + if (bankIndex >= _bankCount) + return; // current chip does not support that many banks + + // hard cap SelectBank to 2 bit values. If we ever have chips with more bank bits rewrite this method. + bankIndex &= 0x3; + + byte value = ReadByte(BANK_REGISTER, out bool valid); + if (valid) + { + value &= 0x9F; + value |= (byte)(bankIndex << 5); + WriteByte(BANK_REGISTER, value); + } + } + + public void Update() + { + if (!Ring0.WaitIsaBusMutex(10)) + return; + + for (int i = 0; i < Voltages.Length; i++) + { + float value = _voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out bool valid); + + if (!valid) + continue; + + if (value > 0) + Voltages[i] = value; + else + Voltages[i] = null; + } + + for (int i = 0; i < Temperatures.Length; i++) + { + sbyte value = (sbyte)ReadByte((byte)(TEMPERATURE_BASE_REG + i), out bool valid); + if (!valid) + continue; + + if (value is < sbyte.MaxValue and > 0) + Temperatures[i] = value; + else + Temperatures[i] = null; + } + + if (_has16BitFanCounter) + { + for (int i = 0; i < Fans.Length; i++) { - float value = _voltageGain * ReadByte((byte)(VOLTAGE_BASE_REG + i), out bool valid); + if (_fansDisabled[i]) + continue; + int value = ReadByte(FAN_TACHOMETER_REG[i], out bool valid); if (!valid) continue; + value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8; + if (!valid) + continue; + + if (value > 0x3f) + Fans[i] = value < 0xffff ? 1.35e6f / (value * 2) : 0; + else + Fans[i] = null; + } + } + else + { + for (int i = 0; i < Fans.Length; i++) + { + int value = ReadByte(FAN_TACHOMETER_REG[i], out bool valid); + if (!valid) + continue; + + int divisor = 2; + if (i < 2) + { + int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid); + if (!valid) + continue; + + divisor = 1 << ((divisors >> (3 * i)) & 0x7); + } + if (value > 0) - Voltages[i] = value; + Fans[i] = value < 0xff ? 1.35e6f / (value * divisor) : 0; else - Voltages[i] = null; + Fans[i] = null; } + } - for (int i = 0; i < Temperatures.Length; i++) + for (int i = 0; i < Controls.Length; i++) + { + byte value = ReadByte(FAN_PWM_CTRL_REG[i], out bool valid); + if (!valid) + continue; + + if ((value & 0x80) > 0) { - sbyte value = (sbyte)ReadByte((byte)(TEMPERATURE_BASE_REG + i), out bool valid); - if (!valid) - continue; - - if (value is < sbyte.MaxValue and > 0) - Temperatures[i] = value; - else - Temperatures[i] = null; - } - - if (_has16BitFanCounter) - { - for (int i = 0; i < Fans.Length; i++) - { - if (_fansDisabled[i]) - continue; - - int value = ReadByte(FAN_TACHOMETER_REG[i], out bool valid); - if (!valid) - continue; - - value |= ReadByte(FAN_TACHOMETER_EXT_REG[i], out valid) << 8; - if (!valid) - continue; - - if (value > 0x3f) - Fans[i] = value < 0xffff ? 1.35e6f / (value * 2) : 0; - else - Fans[i] = null; - } + // Automatic operation (value can't be read). + Controls[i] = null; } else { - for (int i = 0; i < Fans.Length; i++) + // Software operation. + if (_hasExtReg) { - int value = ReadByte(FAN_TACHOMETER_REG[i], out bool valid); - if (!valid) - continue; - - int divisor = 2; - if (i < 2) - { - int divisors = ReadByte(FAN_TACHOMETER_DIVISOR_REGISTER, out valid); - if (!valid) - continue; - - divisor = 1 << ((divisors >> (3 * i)) & 0x7); - } - - if (value > 0) - Fans[i] = value < 0xff ? 1.35e6f / (value * divisor) : 0; - else - Fans[i] = null; - } - } - - for (int i = 0; i < Controls.Length; i++) - { - byte value = ReadByte(FAN_PWM_CTRL_REG[i], out bool valid); - if (!valid) - continue; - - if ((value & 0x80) > 0) - { - // Automatic operation (value can't be read). - Controls[i] = null; + value = ReadByte(FAN_PWM_CTRL_EXT_REG[i], out valid); + if (valid) + Controls[i] = (float)Math.Round(value * 100.0f / 0xFF); } else { - // Software operation. - if (_hasExtReg) - { - value = ReadByte(FAN_PWM_CTRL_EXT_REG[i], out valid); - if (valid) - Controls[i] = (float)Math.Round(value * 100.0f / 0xFF); - } - else - { - Controls[i] = (float)Math.Round((value & 0x7F) * 100.0f / 0x7F); - } + Controls[i] = (float)Math.Round((value & 0x7F) * 100.0f / 0x7F); } } - - Ring0.ReleaseIsaBusMutex(); } - private byte ReadByte(byte register, out bool valid) - { - Ring0.WriteIoPort(_addressReg, register); - byte value = Ring0.ReadIoPort(_dataReg); - valid = register == Ring0.ReadIoPort(_addressReg) || Chip == Chip.IT8688E; - // IT8688E doesn't return the value we wrote to - // addressReg when we read it back. + Ring0.ReleaseIsaBusMutex(); + } - return value; + private byte ReadByte(byte register, out bool valid) + { + Ring0.WriteIoPort(_addressReg, register); + byte value = Ring0.ReadIoPort(_dataReg); + valid = register == Ring0.ReadIoPort(_addressReg) || Chip == Chip.IT8688E; + // IT8688E doesn't return the value we wrote to + // addressReg when we read it back. + + return value; + } + + private void WriteByte(byte register, byte value) + { + Ring0.WriteIoPort(_addressReg, register); + Ring0.WriteIoPort(_dataReg, value); + Ring0.ReadIoPort(_addressReg); + } + + private void SaveDefaultFanPwmControl(int index) + { + if (!_restoreDefaultFanPwmControlRequired[index]) + { + _initialFanPwmControl[index] = ReadByte(FAN_PWM_CTRL_REG[index], out bool _); + + if (index < 3) + _initialFanOutputModeEnabled[index] = ReadByte(FAN_MAIN_CTRL_REG, out bool _) != 0; // Save default control reg value. + + if (_hasExtReg) + _initialFanPwmControlExt[index] = ReadByte(FAN_PWM_CTRL_EXT_REG[index], out _); } - private void WriteByte(byte register, byte value) - { - Ring0.WriteIoPort(_addressReg, register); - Ring0.WriteIoPort(_dataReg, value); - Ring0.ReadIoPort(_addressReg); - } + _restoreDefaultFanPwmControlRequired[index] = true; + } - private void SaveDefaultFanPwmControl(int index) + private void RestoreDefaultFanPwmControl(int index) + { + if (_restoreDefaultFanPwmControlRequired[index]) { - if (!_restoreDefaultFanPwmControlRequired[index]) + WriteByte(FAN_PWM_CTRL_REG[index], _initialFanPwmControl[index]); + + if (index < 3) { - _initialFanPwmControl[index] = ReadByte(FAN_PWM_CTRL_REG[index], out bool _); + byte value = ReadByte(FAN_MAIN_CTRL_REG, out _); - if (index < 3) - _initialFanOutputModeEnabled[index] = ReadByte(FAN_MAIN_CTRL_REG, out bool _) != 0; // Save default control reg value. - - if (_hasExtReg) - _initialFanPwmControlExt[index] = ReadByte(FAN_PWM_CTRL_EXT_REG[index], out _); + bool isEnabled = (value & (1 << index)) != 0; + if (isEnabled != _initialFanOutputModeEnabled[index]) + WriteByte(FAN_MAIN_CTRL_REG, (byte)(value ^ (1 << index))); } - _restoreDefaultFanPwmControlRequired[index] = true; + if (_hasExtReg) + WriteByte(FAN_PWM_CTRL_EXT_REG[index], _initialFanPwmControlExt[index]); + + _restoreDefaultFanPwmControlRequired[index] = false; } + } - private void RestoreDefaultFanPwmControl(int index) - { - if (_restoreDefaultFanPwmControlRequired[index]) - { - WriteByte(FAN_PWM_CTRL_REG[index], _initialFanPwmControl[index]); - - if (index < 3) - { - byte value = ReadByte(FAN_MAIN_CTRL_REG, out _); - - bool isEnabled = (value & (1 << index)) != 0; - if (isEnabled != _initialFanOutputModeEnabled[index]) - WriteByte(FAN_MAIN_CTRL_REG, (byte)(value ^ (1 << index))); - } - - if (_hasExtReg) - WriteByte(FAN_PWM_CTRL_EXT_REG[index], _initialFanPwmControlExt[index]); - - _restoreDefaultFanPwmControlRequired[index] = false; - } - } - - // ReSharper disable InconsistentNaming + // ReSharper disable InconsistentNaming #pragma warning disable IDE1006 // Naming Styles - private const byte ADDRESS_REGISTER_OFFSET = 0x05; + private const byte ADDRESS_REGISTER_OFFSET = 0x05; - private const byte CONFIGURATION_REGISTER = 0x00; - private const byte DATA_REGISTER_OFFSET = 0x06; - private const byte BANK_REGISTER = 0x06; // bit 5-6 define selected bank - private const byte FAN_TACHOMETER_16BIT_REGISTER = 0x0C; - private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B; + private const byte CONFIGURATION_REGISTER = 0x00; + private const byte DATA_REGISTER_OFFSET = 0x06; + private const byte BANK_REGISTER = 0x06; // bit 5-6 define selected bank + private const byte FAN_TACHOMETER_16BIT_REGISTER = 0x0C; + private const byte FAN_TACHOMETER_DIVISOR_REGISTER = 0x0B; - private readonly byte[] ITE_VENDOR_IDS = { 0x90, 0x7F }; + private readonly byte[] ITE_VENDOR_IDS = { 0x90, 0x7F }; - private const byte TEMPERATURE_BASE_REG = 0x29; - private const byte VENDOR_ID_REGISTER = 0x58; - private const byte VOLTAGE_BASE_REG = 0x20; + private const byte TEMPERATURE_BASE_REG = 0x29; + private const byte VENDOR_ID_REGISTER = 0x58; + private const byte VOLTAGE_BASE_REG = 0x20; - private readonly byte[] FAN_PWM_CTRL_REG; - private readonly byte[] FAN_PWM_CTRL_EXT_REG = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab }; - private readonly byte[] FAN_TACHOMETER_EXT_REG = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d }; - private readonly byte[] FAN_TACHOMETER_REG = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c }; + private readonly byte[] FAN_PWM_CTRL_REG; + private readonly byte[] FAN_PWM_CTRL_EXT_REG = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab }; + private readonly byte[] FAN_TACHOMETER_EXT_REG = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d }; + private readonly byte[] FAN_TACHOMETER_REG = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c }; - // Address of the Fan Controller Main Control Register. - // No need for the 2nd control register (bit 7 of 0x15 0x16 0x17), - // as PWM value will set it to manual mode when new value is set. - private const byte FAN_MAIN_CTRL_REG = 0x13; + // Address of the Fan Controller Main Control Register. + // No need for the 2nd control register (bit 7 of 0x15 0x16 0x17), + // as PWM value will set it to manual mode when new value is set. + private const byte FAN_MAIN_CTRL_REG = 0x13; #pragma warning restore IDE1006 // Naming Styles - // ReSharper restore InconsistentNaming - } + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LMSensors.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LMSensors.cs index e34b8d7..ef96fe7 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LMSensors.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LMSensors.cs @@ -12,284 +12,283 @@ using System.Text; // ReSharper disable once InconsistentNaming -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal class LMSensors { - internal class LMSensors + private readonly List _superIOs = new(); + + public LMSensors() { - private readonly List _superIOs = new(); - - public LMSensors() + foreach (string basePath in Directory.GetDirectories("/sys/class/hwmon/")) { - foreach (string basePath in Directory.GetDirectories("/sys/class/hwmon/")) + foreach (string devicePath in new[] { "/device", string.Empty }) { - foreach (string devicePath in new[] { "/device", string.Empty }) + string path = basePath + devicePath; + + string name = null; + try { - string path = basePath + devicePath; + using StreamReader reader = new(path + "/name"); + name = reader.ReadLine(); + } + catch (IOException) + { } - string name = null; - try - { - using StreamReader reader = new(path + "/name"); - name = reader.ReadLine(); - } - catch (IOException) - { } + switch (name) + { + case "atk0110": + _superIOs.Add(new LMChip(Chip.ATK0110, path)); + break; - switch (name) - { - case "atk0110": - _superIOs.Add(new LMChip(Chip.ATK0110, path)); - break; + case "f71858fg": + _superIOs.Add(new LMChip(Chip.F71858, path)); + break; + case "f71862fg": + _superIOs.Add(new LMChip(Chip.F71862, path)); + break; + case "f71869": + _superIOs.Add(new LMChip(Chip.F71869, path)); + break; + case "f71869a": + _superIOs.Add(new LMChip(Chip.F71869A, path)); + break; + case "f71882fg": + _superIOs.Add(new LMChip(Chip.F71882, path)); + break; + case "f71889a": + _superIOs.Add(new LMChip(Chip.F71889AD, path)); + break; + case "f71878ad": + _superIOs.Add(new LMChip(Chip.F71878AD, path)); + break; + case "f71889ed": + _superIOs.Add(new LMChip(Chip.F71889ED, path)); + break; + case "f71889fg": + _superIOs.Add(new LMChip(Chip.F71889F, path)); + break; + case "f71808e": + _superIOs.Add(new LMChip(Chip.F71808E, path)); + break; - case "f71858fg": - _superIOs.Add(new LMChip(Chip.F71858, path)); - break; - case "f71862fg": - _superIOs.Add(new LMChip(Chip.F71862, path)); - break; - case "f71869": - _superIOs.Add(new LMChip(Chip.F71869, path)); - break; - case "f71869a": - _superIOs.Add(new LMChip(Chip.F71869A, path)); - break; - case "f71882fg": - _superIOs.Add(new LMChip(Chip.F71882, path)); - break; - case "f71889a": - _superIOs.Add(new LMChip(Chip.F71889AD, path)); - break; - case "f71878ad": - _superIOs.Add(new LMChip(Chip.F71878AD, path)); - break; - case "f71889ed": - _superIOs.Add(new LMChip(Chip.F71889ED, path)); - break; - case "f71889fg": - _superIOs.Add(new LMChip(Chip.F71889F, path)); - break; - case "f71808e": - _superIOs.Add(new LMChip(Chip.F71808E, path)); - break; + case "it8705": + _superIOs.Add(new LMChip(Chip.IT8705F, path)); + break; + case "it8712": + _superIOs.Add(new LMChip(Chip.IT8712F, path)); + break; + case "it8716": + _superIOs.Add(new LMChip(Chip.IT8716F, path)); + break; + case "it8718": + _superIOs.Add(new LMChip(Chip.IT8718F, path)); + break; + case "it8720": + _superIOs.Add(new LMChip(Chip.IT8720F, path)); + break; - case "it8705": - _superIOs.Add(new LMChip(Chip.IT8705F, path)); - break; - case "it8712": - _superIOs.Add(new LMChip(Chip.IT8712F, path)); - break; - case "it8716": - _superIOs.Add(new LMChip(Chip.IT8716F, path)); - break; - case "it8718": - _superIOs.Add(new LMChip(Chip.IT8718F, path)); - break; - case "it8720": - _superIOs.Add(new LMChip(Chip.IT8720F, path)); - break; + case "nct6775": + _superIOs.Add(new LMChip(Chip.NCT6771F, path)); + break; + case "nct6776": + _superIOs.Add(new LMChip(Chip.NCT6776F, path)); + break; + case "nct6779": + _superIOs.Add(new LMChip(Chip.NCT6779D, path)); + break; + case "nct6791": + _superIOs.Add(new LMChip(Chip.NCT6791D, path)); + break; + case "nct6792": + _superIOs.Add(new LMChip(Chip.NCT6792D, path)); + break; + case "nct6793": + _superIOs.Add(new LMChip(Chip.NCT6793D, path)); + break; + case "nct6795": + _superIOs.Add(new LMChip(Chip.NCT6795D, path)); + break; + case "nct6796": + _superIOs.Add(new LMChip(Chip.NCT6796D, path)); + break; + case "nct6797": + _superIOs.Add(new LMChip(Chip.NCT6797D, path)); + break; + case "nct6798": + _superIOs.Add(new LMChip(Chip.NCT6798D, path)); + break; - case "nct6775": - _superIOs.Add(new LMChip(Chip.NCT6771F, path)); - break; - case "nct6776": - _superIOs.Add(new LMChip(Chip.NCT6776F, path)); - break; - case "nct6779": - _superIOs.Add(new LMChip(Chip.NCT6779D, path)); - break; - case "nct6791": - _superIOs.Add(new LMChip(Chip.NCT6791D, path)); - break; - case "nct6792": - _superIOs.Add(new LMChip(Chip.NCT6792D, path)); - break; - case "nct6793": - _superIOs.Add(new LMChip(Chip.NCT6793D, path)); - break; - case "nct6795": - _superIOs.Add(new LMChip(Chip.NCT6795D, path)); - break; - case "nct6796": - _superIOs.Add(new LMChip(Chip.NCT6796D, path)); - break; - case "nct6797": - _superIOs.Add(new LMChip(Chip.NCT6797D, path)); - break; - case "nct6798": - _superIOs.Add(new LMChip(Chip.NCT6798D, path)); - break; + case "w83627ehf": + _superIOs.Add(new LMChip(Chip.W83627EHF, path)); + break; + case "w83627dhg": + _superIOs.Add(new LMChip(Chip.W83627DHG, path)); + break; + case "w83667hg": + _superIOs.Add(new LMChip(Chip.W83667HG, path)); + break; + case "w83627hf": + _superIOs.Add(new LMChip(Chip.W83627HF, path)); + break; + case "w83627thf": + _superIOs.Add(new LMChip(Chip.W83627THF, path)); + break; + case "w83687thf": + _superIOs.Add(new LMChip(Chip.W83687THF, path)); + break; + } + } + } + } - case "w83627ehf": - _superIOs.Add(new LMChip(Chip.W83627EHF, path)); - break; - case "w83627dhg": - _superIOs.Add(new LMChip(Chip.W83627DHG, path)); - break; - case "w83667hg": - _superIOs.Add(new LMChip(Chip.W83667HG, path)); - break; - case "w83627hf": - _superIOs.Add(new LMChip(Chip.W83627HF, path)); - break; - case "w83627thf": - _superIOs.Add(new LMChip(Chip.W83627THF, path)); - break; - case "w83687thf": - _superIOs.Add(new LMChip(Chip.W83687THF, path)); - break; - } + public IReadOnlyList SuperIO + { + get { return _superIOs; } + } + + public void Close() + { + foreach (ISuperIO superIO in _superIOs) + { + if (superIO is LMChip lmChip) + lmChip.Close(); + } + } + + private class LMChip : ISuperIO + { + private readonly FileStream[] _fanStreams; + private readonly FileStream[] _temperatureStreams; + + private readonly FileStream[] _voltageStreams; + private string _path; + + public LMChip(Chip chip, string path) + { + _path = path; + Chip = chip; + + string[] voltagePaths = Directory.GetFiles(path, "in*_input"); + Voltages = new float?[voltagePaths.Length]; + _voltageStreams = new FileStream[voltagePaths.Length]; + for (int i = 0; i < voltagePaths.Length; i++) + _voltageStreams[i] = new FileStream(voltagePaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + string[] temperaturePaths = Directory.GetFiles(path, "temp*_input"); + Temperatures = new float?[temperaturePaths.Length]; + _temperatureStreams = new FileStream[temperaturePaths.Length]; + for (int i = 0; i < temperaturePaths.Length; i++) + _temperatureStreams[i] = new FileStream(temperaturePaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + string[] fanPaths = Directory.GetFiles(path, "fan*_input"); + Fans = new float?[fanPaths.Length]; + _fanStreams = new FileStream[fanPaths.Length]; + for (int i = 0; i < fanPaths.Length; i++) + _fanStreams[i] = new FileStream(fanPaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + + Controls = Array.Empty(); + } + + public Chip Chip { get; } + + public float?[] Controls { get; } + + public float?[] Fans { get; } + + public float?[] Temperatures { get; } + + public float?[] Voltages { get; } + + public byte? ReadGpio(int index) + { + return null; + } + + public void WriteGpio(int index, byte value) + { } + + public string GetReport() + { + return null; + } + + public void SetControl(int index, byte? value) + { } + + public void Update() + { + for (int i = 0; i < Voltages.Length; i++) + { + string s = ReadFirstLine(_voltageStreams[i]); + try + { + Voltages[i] = 0.001f * + long.Parse(s, CultureInfo.InvariantCulture); + } + catch + { + Voltages[i] = null; + } + } + + for (int i = 0; i < Temperatures.Length; i++) + { + string s = ReadFirstLine(_temperatureStreams[i]); + try + { + Temperatures[i] = 0.001f * + long.Parse(s, CultureInfo.InvariantCulture); + } + catch + { + Temperatures[i] = null; + } + } + + for (int i = 0; i < Fans.Length; i++) + { + string s = ReadFirstLine(_fanStreams[i]); + try + { + Fans[i] = long.Parse(s, CultureInfo.InvariantCulture); + } + catch + { + Fans[i] = null; } } } - public IReadOnlyList SuperIO + private static string ReadFirstLine(Stream stream) { - get { return _superIOs; } + StringBuilder sb = new(); + try + { + stream.Seek(0, SeekOrigin.Begin); + int b = stream.ReadByte(); + while (b is not -1 and not 10) + { + sb.Append((char)b); + b = stream.ReadByte(); + } + } + catch + { } + + return sb.ToString(); } public void Close() { - foreach (ISuperIO superIO in _superIOs) - { - if (superIO is LMChip lmChip) - lmChip.Close(); - } - } + foreach (FileStream stream in _voltageStreams) + stream.Close(); - private class LMChip : ISuperIO - { - private readonly FileStream[] _fanStreams; - private readonly FileStream[] _temperatureStreams; + foreach (FileStream stream in _temperatureStreams) + stream.Close(); - private readonly FileStream[] _voltageStreams; - private string _path; - - public LMChip(Chip chip, string path) - { - _path = path; - Chip = chip; - - string[] voltagePaths = Directory.GetFiles(path, "in*_input"); - Voltages = new float?[voltagePaths.Length]; - _voltageStreams = new FileStream[voltagePaths.Length]; - for (int i = 0; i < voltagePaths.Length; i++) - _voltageStreams[i] = new FileStream(voltagePaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - - string[] temperaturePaths = Directory.GetFiles(path, "temp*_input"); - Temperatures = new float?[temperaturePaths.Length]; - _temperatureStreams = new FileStream[temperaturePaths.Length]; - for (int i = 0; i < temperaturePaths.Length; i++) - _temperatureStreams[i] = new FileStream(temperaturePaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - - string[] fanPaths = Directory.GetFiles(path, "fan*_input"); - Fans = new float?[fanPaths.Length]; - _fanStreams = new FileStream[fanPaths.Length]; - for (int i = 0; i < fanPaths.Length; i++) - _fanStreams[i] = new FileStream(fanPaths[i], FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - - Controls = Array.Empty(); - } - - public Chip Chip { get; } - - public float?[] Controls { get; } - - public float?[] Fans { get; } - - public float?[] Temperatures { get; } - - public float?[] Voltages { get; } - - public byte? ReadGpio(int index) - { - return null; - } - - public void WriteGpio(int index, byte value) - { } - - public string GetReport() - { - return null; - } - - public void SetControl(int index, byte? value) - { } - - public void Update() - { - for (int i = 0; i < Voltages.Length; i++) - { - string s = ReadFirstLine(_voltageStreams[i]); - try - { - Voltages[i] = 0.001f * - long.Parse(s, CultureInfo.InvariantCulture); - } - catch - { - Voltages[i] = null; - } - } - - for (int i = 0; i < Temperatures.Length; i++) - { - string s = ReadFirstLine(_temperatureStreams[i]); - try - { - Temperatures[i] = 0.001f * - long.Parse(s, CultureInfo.InvariantCulture); - } - catch - { - Temperatures[i] = null; - } - } - - for (int i = 0; i < Fans.Length; i++) - { - string s = ReadFirstLine(_fanStreams[i]); - try - { - Fans[i] = long.Parse(s, CultureInfo.InvariantCulture); - } - catch - { - Fans[i] = null; - } - } - } - - private static string ReadFirstLine(Stream stream) - { - StringBuilder sb = new(); - try - { - stream.Seek(0, SeekOrigin.Begin); - int b = stream.ReadByte(); - while (b is not -1 and not 10) - { - sb.Append((char)b); - b = stream.ReadByte(); - } - } - catch - { } - - return sb.ToString(); - } - - public void Close() - { - foreach (FileStream stream in _voltageStreams) - stream.Close(); - - foreach (FileStream stream in _temperatureStreams) - stream.Close(); - - foreach (FileStream stream in _fanStreams) - stream.Close(); - } + foreach (FileStream stream in _fanStreams) + stream.Close(); } } } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs index cb3c26a..b7b0a2e 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LPcPort.cs @@ -4,97 +4,96 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal class LpcPort { - internal class LpcPort + public LpcPort(ushort registerPort, ushort valuePort) { - public LpcPort(ushort registerPort, ushort valuePort) - { - RegisterPort = registerPort; - ValuePort = valuePort; - } - - public ushort RegisterPort { get; } - - public ushort ValuePort { get; } - - public byte ReadByte(byte register) - { - Ring0.WriteIoPort(RegisterPort, register); - return Ring0.ReadIoPort(ValuePort); - } - - public void WriteByte(byte register, byte value) - { - Ring0.WriteIoPort(RegisterPort, register); - Ring0.WriteIoPort(ValuePort, value); - } - - public ushort ReadWord(byte register) - { - return (ushort)((ReadByte(register) << 8) | ReadByte((byte)(register + 1))); - } - - public void Select(byte logicalDeviceNumber) - { - Ring0.WriteIoPort(RegisterPort, DEVICE_SELECT_REGISTER); - Ring0.WriteIoPort(ValuePort, logicalDeviceNumber); - } - - public void WinbondNuvotonFintekEnter() - { - Ring0.WriteIoPort(RegisterPort, 0x87); - Ring0.WriteIoPort(RegisterPort, 0x87); - } - - public void WinbondNuvotonFintekExit() - { - Ring0.WriteIoPort(RegisterPort, 0xAA); - } - - public void NuvotonDisableIOSpaceLock() - { - byte options = ReadByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK); - // if the i/o space lock is enabled - if ((options & 0x10) > 0) - { - // disable the i/o space lock - WriteByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK, (byte)(options & ~0x10)); - } - } - - public void IT87Enter() - { - Ring0.WriteIoPort(RegisterPort, 0x87); - Ring0.WriteIoPort(RegisterPort, 0x01); - Ring0.WriteIoPort(RegisterPort, 0x55); - Ring0.WriteIoPort(RegisterPort, RegisterPort == 0x4E ? (byte)0xAA : (byte)0x55); - } - - public void IT87Exit() - { - // Do not exit config mode for secondary super IO. - if (RegisterPort != 0x4E) - { - Ring0.WriteIoPort(RegisterPort, CONFIGURATION_CONTROL_REGISTER); - Ring0.WriteIoPort(ValuePort, 0x02); - } - } - - public void SmscEnter() - { - Ring0.WriteIoPort(RegisterPort, 0x55); - } - - public void SmscExit() - { - Ring0.WriteIoPort(RegisterPort, 0xAA); - } - - // ReSharper disable InconsistentNaming - private const byte CONFIGURATION_CONTROL_REGISTER = 0x02; - private const byte DEVICE_SELECT_REGISTER = 0x07; - private const byte NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK = 0x28; - // ReSharper restore InconsistentNaming + RegisterPort = registerPort; + ValuePort = valuePort; } -} + + public ushort RegisterPort { get; } + + public ushort ValuePort { get; } + + public byte ReadByte(byte register) + { + Ring0.WriteIoPort(RegisterPort, register); + return Ring0.ReadIoPort(ValuePort); + } + + public void WriteByte(byte register, byte value) + { + Ring0.WriteIoPort(RegisterPort, register); + Ring0.WriteIoPort(ValuePort, value); + } + + public ushort ReadWord(byte register) + { + return (ushort)((ReadByte(register) << 8) | ReadByte((byte)(register + 1))); + } + + public void Select(byte logicalDeviceNumber) + { + Ring0.WriteIoPort(RegisterPort, DEVICE_SELECT_REGISTER); + Ring0.WriteIoPort(ValuePort, logicalDeviceNumber); + } + + public void WinbondNuvotonFintekEnter() + { + Ring0.WriteIoPort(RegisterPort, 0x87); + Ring0.WriteIoPort(RegisterPort, 0x87); + } + + public void WinbondNuvotonFintekExit() + { + Ring0.WriteIoPort(RegisterPort, 0xAA); + } + + public void NuvotonDisableIOSpaceLock() + { + byte options = ReadByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK); + // if the i/o space lock is enabled + if ((options & 0x10) > 0) + { + // disable the i/o space lock + WriteByte(NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK, (byte)(options & ~0x10)); + } + } + + public void IT87Enter() + { + Ring0.WriteIoPort(RegisterPort, 0x87); + Ring0.WriteIoPort(RegisterPort, 0x01); + Ring0.WriteIoPort(RegisterPort, 0x55); + Ring0.WriteIoPort(RegisterPort, RegisterPort == 0x4E ? (byte)0xAA : (byte)0x55); + } + + public void IT87Exit() + { + // Do not exit config mode for secondary super IO. + if (RegisterPort != 0x4E) + { + Ring0.WriteIoPort(RegisterPort, CONFIGURATION_CONTROL_REGISTER); + Ring0.WriteIoPort(ValuePort, 0x02); + } + } + + public void SmscEnter() + { + Ring0.WriteIoPort(RegisterPort, 0x55); + } + + public void SmscExit() + { + Ring0.WriteIoPort(RegisterPort, 0xAA); + } + + // ReSharper disable InconsistentNaming + private const byte CONFIGURATION_CONTROL_REGISTER = 0x02; + private const byte DEVICE_SELECT_REGISTER = 0x07; + private const byte NUVOTON_HARDWARE_MONITOR_IO_SPACE_LOCK = 0x28; + // ReSharper restore InconsistentNaming +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs index a615e5a..b81cafb 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/LpcIO.cs @@ -10,629 +10,628 @@ using System.Globalization; using System.Text; using System.Threading; -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal class LpcIO { - internal class LpcIO + private readonly StringBuilder _report = new(); + private readonly List _superIOs = new(); + + public LpcIO() { - private readonly StringBuilder _report = new(); - private readonly List _superIOs = new(); + if (!Ring0.IsOpen) + return; - public LpcIO() + if (!Ring0.WaitIsaBusMutex(100)) + return; + + Detect(); + + Ring0.ReleaseIsaBusMutex(); + } + + public ISuperIO[] SuperIO => _superIOs.ToArray(); + + private void ReportUnknownChip(LpcPort port, string type, int chip) + { + _report.Append("Chip ID: Unknown "); + _report.Append(type); + _report.Append(" with ID 0x"); + _report.Append(chip.ToString("X", CultureInfo.InvariantCulture)); + _report.Append(" at 0x"); + _report.Append(port.RegisterPort.ToString("X", CultureInfo.InvariantCulture)); + _report.Append("/0x"); + _report.AppendLine(port.ValuePort.ToString("X", CultureInfo.InvariantCulture)); + _report.AppendLine(); + } + + private bool DetectSmsc(LpcPort port) + { + port.SmscEnter(); + + ushort chipId = port.ReadWord(CHIP_ID_REGISTER); + + if (chipId is not 0 and not 0xffff) { - if (!Ring0.IsOpen) - return; - - if (!Ring0.WaitIsaBusMutex(100)) - return; - - Detect(); - - Ring0.ReleaseIsaBusMutex(); + port.SmscExit(); + ReportUnknownChip(port, "SMSC", chipId); } - public ISuperIO[] SuperIO => _superIOs.ToArray(); + return false; + } - private void ReportUnknownChip(LpcPort port, string type, int chip) + private void Detect() + { + for (int i = 0; i < REGISTER_PORTS.Length; i++) { - _report.Append("Chip ID: Unknown "); - _report.Append(type); - _report.Append(" with ID 0x"); - _report.Append(chip.ToString("X", CultureInfo.InvariantCulture)); - _report.Append(" at 0x"); - _report.Append(port.RegisterPort.ToString("X", CultureInfo.InvariantCulture)); - _report.Append("/0x"); - _report.AppendLine(port.ValuePort.ToString("X", CultureInfo.InvariantCulture)); - _report.AppendLine(); + var port = new LpcPort(REGISTER_PORTS[i], VALUE_PORTS[i]); + + if (DetectWinbondFintek(port)) continue; + + if (DetectIT87(port)) continue; + + if (DetectSmsc(port)) continue; + } + } + + public string GetReport() + { + if (_report.Length > 0) + { + return "LpcIO" + Environment.NewLine + Environment.NewLine + _report; } - private bool DetectSmsc(LpcPort port) + return null; + } + + private bool DetectWinbondFintek(LpcPort port) + { + port.WinbondNuvotonFintekEnter(); + + byte logicalDeviceNumber = 0; + byte id = port.ReadByte(CHIP_ID_REGISTER); + byte revision = port.ReadByte(CHIP_REVISION_REGISTER); + Chip chip = Chip.Unknown; + + switch (id) { - port.SmscEnter(); + case 0x05: + switch (revision) + { + case 0x07: + chip = Chip.F71858; + logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN; + break; + case 0x41: + chip = Chip.F71882; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + break; - ushort chipId = port.ReadWord(CHIP_ID_REGISTER); + case 0x06: + switch (revision) + { + case 0x01: + chip = Chip.F71862; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + break; + case 0x07: + switch (revision) + { + case 0x23: + chip = Chip.F71889F; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x08: + switch (revision) + { + case 0x14: + chip = Chip.F71869; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x09: + switch (revision) + { + case 0x01: + chip = Chip.F71808E; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + case 0x09: + chip = Chip.F71889ED; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x10: + switch (revision) + { + case 0x05: + chip = Chip.F71889AD; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + case 0x07: + chip = Chip.F71869A; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x11: + switch (revision) + { + case 0x06: + chip = Chip.F71878AD; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + case 0x18: + chip = Chip.F71811; + logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x52: + switch (revision) + { + case 0x17: + case 0x3A: + case 0x41: + chip = Chip.W83627HF; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x82: + switch (revision & 0xF0) + { + case 0x80: + chip = Chip.W83627THF; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x85: + switch (revision) + { + case 0x41: + chip = Chip.W83687THF; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0x88: + switch (revision & 0xF0) + { + case 0x50: + case 0x60: + chip = Chip.W83627EHF; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xA0: + switch (revision & 0xF0) + { + case 0x20: + chip = Chip.W83627DHG; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xA5: + switch (revision & 0xF0) + { + case 0x10: + chip = Chip.W83667HG; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xB0: + switch (revision & 0xF0) + { + case 0x70: + chip = Chip.W83627DHGP; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xB3: + switch (revision & 0xF0) + { + case 0x50: + chip = Chip.W83667HGB; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xB4: + switch (revision & 0xF0) + { + case 0x70: + chip = Chip.NCT6771F; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xC3: + switch (revision & 0xF0) + { + case 0x30: + chip = Chip.NCT6776F; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xC4: + switch (revision & 0xF0) + { + case 0x50: + chip = Chip.NCT610XD; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xC5: + switch (revision & 0xF0) + { + case 0x60: + chip = Chip.NCT6779D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xC8: + switch (revision) + { + case 0x03: + chip = Chip.NCT6791D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xC9: + switch (revision) + { + case 0x11: + chip = Chip.NCT6792D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + case 0x13: + chip = Chip.NCT6792DA; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xD1: + switch (revision) + { + case 0x21: + chip = Chip.NCT6793D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xD3: + switch (revision) + { + case 0x52: + chip = Chip.NCT6795D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xD4: + switch (revision) + { + case 0x23: + chip = Chip.NCT6796D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + case 0x2A: + chip = Chip.NCT6796DR; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + case 0x51: + chip = Chip.NCT6797D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + case 0x2B: + chip = Chip.NCT6798D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 0xD5: + switch (revision) + { + case 0x92: + chip = Chip.NCT6687D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + + case 199: + switch (revision) + { + case 50: + chip = Chip.NCT6683D; + logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; + break; + } + break; + } + + if (chip == Chip.Unknown) + { + if (id is not 0 and not 0xff) + { + port.WinbondNuvotonFintekExit(); + ReportUnknownChip(port, "Winbond / Nuvoton / Fintek", (id << 8) | revision); + } + } + else + { + port.Select(logicalDeviceNumber); + ushort address = port.ReadWord(BASE_ADDRESS_REGISTER); + Thread.Sleep(1); + ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER); + + ushort vendorId = port.ReadWord(FINTEK_VENDOR_ID_REGISTER); + + // disable the hardware monitor i/o space lock on NCT679XD chips + if (address == verify && + chip is Chip.NCT6791D or Chip.NCT6792D or Chip.NCT6792DA or Chip.NCT6793D or Chip.NCT6795D or Chip.NCT6796D or Chip.NCT6796DR or Chip.NCT6798D or Chip.NCT6797D) + { + port.NuvotonDisableIOSpaceLock(); + } + + port.WinbondNuvotonFintekExit(); + + if (address != verify) + { + _report.Append("Chip ID: 0x"); + _report.AppendLine(chip.ToString("X")); + _report.Append("Chip revision: 0x"); + _report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); + _report.AppendLine("Error: Address verification failed"); + _report.AppendLine(); + + return false; + } + + // some Fintek chips have address register offset 0x05 added already + if ((address & 0x07) == 0x05) + address &= 0xFFF8; + + if (address < 0x100 || (address & 0xF007) != 0) + { + _report.Append("Chip ID: 0x"); + _report.AppendLine(chip.ToString("X")); + _report.Append("Chip revision: 0x"); + _report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); + _report.Append("Error: Invalid address 0x"); + _report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture)); + _report.AppendLine(); + + return false; + } + + switch (chip) + { + case Chip.W83627DHG: + case Chip.W83627DHGP: + case Chip.W83627EHF: + case Chip.W83627HF: + case Chip.W83627THF: + case Chip.W83667HG: + case Chip.W83667HGB: + case Chip.W83687THF: + _superIOs.Add(new W836XX(chip, revision, address)); + break; + + case Chip.NCT610XD: + case Chip.NCT6771F: + case Chip.NCT6776F: + case Chip.NCT6779D: + case Chip.NCT6791D: + case Chip.NCT6792D: + case Chip.NCT6792DA: + case Chip.NCT6793D: + case Chip.NCT6795D: + case Chip.NCT6796D: + case Chip.NCT6796DR: + case Chip.NCT6797D: + case Chip.NCT6798D: + case Chip.NCT6687D: + case Chip.NCT6683D: + _superIOs.Add(new Nct677X(chip, revision, address, port)); + break; + + case Chip.F71858: + case Chip.F71862: + case Chip.F71869: + case Chip.F71878AD: + case Chip.F71869A: + case Chip.F71882: + case Chip.F71889AD: + case Chip.F71889ED: + case Chip.F71889F: + case Chip.F71808E: + if (vendorId != FINTEK_VENDOR_ID) + { + _report.Append("Chip ID: 0x"); + _report.AppendLine(chip.ToString("X")); + _report.Append("Chip revision: 0x"); + _report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); + _report.Append("Error: Invalid vendor ID 0x"); + _report.AppendLine(vendorId.ToString("X", CultureInfo.InvariantCulture)); + _report.AppendLine(); + + return false; + } + + _superIOs.Add(new F718XX(chip, address)); + break; + } + + return true; + } + + return false; + } + + private bool DetectIT87(LpcPort port) + { + // IT87XX can enter only on port 0x2E + // IT8792 using 0x4E + if (port.RegisterPort is not 0x2E and not 0x4E) + return false; + + port.IT87Enter(); + + ushort chipId = port.ReadWord(CHIP_ID_REGISTER); + Chip chip = chipId switch + { + 0x8613 => Chip.IT8613E, + 0x8620 => Chip.IT8620E, + 0x8628 => Chip.IT8628E, + 0x8631 => Chip.IT8631E, + 0x8665 => Chip.IT8665E, + 0x8655 => Chip.IT8655E, + 0x8686 => Chip.IT8686E, + 0x8688 => Chip.IT8688E, + 0x8689 => Chip.IT8689E, + 0x8695 => Chip.IT8695E, + 0x8705 => Chip.IT8705F, + 0x8712 => Chip.IT8712F, + 0x8716 => Chip.IT8716F, + 0x8718 => Chip.IT8718F, + 0x8720 => Chip.IT8720F, + 0x8721 => Chip.IT8721F, + 0x8726 => Chip.IT8726F, + 0x8728 => Chip.IT8728F, + 0x8771 => Chip.IT8771E, + 0x8772 => Chip.IT8772E, + 0x8733 => Chip.IT879XE, + _ => Chip.Unknown + }; + + if (chip == Chip.Unknown) + { if (chipId is not 0 and not 0xffff) { - port.SmscExit(); - ReportUnknownChip(port, "SMSC", chipId); - } - - return false; - } - - private void Detect() - { - for (int i = 0; i < REGISTER_PORTS.Length; i++) - { - var port = new LpcPort(REGISTER_PORTS[i], VALUE_PORTS[i]); - - if (DetectWinbondFintek(port)) continue; - - if (DetectIT87(port)) continue; - - if (DetectSmsc(port)) continue; - } - } - - public string GetReport() - { - if (_report.Length > 0) - { - return "LpcIO" + Environment.NewLine + Environment.NewLine + _report; - } - - return null; - } - - private bool DetectWinbondFintek(LpcPort port) - { - port.WinbondNuvotonFintekEnter(); - - byte logicalDeviceNumber = 0; - byte id = port.ReadByte(CHIP_ID_REGISTER); - byte revision = port.ReadByte(CHIP_REVISION_REGISTER); - Chip chip = Chip.Unknown; - - switch (id) - { - case 0x05: - switch (revision) - { - case 0x07: - chip = Chip.F71858; - logicalDeviceNumber = F71858_HARDWARE_MONITOR_LDN; - break; - case 0x41: - chip = Chip.F71882; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x06: - switch (revision) - { - case 0x01: - chip = Chip.F71862; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x07: - switch (revision) - { - case 0x23: - chip = Chip.F71889F; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x08: - switch (revision) - { - case 0x14: - chip = Chip.F71869; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x09: - switch (revision) - { - case 0x01: - chip = Chip.F71808E; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - case 0x09: - chip = Chip.F71889ED; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x10: - switch (revision) - { - case 0x05: - chip = Chip.F71889AD; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - case 0x07: - chip = Chip.F71869A; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x11: - switch (revision) - { - case 0x06: - chip = Chip.F71878AD; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - case 0x18: - chip = Chip.F71811; - logicalDeviceNumber = FINTEK_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x52: - switch (revision) - { - case 0x17: - case 0x3A: - case 0x41: - chip = Chip.W83627HF; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x82: - switch (revision & 0xF0) - { - case 0x80: - chip = Chip.W83627THF; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x85: - switch (revision) - { - case 0x41: - chip = Chip.W83687THF; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0x88: - switch (revision & 0xF0) - { - case 0x50: - case 0x60: - chip = Chip.W83627EHF; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xA0: - switch (revision & 0xF0) - { - case 0x20: - chip = Chip.W83627DHG; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xA5: - switch (revision & 0xF0) - { - case 0x10: - chip = Chip.W83667HG; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xB0: - switch (revision & 0xF0) - { - case 0x70: - chip = Chip.W83627DHGP; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xB3: - switch (revision & 0xF0) - { - case 0x50: - chip = Chip.W83667HGB; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xB4: - switch (revision & 0xF0) - { - case 0x70: - chip = Chip.NCT6771F; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xC3: - switch (revision & 0xF0) - { - case 0x30: - chip = Chip.NCT6776F; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xC4: - switch (revision & 0xF0) - { - case 0x50: - chip = Chip.NCT610XD; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xC5: - switch (revision & 0xF0) - { - case 0x60: - chip = Chip.NCT6779D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xC8: - switch (revision) - { - case 0x03: - chip = Chip.NCT6791D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xC9: - switch (revision) - { - case 0x11: - chip = Chip.NCT6792D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - case 0x13: - chip = Chip.NCT6792DA; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xD1: - switch (revision) - { - case 0x21: - chip = Chip.NCT6793D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xD3: - switch (revision) - { - case 0x52: - chip = Chip.NCT6795D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xD4: - switch (revision) - { - case 0x23: - chip = Chip.NCT6796D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - case 0x2A: - chip = Chip.NCT6796DR; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - case 0x51: - chip = Chip.NCT6797D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - case 0x2B: - chip = Chip.NCT6798D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 0xD5: - switch (revision) - { - case 0x92: - chip = Chip.NCT6687D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - - case 199: - switch (revision) - { - case 50: - chip = Chip.NCT6683D; - logicalDeviceNumber = WINBOND_NUVOTON_HARDWARE_MONITOR_LDN; - break; - } - break; - } - - if (chip == Chip.Unknown) - { - if (id is not 0 and not 0xff) - { - port.WinbondNuvotonFintekExit(); - ReportUnknownChip(port, "Winbond / Nuvoton / Fintek", (id << 8) | revision); - } - } - else - { - port.Select(logicalDeviceNumber); - ushort address = port.ReadWord(BASE_ADDRESS_REGISTER); - Thread.Sleep(1); - ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER); - - ushort vendorId = port.ReadWord(FINTEK_VENDOR_ID_REGISTER); - - // disable the hardware monitor i/o space lock on NCT679XD chips - if (address == verify && - chip is Chip.NCT6791D or Chip.NCT6792D or Chip.NCT6792DA or Chip.NCT6793D or Chip.NCT6795D or Chip.NCT6796D or Chip.NCT6796DR or Chip.NCT6798D or Chip.NCT6797D) - { - port.NuvotonDisableIOSpaceLock(); - } - - port.WinbondNuvotonFintekExit(); - - if (address != verify) - { - _report.Append("Chip ID: 0x"); - _report.AppendLine(chip.ToString("X")); - _report.Append("Chip revision: 0x"); - _report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); - _report.AppendLine("Error: Address verification failed"); - _report.AppendLine(); - - return false; - } - - // some Fintek chips have address register offset 0x05 added already - if ((address & 0x07) == 0x05) - address &= 0xFFF8; - - if (address < 0x100 || (address & 0xF007) != 0) - { - _report.Append("Chip ID: 0x"); - _report.AppendLine(chip.ToString("X")); - _report.Append("Chip revision: 0x"); - _report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); - _report.Append("Error: Invalid address 0x"); - _report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture)); - _report.AppendLine(); - - return false; - } - - switch (chip) - { - case Chip.W83627DHG: - case Chip.W83627DHGP: - case Chip.W83627EHF: - case Chip.W83627HF: - case Chip.W83627THF: - case Chip.W83667HG: - case Chip.W83667HGB: - case Chip.W83687THF: - _superIOs.Add(new W836XX(chip, revision, address)); - break; - - case Chip.NCT610XD: - case Chip.NCT6771F: - case Chip.NCT6776F: - case Chip.NCT6779D: - case Chip.NCT6791D: - case Chip.NCT6792D: - case Chip.NCT6792DA: - case Chip.NCT6793D: - case Chip.NCT6795D: - case Chip.NCT6796D: - case Chip.NCT6796DR: - case Chip.NCT6797D: - case Chip.NCT6798D: - case Chip.NCT6687D: - case Chip.NCT6683D: - _superIOs.Add(new Nct677X(chip, revision, address, port)); - break; - - case Chip.F71858: - case Chip.F71862: - case Chip.F71869: - case Chip.F71878AD: - case Chip.F71869A: - case Chip.F71882: - case Chip.F71889AD: - case Chip.F71889ED: - case Chip.F71889F: - case Chip.F71808E: - if (vendorId != FINTEK_VENDOR_ID) - { - _report.Append("Chip ID: 0x"); - _report.AppendLine(chip.ToString("X")); - _report.Append("Chip revision: 0x"); - _report.AppendLine(revision.ToString("X", CultureInfo.InvariantCulture)); - _report.Append("Error: Invalid vendor ID 0x"); - _report.AppendLine(vendorId.ToString("X", CultureInfo.InvariantCulture)); - _report.AppendLine(); - - return false; - } - - _superIOs.Add(new F718XX(chip, address)); - break; - } - - return true; - } - - return false; - } - - private bool DetectIT87(LpcPort port) - { - // IT87XX can enter only on port 0x2E - // IT8792 using 0x4E - if (port.RegisterPort is not 0x2E and not 0x4E) - return false; - - port.IT87Enter(); - - ushort chipId = port.ReadWord(CHIP_ID_REGISTER); - Chip chip = chipId switch - { - 0x8613 => Chip.IT8613E, - 0x8620 => Chip.IT8620E, - 0x8628 => Chip.IT8628E, - 0x8631 => Chip.IT8631E, - 0x8665 => Chip.IT8665E, - 0x8655 => Chip.IT8655E, - 0x8686 => Chip.IT8686E, - 0x8688 => Chip.IT8688E, - 0x8689 => Chip.IT8689E, - 0x8695 => Chip.IT8695E, - 0x8705 => Chip.IT8705F, - 0x8712 => Chip.IT8712F, - 0x8716 => Chip.IT8716F, - 0x8718 => Chip.IT8718F, - 0x8720 => Chip.IT8720F, - 0x8721 => Chip.IT8721F, - 0x8726 => Chip.IT8726F, - 0x8728 => Chip.IT8728F, - 0x8771 => Chip.IT8771E, - 0x8772 => Chip.IT8772E, - 0x8733 => Chip.IT879XE, - _ => Chip.Unknown - }; - - if (chip == Chip.Unknown) - { - if (chipId is not 0 and not 0xffff) - { - port.IT87Exit(); - - ReportUnknownChip(port, "ITE", chipId); - } - } - else - { - port.Select(IT87_ENVIRONMENT_CONTROLLER_LDN); - - ushort address = port.ReadWord(BASE_ADDRESS_REGISTER); - Thread.Sleep(1); - ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER); - - byte version = (byte)(port.ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F); - - ushort gpioAddress; - ushort gpioVerify; - - if (chip == Chip.IT8705F) - { - port.Select(IT8705_GPIO_LDN); - gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER); - Thread.Sleep(1); - gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER); - } - else - { - port.Select(IT87XX_GPIO_LDN); - gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER + 2); - Thread.Sleep(1); - gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER + 2); - } - port.IT87Exit(); - if (address != verify || address < 0x100 || (address & 0xF007) != 0) - { - _report.Append("Chip ID: 0x"); - _report.AppendLine(chip.ToString("X")); - _report.Append("Error: Invalid address 0x"); - _report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture)); - _report.AppendLine(); + ReportUnknownChip(port, "ITE", chipId); + } + } + else + { + port.Select(IT87_ENVIRONMENT_CONTROLLER_LDN); - return false; - } + ushort address = port.ReadWord(BASE_ADDRESS_REGISTER); + Thread.Sleep(1); + ushort verify = port.ReadWord(BASE_ADDRESS_REGISTER); - if (gpioAddress != gpioVerify || gpioAddress < 0x100 || (gpioAddress & 0xF007) != 0) - { - _report.Append("Chip ID: 0x"); - _report.AppendLine(chip.ToString("X")); - _report.Append("Error: Invalid GPIO address 0x"); - _report.AppendLine(gpioAddress.ToString("X", CultureInfo.InvariantCulture)); - _report.AppendLine(); + byte version = (byte)(port.ReadByte(IT87_CHIP_VERSION_REGISTER) & 0x0F); - return false; - } + ushort gpioAddress; + ushort gpioVerify; - _superIOs.Add(new IT87XX(chip, address, gpioAddress, version)); - return true; + if (chip == Chip.IT8705F) + { + port.Select(IT8705_GPIO_LDN); + gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER); + Thread.Sleep(1); + gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER); + } + else + { + port.Select(IT87XX_GPIO_LDN); + gpioAddress = port.ReadWord(BASE_ADDRESS_REGISTER + 2); + Thread.Sleep(1); + gpioVerify = port.ReadWord(BASE_ADDRESS_REGISTER + 2); } - return false; + port.IT87Exit(); + + if (address != verify || address < 0x100 || (address & 0xF007) != 0) + { + _report.Append("Chip ID: 0x"); + _report.AppendLine(chip.ToString("X")); + _report.Append("Error: Invalid address 0x"); + _report.AppendLine(address.ToString("X", CultureInfo.InvariantCulture)); + _report.AppendLine(); + + return false; + } + + if (gpioAddress != gpioVerify || gpioAddress < 0x100 || (gpioAddress & 0xF007) != 0) + { + _report.Append("Chip ID: 0x"); + _report.AppendLine(chip.ToString("X")); + _report.Append("Error: Invalid GPIO address 0x"); + _report.AppendLine(gpioAddress.ToString("X", CultureInfo.InvariantCulture)); + _report.AppendLine(); + + return false; + } + + _superIOs.Add(new IT87XX(chip, address, gpioAddress, version)); + return true; } - // ReSharper disable InconsistentNaming - private const byte BASE_ADDRESS_REGISTER = 0x60; - private const byte CHIP_ID_REGISTER = 0x20; - private const byte CHIP_REVISION_REGISTER = 0x21; - - private const byte F71858_HARDWARE_MONITOR_LDN = 0x02; - private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04; - private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04; - private const byte IT8705_GPIO_LDN = 0x05; - private const byte IT87XX_GPIO_LDN = 0x07; - private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B; - - private const ushort FINTEK_VENDOR_ID = 0x1934; - - private const byte FINTEK_VENDOR_ID_REGISTER = 0x23; - private const byte IT87_CHIP_VERSION_REGISTER = 0x22; - - private readonly ushort[] REGISTER_PORTS = { 0x2E, 0x4E }; - private readonly ushort[] VALUE_PORTS = { 0x2F, 0x4F }; - // ReSharper restore InconsistentNaming + return false; } + + // ReSharper disable InconsistentNaming + private const byte BASE_ADDRESS_REGISTER = 0x60; + private const byte CHIP_ID_REGISTER = 0x20; + private const byte CHIP_REVISION_REGISTER = 0x21; + + private const byte F71858_HARDWARE_MONITOR_LDN = 0x02; + private const byte FINTEK_HARDWARE_MONITOR_LDN = 0x04; + private const byte IT87_ENVIRONMENT_CONTROLLER_LDN = 0x04; + private const byte IT8705_GPIO_LDN = 0x05; + private const byte IT87XX_GPIO_LDN = 0x07; + private const byte WINBOND_NUVOTON_HARDWARE_MONITOR_LDN = 0x0B; + + private const ushort FINTEK_VENDOR_ID = 0x1934; + + private const byte FINTEK_VENDOR_ID_REGISTER = 0x23; + private const byte IT87_CHIP_VERSION_REGISTER = 0x22; + + private readonly ushort[] REGISTER_PORTS = { 0x2E, 0x4E }; + private readonly ushort[] VALUE_PORTS = { 0x2F, 0x4F }; + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs index b5e857e..d040c9b 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/Nct677X.cs @@ -11,987 +11,986 @@ using System.Globalization; using System.Text; using System.Threading; -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal class Nct677X : ISuperIO { - internal class Nct677X : ISuperIO + private readonly struct TemperatureSourceData { - private readonly struct TemperatureSourceData + public TemperatureSourceData(Enum source, ushort register, ushort halfRegister = 0, int halfBit = -1, ushort sourceRegister = 0, ushort? alternateRegister = null) { - public TemperatureSourceData(Enum source, ushort register, ushort halfRegister = 0, int halfBit = -1, ushort sourceRegister = 0, ushort? alternateRegister = null) - { - Source = source; - Register = register; - HalfRegister = halfRegister; - HalfBit = halfBit; - SourceRegister = sourceRegister; - AlternateRegister = alternateRegister; - } - public readonly Enum Source; - public readonly ushort Register; - public readonly ushort HalfRegister; - public readonly int HalfBit; - public readonly ushort SourceRegister; - public readonly ushort? AlternateRegister; + Source = source; + Register = register; + HalfRegister = halfRegister; + HalfBit = halfBit; + SourceRegister = sourceRegister; + AlternateRegister = alternateRegister; + } + public readonly Enum Source; + public readonly ushort Register; + public readonly ushort HalfRegister; + public readonly int HalfBit; + public readonly ushort SourceRegister; + public readonly ushort? AlternateRegister; + } + + private readonly ushort[] _fanCountRegister; + private readonly ushort[] _fanRpmRegister; + private readonly byte[] _initialFanControlMode = new byte[7]; + private readonly byte[] _initialFanPwmCommand = new byte[7]; + private readonly bool _isNuvotonVendor; + private readonly LpcPort _lpcPort; + private readonly int _maxFanCount; + private readonly int _minFanCount; + private readonly int _minFanRpm; + private readonly ushort _port; + private readonly bool[] _restoreDefaultFanControlRequired = new bool[7]; + private readonly byte _revision; + private readonly TemperatureSourceData[] _temperaturesSource; + private readonly ushort _vBatMonitorControlRegister; + private readonly ushort[] _voltageRegisters; + private readonly ushort _voltageVBatRegister; + + public Nct677X(Chip chip, byte revision, ushort port, LpcPort lpcPort) + { + Chip = chip; + _revision = revision; + _port = port; + _lpcPort = lpcPort; + + if (chip == Chip.NCT610XD) + { + VENDOR_ID_HIGH_REGISTER = 0x80FE; + VENDOR_ID_LOW_REGISTER = 0x00FE; + + FAN_PWM_OUT_REG = new ushort[] { 0x04A, 0x04B, 0x04C }; + FAN_PWM_COMMAND_REG = new ushort[] { 0x119, 0x129, 0x139 }; + FAN_CONTROL_MODE_REG = new ushort[] { 0x113, 0x123, 0x133 }; + + _vBatMonitorControlRegister = 0x0318; + } + else if (chip is Chip.NCT6687D or Chip.NCT6683D) + { + FAN_PWM_OUT_REG = new ushort[] { 0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167 }; + FAN_PWM_COMMAND_REG = new ushort[] { 0xA28, 0xA29, 0xA2A, 0xA2B, 0xA2C, 0xA2D, 0xA2E, 0xA2F }; + FAN_CONTROL_MODE_REG = new ushort[] { 0xA00, 0xA00, 0xA00, 0xA00, 0xA00, 0xA00, 0xA00, 0xA00 }; + FAN_PWM_REQUEST_REG = new ushort[] { 0xA01, 0xA01, 0xA01, 0xA01, 0xA01, 0xA01, 0xA01, 0xA01 }; + } + else + { + VENDOR_ID_HIGH_REGISTER = 0x804F; + VENDOR_ID_LOW_REGISTER = 0x004F; + + FAN_PWM_OUT_REG = chip is Chip.NCT6797D or Chip.NCT6798D + ? new ushort[] { 0x001, 0x003, 0x011, 0x013, 0x015, 0xA09, 0xB09 } + : new ushort[] { 0x001, 0x003, 0x011, 0x013, 0x015, 0x017, 0x029 }; + + FAN_PWM_COMMAND_REG = new ushort[] { 0x109, 0x209, 0x309, 0x809, 0x909, 0xA09, 0xB09 }; + FAN_CONTROL_MODE_REG = new ushort[] { 0x102, 0x202, 0x302, 0x802, 0x902, 0xA02, 0xB02 }; + + _vBatMonitorControlRegister = 0x005D; } - private readonly ushort[] _fanCountRegister; - private readonly ushort[] _fanRpmRegister; - private readonly byte[] _initialFanControlMode = new byte[7]; - private readonly byte[] _initialFanPwmCommand = new byte[7]; - private readonly bool _isNuvotonVendor; - private readonly LpcPort _lpcPort; - private readonly int _maxFanCount; - private readonly int _minFanCount; - private readonly int _minFanRpm; - private readonly ushort _port; - private readonly bool[] _restoreDefaultFanControlRequired = new bool[7]; - private readonly byte _revision; - private readonly TemperatureSourceData[] _temperaturesSource; - private readonly ushort _vBatMonitorControlRegister; - private readonly ushort[] _voltageRegisters; - private readonly ushort _voltageVBatRegister; + _isNuvotonVendor = IsNuvotonVendor(); - public Nct677X(Chip chip, byte revision, ushort port, LpcPort lpcPort) + if (!_isNuvotonVendor) + return; + + switch (chip) { - Chip = chip; - _revision = revision; - _port = port; - _lpcPort = lpcPort; + case Chip.NCT6771F: + case Chip.NCT6776F: + if (chip == Chip.NCT6771F) + { + Fans = new float?[4]; - if (chip == Chip.NCT610XD) - { - VENDOR_ID_HIGH_REGISTER = 0x80FE; - VENDOR_ID_LOW_REGISTER = 0x00FE; - - FAN_PWM_OUT_REG = new ushort[] { 0x04A, 0x04B, 0x04C }; - FAN_PWM_COMMAND_REG = new ushort[] { 0x119, 0x129, 0x139 }; - FAN_CONTROL_MODE_REG = new ushort[] { 0x113, 0x123, 0x133 }; - - _vBatMonitorControlRegister = 0x0318; - } - else if (chip is Chip.NCT6687D or Chip.NCT6683D) - { - FAN_PWM_OUT_REG = new ushort[] { 0x160, 0x161, 0x162, 0x163, 0x164, 0x165, 0x166, 0x167 }; - FAN_PWM_COMMAND_REG = new ushort[] { 0xA28, 0xA29, 0xA2A, 0xA2B, 0xA2C, 0xA2D, 0xA2E, 0xA2F }; - FAN_CONTROL_MODE_REG = new ushort[] { 0xA00, 0xA00, 0xA00, 0xA00, 0xA00, 0xA00, 0xA00, 0xA00 }; - FAN_PWM_REQUEST_REG = new ushort[] { 0xA01, 0xA01, 0xA01, 0xA01, 0xA01, 0xA01, 0xA01, 0xA01 }; - } - else - { - VENDOR_ID_HIGH_REGISTER = 0x804F; - VENDOR_ID_LOW_REGISTER = 0x004F; - - FAN_PWM_OUT_REG = chip is Chip.NCT6797D or Chip.NCT6798D - ? new ushort[] { 0x001, 0x003, 0x011, 0x013, 0x015, 0xA09, 0xB09 } - : new ushort[] { 0x001, 0x003, 0x011, 0x013, 0x015, 0x017, 0x029 }; - - FAN_PWM_COMMAND_REG = new ushort[] { 0x109, 0x209, 0x309, 0x809, 0x909, 0xA09, 0xB09 }; - FAN_CONTROL_MODE_REG = new ushort[] { 0x102, 0x202, 0x302, 0x802, 0x902, 0xA02, 0xB02 }; - - _vBatMonitorControlRegister = 0x005D; - } - - _isNuvotonVendor = IsNuvotonVendor(); - - if (!_isNuvotonVendor) - return; - - switch (chip) - { - case Chip.NCT6771F: - case Chip.NCT6776F: - if (chip == Chip.NCT6771F) - { - Fans = new float?[4]; - - // min value RPM value with 16-bit fan counter - _minFanRpm = (int)(1.35e6 / 0xFFFF); - } - else - { - Fans = new float?[5]; - - // min value RPM value with 13-bit fan counter - _minFanRpm = (int)(1.35e6 / 0x1FFF); - } - - _fanRpmRegister = new ushort[5]; - for (int i = 0; i < _fanRpmRegister.Length; i++) - _fanRpmRegister[i] = (ushort)(0x656 + (i << 1)); - - Controls = new float?[3]; - - Voltages = new float?[9]; - _voltageRegisters = new ushort[] { 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x550, 0x551 }; - _voltageVBatRegister = 0x551; - _temperaturesSource = new TemperatureSourceData[] - { - new(chip == Chip.NCT6771F ? SourceNct6771F.PECI_0 : SourceNct6776F.PECI_0, 0x027, 0, -1, 0x621), - new(chip == Chip.NCT6771F ? SourceNct6771F.CPUTIN : SourceNct6776F.CPUTIN, 0x073, 0x074, 7, 0x100), - new(chip == Chip.NCT6771F ? SourceNct6771F.AUXTIN : SourceNct6776F.AUXTIN, 0x075, 0x076, 7, 0x200), - new(chip == Chip.NCT6771F ? SourceNct6771F.SYSTIN : SourceNct6776F.SYSTIN, 0x077, 0x078, 7, 0x300), - new(null, 0x150, 0x151, 7, 0x622), - new(null, 0x250, 0x251, 7, 0x623), - new(null, 0x62B, 0x62E, 0, 0x624), - new(null, 0x62C, 0x62E, 1, 0x625), - new(null, 0x62D, 0x62E, 2, 0x626) - }; - - Temperatures = new float?[4]; - break; - - case Chip.NCT6779D: - case Chip.NCT6791D: - case Chip.NCT6792D: - case Chip.NCT6792DA: - case Chip.NCT6793D: - case Chip.NCT6795D: - case Chip.NCT6796D: - case Chip.NCT6796DR: - case Chip.NCT6797D: - case Chip.NCT6798D: - switch (chip) - { - case Chip.NCT6779D: - Fans = new float?[5]; - Controls = new float?[5]; - break; - - case Chip.NCT6796DR: - case Chip.NCT6797D: - case Chip.NCT6798D: - Fans = new float?[7]; - Controls = new float?[7]; - break; - - default: - Fans = new float?[6]; - Controls = new float?[6]; - break; - } - - _fanCountRegister = new ushort[] { 0x4B0, 0x4B2, 0x4B4, 0x4B6, 0x4B8, 0x4BA, 0x4CC }; - - // max value for 13-bit fan counter - _maxFanCount = 0x1FFF; - - // min value that could be transferred to 16-bit RPM registers - _minFanCount = 0x15; - - Voltages = new float?[15]; - _voltageRegisters = new ushort[] { 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487, 0x488, 0x489, 0x48A, 0x48B, 0x48C, 0x48D, 0x48E }; - _voltageVBatRegister = 0x488; - var temperaturesSources = new List(); - - switch (chip) - { - case Chip.NCT6796D: - case Chip.NCT6796DR: - case Chip.NCT6797D: - case Chip.NCT6798D: - temperaturesSources.AddRange(new TemperatureSourceData[] - { - new(SourceNct67Xxd.PECI_0, 0x073, 0x074, 7, 0x100), - new(SourceNct67Xxd.CPUTIN, 0x075, 0x076, 7, 0x200, 0x491), - new(SourceNct67Xxd.SYSTIN, 0x077, 0x078, 7, 0x300, 0x490), - new(SourceNct67Xxd.AUXTIN0, 0x079, 0x07A, 7, 0x800, 0x492), - new(SourceNct67Xxd.AUXTIN1, 0x07B, 0x07C, 7, 0x900, 0x493), - new(SourceNct67Xxd.AUXTIN2, 0x07D, 0x07E, 7, 0xA00, 0x494), - new(SourceNct67Xxd.AUXTIN3, 0x4A0, 0x49E, 6, 0xB00, 0x495), - new(SourceNct67Xxd.AUXTIN4, 0x027, 0, -1, 0x621), - new(SourceNct67Xxd.SMBUSMASTER0, 0x150, 0x151, 7, 0x622), - new(SourceNct67Xxd.SMBUSMASTER1, 0x670, 0, -1, 0xC26), - new(SourceNct67Xxd.PECI_1, 0x672, 0, -1, 0xC27), - new(SourceNct67Xxd.PCH_CHIP_CPU_MAX_TEMP, 0x674, 0, -1, 0xC28, 0x400), - new(SourceNct67Xxd.PCH_CHIP_TEMP, 0x676, 0, -1, 0xC29, 0x401), - new(SourceNct67Xxd.PCH_CPU_TEMP, 0x678, 0, -1, 0xC2A, 0x402), - new(SourceNct67Xxd.PCH_MCH_TEMP, 0x67A, 0, -1, 0xC2B, 0x404), - new(SourceNct67Xxd.AGENT0_DIMM0, 0), - new(SourceNct67Xxd.AGENT0_DIMM1, 0), - new(SourceNct67Xxd.AGENT1_DIMM0, 0), - new(SourceNct67Xxd.AGENT1_DIMM1, 0), - new(SourceNct67Xxd.BYTE_TEMP0, 0), - new(SourceNct67Xxd.BYTE_TEMP1, 0), - new(SourceNct67Xxd.PECI_0_CAL, 0), - new(SourceNct67Xxd.PECI_1_CAL, 0), - new(SourceNct67Xxd.VIRTUAL_TEMP, 0) - }); - break; - - default: - temperaturesSources.AddRange(new TemperatureSourceData[] - { - new(SourceNct67Xxd.PECI_0, 0x027, 0, -1, 0x621), - new(SourceNct67Xxd.CPUTIN, 0x073, 0x074, 7, 0x100, 0x491), - new(SourceNct67Xxd.SYSTIN, 0x075, 0x076, 7, 0x200, 0x490), - new(SourceNct67Xxd.AUXTIN0, 0x077, 0x078, 7, 0x300, 0x492), - new(SourceNct67Xxd.AUXTIN1, 0x079, 0x07A, 7, 0x800, 0x493), - new(SourceNct67Xxd.AUXTIN2, 0x07B, 0x07C, 7, 0x900, 0x494), - new(SourceNct67Xxd.AUXTIN3, 0x150, 0x151, 7, 0x622, 0x495) - }); - break; - } - - _temperaturesSource = temperaturesSources.ToArray(); - Temperatures = new float?[_temperaturesSource.Length]; - break; - - case Chip.NCT610XD: - Fans = new float?[3]; - Controls = new float?[3]; - - _fanRpmRegister = new ushort[3]; - for (int i = 0; i < _fanRpmRegister.Length; i++) - _fanRpmRegister[i] = (ushort)(0x030 + (i << 1)); + // min value RPM value with 16-bit fan counter + _minFanRpm = (int)(1.35e6 / 0xFFFF); + } + else + { + Fans = new float?[5]; // min value RPM value with 13-bit fan counter _minFanRpm = (int)(1.35e6 / 0x1FFF); - - Voltages = new float?[9]; - _voltageRegisters = new ushort[] { 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x307, 0x308, 0x309 }; - _voltageVBatRegister = 0x308; - Temperatures = new float?[4]; - _temperaturesSource = new TemperatureSourceData[] { - new(SourceNct610X.PECI_0, 0x027, 0, -1, 0x621), - new(SourceNct610X.SYSTIN, 0x018, 0x01B, 7, 0x100, 0x018), - new(SourceNct610X.CPUTIN, 0x019, 0x11B, 7, 0x200, 0x019), - new(SourceNct610X.AUXTIN, 0x01A, 0x21B, 7, 0x300, 0x01A) - }; - break; - - case Chip.NCT6683D: - case Chip.NCT6687D: - Fans = new float?[8]; - Controls = new float?[8]; - Voltages = new float?[14]; - Temperatures = new float?[7]; - - // CPU - // System - // MOS - // PCH - // CPU Socket - // PCIE_1 - // M2_1 - _temperaturesSource = new TemperatureSourceData[] { - new(null, 0x100), - new(null, 0x102), - new(null, 0x104), - new(null, 0x106), - new(null, 0x108), - new(null, 0x10A), - new(null, 0x10C) - }; - - // VIN0 +12V - // VIN1 +5V - // VIN2 VCore - // VIN3 SIO - // VIN4 DRAM - // VIN5 CPU IO - // VIN6 CPU SA - // VIN7 SIO - // 3VCC I/O +3.3 - // SIO VTT - // SIO VREF - // SIO VSB - // SIO AVSB - // SIO VBAT - _voltageRegisters = new ushort[] { 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x13A, 0x13E, 0x136, 0x138, 0x13C }; - - // CPU Fan - // PUMP Fan - // SYS Fan 1 - // SYS Fan 2 - // SYS Fan 3 - // SYS Fan 4 - // SYS Fan 5 - // SYS Fan 6 - _fanRpmRegister = new ushort[] { 0x140, 0x142, 0x144, 0x146, 0x148, 0x14A, 0x14C, 0x14E }; - - _restoreDefaultFanControlRequired = new bool[_fanRpmRegister.Length]; - _initialFanControlMode = new byte[_fanRpmRegister.Length]; - _initialFanPwmCommand = new byte[_fanRpmRegister.Length]; - - // initialize - const ushort initRegister = 0x180; - byte data = ReadByte(initRegister); - if ((data & 0x80) == 0) - { - WriteByte(initRegister, (byte)(data | 0x80)); - } - - // enable SIO voltage - WriteByte(0x1BB, 0x61); - WriteByte(0x1BC, 0x62); - WriteByte(0x1BD, 0x63); - WriteByte(0x1BE, 0x64); - WriteByte(0x1BF, 0x65); - break; - } - } - - public Chip Chip { get; } - - public float?[] Controls { get; } = Array.Empty(); - - public float?[] Fans { get; } = Array.Empty(); - - public float?[] Temperatures { get; } = Array.Empty(); - - public float?[] Voltages { get; } = Array.Empty(); - - public byte? ReadGpio(int index) - { - return null; - } - - public void WriteGpio(int index, byte value) - { } - - public void SetControl(int index, byte? value) - { - if (!_isNuvotonVendor) - return; - - if (index < 0 || index >= Controls.Length) - throw new ArgumentOutOfRangeException(nameof(index)); - - if (!Ring0.WaitIsaBusMutex(10)) - return; - - if (value.HasValue) - { - SaveDefaultFanControl(index); - - if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) - { - // set manual mode - WriteByte(FAN_CONTROL_MODE_REG[index], 0); - - // set output value - WriteByte(FAN_PWM_COMMAND_REG[index], value.Value); } - else + + _fanRpmRegister = new ushort[5]; + for (int i = 0; i < _fanRpmRegister.Length; i++) + _fanRpmRegister[i] = (ushort)(0x656 + (i << 1)); + + Controls = new float?[3]; + + Voltages = new float?[9]; + _voltageRegisters = new ushort[] { 0x020, 0x021, 0x022, 0x023, 0x024, 0x025, 0x026, 0x550, 0x551 }; + _voltageVBatRegister = 0x551; + _temperaturesSource = new TemperatureSourceData[] { - // Manual mode, bit(1 : set, 0 : unset) - // bit 0 : CPU Fan - // bit 1 : PUMP Fan - // bit 2 : SYS Fan 1 - // bit 3 : SYS Fan 2 - // bit 4 : SYS Fan 3 - // bit 5 : SYS Fan 4 - // bit 6 : SYS Fan 5 - // bit 7 : SYS Fan 6 + new(chip == Chip.NCT6771F ? SourceNct6771F.PECI_0 : SourceNct6776F.PECI_0, 0x027, 0, -1, 0x621), + new(chip == Chip.NCT6771F ? SourceNct6771F.CPUTIN : SourceNct6776F.CPUTIN, 0x073, 0x074, 7, 0x100), + new(chip == Chip.NCT6771F ? SourceNct6771F.AUXTIN : SourceNct6776F.AUXTIN, 0x075, 0x076, 7, 0x200), + new(chip == Chip.NCT6771F ? SourceNct6771F.SYSTIN : SourceNct6776F.SYSTIN, 0x077, 0x078, 7, 0x300), + new(null, 0x150, 0x151, 7, 0x622), + new(null, 0x250, 0x251, 7, 0x623), + new(null, 0x62B, 0x62E, 0, 0x624), + new(null, 0x62C, 0x62E, 1, 0x625), + new(null, 0x62D, 0x62E, 2, 0x626) + }; - byte mode = ReadByte(FAN_CONTROL_MODE_REG[index]); - byte bitMask = (byte)(0x01 << index); - mode = (byte)(mode | bitMask); - WriteByte(FAN_CONTROL_MODE_REG[index], mode); + Temperatures = new float?[4]; + break; - WriteByte(FAN_PWM_REQUEST_REG[index], 0x80); - Thread.Sleep(50); - - WriteByte(FAN_PWM_COMMAND_REG[index], value.Value); - WriteByte(FAN_PWM_REQUEST_REG[index], 0x40); - Thread.Sleep(50); - } - } - else - { - RestoreDefaultFanControl(index); - } - - Ring0.ReleaseIsaBusMutex(); - } - - public void Update() - { - if (!_isNuvotonVendor) - return; - - if (!Ring0.WaitIsaBusMutex(10)) - return; - - DisableIOSpaceLock(); - - for (int i = 0; i < Voltages.Length; i++) - { - if (Chip != Chip.NCT6687D) + case Chip.NCT6779D: + case Chip.NCT6791D: + case Chip.NCT6792D: + case Chip.NCT6792DA: + case Chip.NCT6793D: + case Chip.NCT6795D: + case Chip.NCT6796D: + case Chip.NCT6796DR: + case Chip.NCT6797D: + case Chip.NCT6798D: + switch (chip) { - float value = 0.008f * ReadByte(_voltageRegisters[i]); - bool valid = value > 0; - - // check if battery voltage monitor is enabled - if (valid && _voltageRegisters[i] == _voltageVBatRegister) - valid = (ReadByte(_vBatMonitorControlRegister) & 0x01) > 0; - - Voltages[i] = valid ? value : null; - } - else - { - float value = 0.001f * ((16 * ReadByte(_voltageRegisters[i])) + (ReadByte((ushort)(_voltageRegisters[i] + 1)) >> 4)); - - Voltages[i] = i switch - { - // 12V - 0 => value * 12.0f, - // 5V - 1 => value * 5.0f, - // DRAM - 4 => value * 2.0f, - _ => value - }; - } - } - - System.Diagnostics.Debug.WriteLine("Updating temperatures."); - long temperatureSourceMask = 0; - for (int i = 0; i < _temperaturesSource.Length; i++) - { - TemperatureSourceData ts = _temperaturesSource[i]; - int value; - SourceNct67Xxd source; - float? temperature; - - switch (Chip) - { - case Chip.NCT6687D: - case Chip.NCT6683D: - value = (sbyte)ReadByte(ts.Register); - int half = (ReadByte((ushort)(ts.Register + 1)) >> 7) & 0x1; - Temperatures[i] = value + (0.5f * half); + case Chip.NCT6779D: + Fans = new float?[5]; + Controls = new float?[5]; break; + case Chip.NCT6796DR: + case Chip.NCT6797D: + case Chip.NCT6798D: + Fans = new float?[7]; + Controls = new float?[7]; + break; + + default: + Fans = new float?[6]; + Controls = new float?[6]; + break; + } + + _fanCountRegister = new ushort[] { 0x4B0, 0x4B2, 0x4B4, 0x4B6, 0x4B8, 0x4BA, 0x4CC }; + + // max value for 13-bit fan counter + _maxFanCount = 0x1FFF; + + // min value that could be transferred to 16-bit RPM registers + _minFanCount = 0x15; + + Voltages = new float?[15]; + _voltageRegisters = new ushort[] { 0x480, 0x481, 0x482, 0x483, 0x484, 0x485, 0x486, 0x487, 0x488, 0x489, 0x48A, 0x48B, 0x48C, 0x48D, 0x48E }; + _voltageVBatRegister = 0x488; + var temperaturesSources = new List(); + + switch (chip) + { case Chip.NCT6796D: case Chip.NCT6796DR: case Chip.NCT6797D: case Chip.NCT6798D: - if (_temperaturesSource[i].Register == 0) + temperaturesSources.AddRange(new TemperatureSourceData[] { - System.Diagnostics.Debug.WriteLine("Temperature register {0} skipped, address 0.", i); - continue; - } - - value = (sbyte)ReadByte(_temperaturesSource[i].Register) << 1; - System.Diagnostics.Debug.WriteLine("Temperature register {0} at 0x{1:X3} value (integer): {2}/2", i, ts.Register, value); - if (_temperaturesSource[i].HalfBit > 0) - { - value |= (ReadByte(_temperaturesSource[i].HalfRegister) >> ts.HalfBit) & 0x1; - System.Diagnostics.Debug.WriteLine("Temperature register {0} value updated from 0x{1:X3} (fractional): {2}/2", i, ts.HalfRegister, value); - } - - if (ts.SourceRegister > 0) - { - source = (SourceNct67Xxd)(ReadByte(ts.SourceRegister) & 0x1F); - System.Diagnostics.Debug.WriteLine("Temperature register {0} source at 0x{1:X3}: {2:G} ({2:D})", i, ts.SourceRegister, source); - } - else - { - source = (SourceNct67Xxd)ts.Source; - System.Diagnostics.Debug.WriteLine("Temperature register {0} source register is 0, source set to: {1:G} ({1:D})", i, source); - } - - // Skip reading when already filled, because later values are without fractional - if ((temperatureSourceMask & (1L << (byte)source)) > 0) - { - System.Diagnostics.Debug.WriteLine("Temperature register {0} discarded, because source seen before.", i); - continue; - } - - temperature = 0.5f * value; - System.Diagnostics.Debug.WriteLine("Temperature register {0} final temperature: {1}.", i, temperature); - if (temperature is > 125 or < -55) - { - temperature = null; - System.Diagnostics.Debug.WriteLine("Temperature register {0} discarded: Out of range.", i); - } - else - { - temperatureSourceMask |= 1L << (byte)source; - System.Diagnostics.Debug.WriteLine("Temperature register {0} accepted.", i); - } - - for (int j = 0; j < Temperatures.Length; j++) - { - if ((SourceNct67Xxd)_temperaturesSource[j].Source == source) - { - Temperatures[j] = temperature; - System.Diagnostics.Debug.WriteLine("Temperature register {0}, value from source {1:G} ({1:D}), written at position {2}.", i, _temperaturesSource[j].Source, j); - } - } + new(SourceNct67Xxd.PECI_0, 0x073, 0x074, 7, 0x100), + new(SourceNct67Xxd.CPUTIN, 0x075, 0x076, 7, 0x200, 0x491), + new(SourceNct67Xxd.SYSTIN, 0x077, 0x078, 7, 0x300, 0x490), + new(SourceNct67Xxd.AUXTIN0, 0x079, 0x07A, 7, 0x800, 0x492), + new(SourceNct67Xxd.AUXTIN1, 0x07B, 0x07C, 7, 0x900, 0x493), + new(SourceNct67Xxd.AUXTIN2, 0x07D, 0x07E, 7, 0xA00, 0x494), + new(SourceNct67Xxd.AUXTIN3, 0x4A0, 0x49E, 6, 0xB00, 0x495), + new(SourceNct67Xxd.AUXTIN4, 0x027, 0, -1, 0x621), + new(SourceNct67Xxd.SMBUSMASTER0, 0x150, 0x151, 7, 0x622), + new(SourceNct67Xxd.SMBUSMASTER1, 0x670, 0, -1, 0xC26), + new(SourceNct67Xxd.PECI_1, 0x672, 0, -1, 0xC27), + new(SourceNct67Xxd.PCH_CHIP_CPU_MAX_TEMP, 0x674, 0, -1, 0xC28, 0x400), + new(SourceNct67Xxd.PCH_CHIP_TEMP, 0x676, 0, -1, 0xC29, 0x401), + new(SourceNct67Xxd.PCH_CPU_TEMP, 0x678, 0, -1, 0xC2A, 0x402), + new(SourceNct67Xxd.PCH_MCH_TEMP, 0x67A, 0, -1, 0xC2B, 0x404), + new(SourceNct67Xxd.AGENT0_DIMM0, 0), + new(SourceNct67Xxd.AGENT0_DIMM1, 0), + new(SourceNct67Xxd.AGENT1_DIMM0, 0), + new(SourceNct67Xxd.AGENT1_DIMM1, 0), + new(SourceNct67Xxd.BYTE_TEMP0, 0), + new(SourceNct67Xxd.BYTE_TEMP1, 0), + new(SourceNct67Xxd.PECI_0_CAL, 0), + new(SourceNct67Xxd.PECI_1_CAL, 0), + new(SourceNct67Xxd.VIRTUAL_TEMP, 0) + }); break; default: - value = (sbyte)ReadByte(ts.Register) << 1; - if (ts.HalfBit > 0) + temperaturesSources.AddRange(new TemperatureSourceData[] { - value |= (ReadByte(ts.HalfRegister) >> ts.HalfBit) & 0x1; - } - - source = (SourceNct67Xxd)ReadByte(ts.SourceRegister); - temperatureSourceMask |= 1L << (byte)source; - - temperature = 0.5f * value; - if (temperature is > 125 or < -55) - temperature = null; - - for (int j = 0; j < Temperatures.Length; j++) - { - if ((SourceNct67Xxd)_temperaturesSource[j].Source == source) - Temperatures[j] = temperature; - } + new(SourceNct67Xxd.PECI_0, 0x027, 0, -1, 0x621), + new(SourceNct67Xxd.CPUTIN, 0x073, 0x074, 7, 0x100, 0x491), + new(SourceNct67Xxd.SYSTIN, 0x075, 0x076, 7, 0x200, 0x490), + new(SourceNct67Xxd.AUXTIN0, 0x077, 0x078, 7, 0x300, 0x492), + new(SourceNct67Xxd.AUXTIN1, 0x079, 0x07A, 7, 0x800, 0x493), + new(SourceNct67Xxd.AUXTIN2, 0x07B, 0x07C, 7, 0x900, 0x494), + new(SourceNct67Xxd.AUXTIN3, 0x150, 0x151, 7, 0x622, 0x495) + }); break; } - } - for (int i = 0; i < _temperaturesSource.Length; i++) + _temperaturesSource = temperaturesSources.ToArray(); + Temperatures = new float?[_temperaturesSource.Length]; + break; + + case Chip.NCT610XD: + Fans = new float?[3]; + Controls = new float?[3]; + + _fanRpmRegister = new ushort[3]; + for (int i = 0; i < _fanRpmRegister.Length; i++) + _fanRpmRegister[i] = (ushort)(0x030 + (i << 1)); + + // min value RPM value with 13-bit fan counter + _minFanRpm = (int)(1.35e6 / 0x1FFF); + + Voltages = new float?[9]; + _voltageRegisters = new ushort[] { 0x300, 0x301, 0x302, 0x303, 0x304, 0x305, 0x307, 0x308, 0x309 }; + _voltageVBatRegister = 0x308; + Temperatures = new float?[4]; + _temperaturesSource = new TemperatureSourceData[] { + new(SourceNct610X.PECI_0, 0x027, 0, -1, 0x621), + new(SourceNct610X.SYSTIN, 0x018, 0x01B, 7, 0x100, 0x018), + new(SourceNct610X.CPUTIN, 0x019, 0x11B, 7, 0x200, 0x019), + new(SourceNct610X.AUXTIN, 0x01A, 0x21B, 7, 0x300, 0x01A) + }; + break; + + case Chip.NCT6683D: + case Chip.NCT6687D: + Fans = new float?[8]; + Controls = new float?[8]; + Voltages = new float?[14]; + Temperatures = new float?[7]; + + // CPU + // System + // MOS + // PCH + // CPU Socket + // PCIE_1 + // M2_1 + _temperaturesSource = new TemperatureSourceData[] { + new(null, 0x100), + new(null, 0x102), + new(null, 0x104), + new(null, 0x106), + new(null, 0x108), + new(null, 0x10A), + new(null, 0x10C) + }; + + // VIN0 +12V + // VIN1 +5V + // VIN2 VCore + // VIN3 SIO + // VIN4 DRAM + // VIN5 CPU IO + // VIN6 CPU SA + // VIN7 SIO + // 3VCC I/O +3.3 + // SIO VTT + // SIO VREF + // SIO VSB + // SIO AVSB + // SIO VBAT + _voltageRegisters = new ushort[] { 0x120, 0x122, 0x124, 0x126, 0x128, 0x12A, 0x12C, 0x12E, 0x130, 0x13A, 0x13E, 0x136, 0x138, 0x13C }; + + // CPU Fan + // PUMP Fan + // SYS Fan 1 + // SYS Fan 2 + // SYS Fan 3 + // SYS Fan 4 + // SYS Fan 5 + // SYS Fan 6 + _fanRpmRegister = new ushort[] { 0x140, 0x142, 0x144, 0x146, 0x148, 0x14A, 0x14C, 0x14E }; + + _restoreDefaultFanControlRequired = new bool[_fanRpmRegister.Length]; + _initialFanControlMode = new byte[_fanRpmRegister.Length]; + _initialFanPwmCommand = new byte[_fanRpmRegister.Length]; + + // initialize + const ushort initRegister = 0x180; + byte data = ReadByte(initRegister); + if ((data & 0x80) == 0) + { + WriteByte(initRegister, (byte)(data | 0x80)); + } + + // enable SIO voltage + WriteByte(0x1BB, 0x61); + WriteByte(0x1BC, 0x62); + WriteByte(0x1BD, 0x63); + WriteByte(0x1BE, 0x64); + WriteByte(0x1BF, 0x65); + break; + } + } + + public Chip Chip { get; } + + public float?[] Controls { get; } = Array.Empty(); + + public float?[] Fans { get; } = Array.Empty(); + + public float?[] Temperatures { get; } = Array.Empty(); + + public float?[] Voltages { get; } = Array.Empty(); + + public byte? ReadGpio(int index) + { + return null; + } + + public void WriteGpio(int index, byte value) + { } + + public void SetControl(int index, byte? value) + { + if (!_isNuvotonVendor) + return; + + if (index < 0 || index >= Controls.Length) + throw new ArgumentOutOfRangeException(nameof(index)); + + if (!Ring0.WaitIsaBusMutex(10)) + return; + + if (value.HasValue) + { + SaveDefaultFanControl(index); + + if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) { - TemperatureSourceData ts = _temperaturesSource[i]; - if (!ts.AlternateRegister.HasValue) - { - System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), skipped, because address is null.", i, ts.Source); - continue; - } + // set manual mode + WriteByte(FAN_CONTROL_MODE_REG[index], 0); - if ((temperatureSourceMask & (1L << (byte)(SourceNct67Xxd)ts.Source)) > 0) - { - System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} skipped, because value already set.", i, ts.Source, ts.AlternateRegister.Value); - continue; - } - - float? temperature = (sbyte)ReadByte(ts.AlternateRegister.Value); - System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} final temperature: {3}.", i, ts.Source, ts.AlternateRegister.Value, temperature); - - if (temperature is > 125 or <= 0) - { - temperature = null; - System.Diagnostics.Debug.WriteLine("Alternate Temperature register for temperature {0}, {1:G} ({1:D}), discarded: Out of range.", i, ts.Source); - } - - Temperatures[i] = temperature; + // set output value + WriteByte(FAN_PWM_COMMAND_REG[index], value.Value); } - - for (int i = 0; i < Fans.Length; i++) + else { - if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) + // Manual mode, bit(1 : set, 0 : unset) + // bit 0 : CPU Fan + // bit 1 : PUMP Fan + // bit 2 : SYS Fan 1 + // bit 3 : SYS Fan 2 + // bit 4 : SYS Fan 3 + // bit 5 : SYS Fan 4 + // bit 6 : SYS Fan 5 + // bit 7 : SYS Fan 6 + + byte mode = ReadByte(FAN_CONTROL_MODE_REG[index]); + byte bitMask = (byte)(0x01 << index); + mode = (byte)(mode | bitMask); + WriteByte(FAN_CONTROL_MODE_REG[index], mode); + + WriteByte(FAN_PWM_REQUEST_REG[index], 0x80); + Thread.Sleep(50); + + WriteByte(FAN_PWM_COMMAND_REG[index], value.Value); + WriteByte(FAN_PWM_REQUEST_REG[index], 0x40); + Thread.Sleep(50); + } + } + else + { + RestoreDefaultFanControl(index); + } + + Ring0.ReleaseIsaBusMutex(); + } + + public void Update() + { + if (!_isNuvotonVendor) + return; + + if (!Ring0.WaitIsaBusMutex(10)) + return; + + DisableIOSpaceLock(); + + for (int i = 0; i < Voltages.Length; i++) + { + if (Chip != Chip.NCT6687D) + { + float value = 0.008f * ReadByte(_voltageRegisters[i]); + bool valid = value > 0; + + // check if battery voltage monitor is enabled + if (valid && _voltageRegisters[i] == _voltageVBatRegister) + valid = (ReadByte(_vBatMonitorControlRegister) & 0x01) > 0; + + Voltages[i] = valid ? value : null; + } + else + { + float value = 0.001f * ((16 * ReadByte(_voltageRegisters[i])) + (ReadByte((ushort)(_voltageRegisters[i] + 1)) >> 4)); + + Voltages[i] = i switch { - if (_fanCountRegister != null) + // 12V + 0 => value * 12.0f, + // 5V + 1 => value * 5.0f, + // DRAM + 4 => value * 2.0f, + _ => value + }; + } + } + + System.Diagnostics.Debug.WriteLine("Updating temperatures."); + long temperatureSourceMask = 0; + for (int i = 0; i < _temperaturesSource.Length; i++) + { + TemperatureSourceData ts = _temperaturesSource[i]; + int value; + SourceNct67Xxd source; + float? temperature; + + switch (Chip) + { + case Chip.NCT6687D: + case Chip.NCT6683D: + value = (sbyte)ReadByte(ts.Register); + int half = (ReadByte((ushort)(ts.Register + 1)) >> 7) & 0x1; + Temperatures[i] = value + (0.5f * half); + break; + + case Chip.NCT6796D: + case Chip.NCT6796DR: + case Chip.NCT6797D: + case Chip.NCT6798D: + if (_temperaturesSource[i].Register == 0) { - byte high = ReadByte(_fanCountRegister[i]); - byte low = ReadByte((ushort)(_fanCountRegister[i] + 1)); + System.Diagnostics.Debug.WriteLine("Temperature register {0} skipped, address 0.", i); + continue; + } - int count = (high << 5) | (low & 0x1F); - if (count < _maxFanCount) + value = (sbyte)ReadByte(_temperaturesSource[i].Register) << 1; + System.Diagnostics.Debug.WriteLine("Temperature register {0} at 0x{1:X3} value (integer): {2}/2", i, ts.Register, value); + if (_temperaturesSource[i].HalfBit > 0) + { + value |= (ReadByte(_temperaturesSource[i].HalfRegister) >> ts.HalfBit) & 0x1; + System.Diagnostics.Debug.WriteLine("Temperature register {0} value updated from 0x{1:X3} (fractional): {2}/2", i, ts.HalfRegister, value); + } + + if (ts.SourceRegister > 0) + { + source = (SourceNct67Xxd)(ReadByte(ts.SourceRegister) & 0x1F); + System.Diagnostics.Debug.WriteLine("Temperature register {0} source at 0x{1:X3}: {2:G} ({2:D})", i, ts.SourceRegister, source); + } + else + { + source = (SourceNct67Xxd)ts.Source; + System.Diagnostics.Debug.WriteLine("Temperature register {0} source register is 0, source set to: {1:G} ({1:D})", i, source); + } + + // Skip reading when already filled, because later values are without fractional + if ((temperatureSourceMask & (1L << (byte)source)) > 0) + { + System.Diagnostics.Debug.WriteLine("Temperature register {0} discarded, because source seen before.", i); + continue; + } + + temperature = 0.5f * value; + System.Diagnostics.Debug.WriteLine("Temperature register {0} final temperature: {1}.", i, temperature); + if (temperature is > 125 or < -55) + { + temperature = null; + System.Diagnostics.Debug.WriteLine("Temperature register {0} discarded: Out of range.", i); + } + else + { + temperatureSourceMask |= 1L << (byte)source; + System.Diagnostics.Debug.WriteLine("Temperature register {0} accepted.", i); + } + + for (int j = 0; j < Temperatures.Length; j++) + { + if ((SourceNct67Xxd)_temperaturesSource[j].Source == source) { - if (count >= _minFanCount) - { - Fans[i] = 1.35e6f / count; - } - else - { - Fans[i] = null; - } + Temperatures[j] = temperature; + System.Diagnostics.Debug.WriteLine("Temperature register {0}, value from source {1:G} ({1:D}), written at position {2}.", i, _temperaturesSource[j].Source, j); + } + } + break; + + default: + value = (sbyte)ReadByte(ts.Register) << 1; + if (ts.HalfBit > 0) + { + value |= (ReadByte(ts.HalfRegister) >> ts.HalfBit) & 0x1; + } + + source = (SourceNct67Xxd)ReadByte(ts.SourceRegister); + temperatureSourceMask |= 1L << (byte)source; + + temperature = 0.5f * value; + if (temperature is > 125 or < -55) + temperature = null; + + for (int j = 0; j < Temperatures.Length; j++) + { + if ((SourceNct67Xxd)_temperaturesSource[j].Source == source) + Temperatures[j] = temperature; + } + break; + } + } + + for (int i = 0; i < _temperaturesSource.Length; i++) + { + TemperatureSourceData ts = _temperaturesSource[i]; + if (!ts.AlternateRegister.HasValue) + { + System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), skipped, because address is null.", i, ts.Source); + continue; + } + + if ((temperatureSourceMask & (1L << (byte)(SourceNct67Xxd)ts.Source)) > 0) + { + System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} skipped, because value already set.", i, ts.Source, ts.AlternateRegister.Value); + continue; + } + + float? temperature = (sbyte)ReadByte(ts.AlternateRegister.Value); + System.Diagnostics.Debug.WriteLine("Alternate temperature register for temperature {0}, {1:G} ({1:D}), at 0x{2:X3} final temperature: {3}.", i, ts.Source, ts.AlternateRegister.Value, temperature); + + if (temperature is > 125 or <= 0) + { + temperature = null; + System.Diagnostics.Debug.WriteLine("Alternate Temperature register for temperature {0}, {1:G} ({1:D}), discarded: Out of range.", i, ts.Source); + } + + Temperatures[i] = temperature; + } + + for (int i = 0; i < Fans.Length; i++) + { + if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) + { + if (_fanCountRegister != null) + { + byte high = ReadByte(_fanCountRegister[i]); + byte low = ReadByte((ushort)(_fanCountRegister[i] + 1)); + + int count = (high << 5) | (low & 0x1F); + if (count < _maxFanCount) + { + if (count >= _minFanCount) + { + Fans[i] = 1.35e6f / count; } else { - Fans[i] = 0; + Fans[i] = null; } } else { - byte high = ReadByte(_fanRpmRegister[i]); - byte low = ReadByte((ushort)(_fanRpmRegister[i] + 1)); - int value = (high << 8) | low; - - Fans[i] = value > _minFanRpm ? value : 0; + Fans[i] = 0; } } else { - Fans[i] = (ReadByte(_fanRpmRegister[i]) << 8) | ReadByte((ushort)(_fanRpmRegister[i] + 1)); - } - } + byte high = ReadByte(_fanRpmRegister[i]); + byte low = ReadByte((ushort)(_fanRpmRegister[i] + 1)); + int value = (high << 8) | low; - for (int i = 0; i < Controls.Length; i++) - { - if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) - { - int value = ReadByte(FAN_PWM_OUT_REG[i]); - Controls[i] = value / 2.55f; - } - else - { - int value = ReadByte(FAN_PWM_OUT_REG[i]); - Controls[i] = (float)Math.Round(value / 2.55f); - } - } - - Ring0.ReleaseIsaBusMutex(); - } - - public string GetReport() - { - StringBuilder r = new(); - - r.AppendLine("LPC " + GetType().Name); - r.AppendLine(); - r.Append("Chip Id: 0x"); - r.AppendLine(Chip.ToString("X")); - r.Append("Chip Revision: 0x"); - r.AppendLine(_revision.ToString("X", CultureInfo.InvariantCulture)); - r.Append("Base Address: 0x"); - r.AppendLine(_port.ToString("X4", CultureInfo.InvariantCulture)); - r.AppendLine(); - - if (!Ring0.WaitIsaBusMutex(100)) - return r.ToString(); - - ushort[] addresses = - { - 0x000, - 0x010, - 0x020, - 0x030, - 0x040, - 0x050, - 0x060, - 0x070, - 0x0F0, - 0x100, - 0x110, - 0x120, - 0x130, - 0x140, - 0x150, - 0x200, - 0x210, - 0x220, - 0x230, - 0x240, - 0x250, - 0x260, - 0x300, - 0x320, - 0x330, - 0x340, - 0x360, - 0x400, - 0x410, - 0x420, - 0x440, - 0x450, - 0x460, - 0x480, - 0x490, - 0x4B0, - 0x4C0, - 0x4F0, - 0x500, - 0x550, - 0x560, - 0x600, - 0x610, - 0x620, - 0x630, - 0x640, - 0x650, - 0x660, - 0x670, - 0x700, - 0x710, - 0x720, - 0x730, - 0x800, - 0x820, - 0x830, - 0x840, - 0x900, - 0x920, - 0x930, - 0x940, - 0x960, - 0xA00, - 0xA10, - 0xA20, - 0xA30, - 0xA40, - 0xA50, - 0xA60, - 0xA70, - 0xB00, - 0xB10, - 0xB20, - 0xB30, - 0xB50, - 0xB60, - 0xB70, - 0xC00, - 0xC10, - 0xC20, - 0xC30, - 0xC50, - 0xC60, - 0xC70, - 0xD00, - 0xD10, - 0xD20, - 0xD30, - 0xD50, - 0xD60, - 0xE00, - 0xE10, - 0xE20, - 0xE30, - 0xF00, - 0xF10, - 0xF20, - 0xF30, - 0x8040, - 0x80F0 - }; - - r.AppendLine("Hardware Monitor Registers"); - r.AppendLine(); - r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - r.AppendLine(); - - if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) - { - foreach (ushort address in addresses) - { - r.Append(" "); - r.Append(address.ToString("X4", CultureInfo.InvariantCulture)); - r.Append(" "); - for (ushort j = 0; j <= 0xF; j++) - { - r.Append(" "); - r.Append(ReadByte((ushort)(address | j)).ToString("X2", CultureInfo.InvariantCulture)); - } - - r.AppendLine(); + Fans[i] = value > _minFanRpm ? value : 0; } } else { - for (int i = 0; i <= 0xFF; i++) - { - r.Append(" "); - r.Append((i << 4).ToString("X4", CultureInfo.InvariantCulture)); - r.Append(" "); - for (int j = 0; j <= 0xF; j++) - { - ushort address = (ushort)(i << 4 | j); - r.Append(" "); - r.Append(ReadByte(address).ToString("X2", CultureInfo.InvariantCulture)); - } - - r.AppendLine(); - } + Fans[i] = (ReadByte(_fanRpmRegister[i]) << 8) | ReadByte((ushort)(_fanRpmRegister[i] + 1)); } - - r.AppendLine(); - - Ring0.ReleaseIsaBusMutex(); - - return r.ToString(); } - private byte ReadByte(ushort address) + for (int i = 0; i < Controls.Length; i++) { if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) { - byte bank = (byte)(address >> 8); - byte register = (byte)(address & 0xFF); - Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER); - Ring0.WriteIoPort(_port + DATA_REGISTER_OFFSET, bank); - Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, register); - return Ring0.ReadIoPort(_port + DATA_REGISTER_OFFSET); + int value = ReadByte(FAN_PWM_OUT_REG[i]); + Controls[i] = value / 2.55f; } + else + { + int value = ReadByte(FAN_PWM_OUT_REG[i]); + Controls[i] = (float)Math.Round(value / 2.55f); + } + } + Ring0.ReleaseIsaBusMutex(); + } + + public string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("LPC " + GetType().Name); + r.AppendLine(); + r.Append("Chip Id: 0x"); + r.AppendLine(Chip.ToString("X")); + r.Append("Chip Revision: 0x"); + r.AppendLine(_revision.ToString("X", CultureInfo.InvariantCulture)); + r.Append("Base Address: 0x"); + r.AppendLine(_port.ToString("X4", CultureInfo.InvariantCulture)); + r.AppendLine(); + + if (!Ring0.WaitIsaBusMutex(100)) + return r.ToString(); + + ushort[] addresses = + { + 0x000, + 0x010, + 0x020, + 0x030, + 0x040, + 0x050, + 0x060, + 0x070, + 0x0F0, + 0x100, + 0x110, + 0x120, + 0x130, + 0x140, + 0x150, + 0x200, + 0x210, + 0x220, + 0x230, + 0x240, + 0x250, + 0x260, + 0x300, + 0x320, + 0x330, + 0x340, + 0x360, + 0x400, + 0x410, + 0x420, + 0x440, + 0x450, + 0x460, + 0x480, + 0x490, + 0x4B0, + 0x4C0, + 0x4F0, + 0x500, + 0x550, + 0x560, + 0x600, + 0x610, + 0x620, + 0x630, + 0x640, + 0x650, + 0x660, + 0x670, + 0x700, + 0x710, + 0x720, + 0x730, + 0x800, + 0x820, + 0x830, + 0x840, + 0x900, + 0x920, + 0x930, + 0x940, + 0x960, + 0xA00, + 0xA10, + 0xA20, + 0xA30, + 0xA40, + 0xA50, + 0xA60, + 0xA70, + 0xB00, + 0xB10, + 0xB20, + 0xB30, + 0xB50, + 0xB60, + 0xB70, + 0xC00, + 0xC10, + 0xC20, + 0xC30, + 0xC50, + 0xC60, + 0xC70, + 0xD00, + 0xD10, + 0xD20, + 0xD30, + 0xD50, + 0xD60, + 0xE00, + 0xE10, + 0xE20, + 0xE30, + 0xF00, + 0xF10, + 0xF20, + 0xF30, + 0x8040, + 0x80F0 + }; + + r.AppendLine("Hardware Monitor Registers"); + r.AppendLine(); + r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); + r.AppendLine(); + + if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) + { + foreach (ushort address in addresses) + { + r.Append(" "); + r.Append(address.ToString("X4", CultureInfo.InvariantCulture)); + r.Append(" "); + for (ushort j = 0; j <= 0xF; j++) + { + r.Append(" "); + r.Append(ReadByte((ushort)(address | j)).ToString("X2", CultureInfo.InvariantCulture)); + } + + r.AppendLine(); + } + } + else + { + for (int i = 0; i <= 0xFF; i++) + { + r.Append(" "); + r.Append((i << 4).ToString("X4", CultureInfo.InvariantCulture)); + r.Append(" "); + for (int j = 0; j <= 0xF; j++) + { + ushort address = (ushort)(i << 4 | j); + r.Append(" "); + r.Append(ReadByte(address).ToString("X2", CultureInfo.InvariantCulture)); + } + + r.AppendLine(); + } + } + + r.AppendLine(); + + Ring0.ReleaseIsaBusMutex(); + + return r.ToString(); + } + + private byte ReadByte(ushort address) + { + if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) + { + byte bank = (byte)(address >> 8); + byte register = (byte)(address & 0xFF); + Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER); + Ring0.WriteIoPort(_port + DATA_REGISTER_OFFSET, bank); + Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, register); + return Ring0.ReadIoPort(_port + DATA_REGISTER_OFFSET); + } + + byte page = (byte)(address >> 8); + byte index = (byte)(address & 0xFF); + Ring0.WriteIoPort(_port + EC_SPACE_PAGE_REGISTER_OFFSET, EC_SPACE_PAGE_SELECT); + Ring0.WriteIoPort(_port + EC_SPACE_PAGE_REGISTER_OFFSET, page); + Ring0.WriteIoPort(_port + EC_SPACE_INDEX_REGISTER_OFFSET, index); + return Ring0.ReadIoPort(_port + EC_SPACE_DATA_REGISTER_OFFSET); + } + + private void WriteByte(ushort address, byte value) + { + if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) + { + byte bank = (byte)(address >> 8); + byte register = (byte)(address & 0xFF); + Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER); + Ring0.WriteIoPort(_port + DATA_REGISTER_OFFSET, bank); + Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, register); + Ring0.WriteIoPort(_port + DATA_REGISTER_OFFSET, value); + } + else + { byte page = (byte)(address >> 8); byte index = (byte)(address & 0xFF); Ring0.WriteIoPort(_port + EC_SPACE_PAGE_REGISTER_OFFSET, EC_SPACE_PAGE_SELECT); Ring0.WriteIoPort(_port + EC_SPACE_PAGE_REGISTER_OFFSET, page); Ring0.WriteIoPort(_port + EC_SPACE_INDEX_REGISTER_OFFSET, index); - return Ring0.ReadIoPort(_port + EC_SPACE_DATA_REGISTER_OFFSET); + Ring0.WriteIoPort(_port + EC_SPACE_DATA_REGISTER_OFFSET, value); } + } - private void WriteByte(ushort address, byte value) + private bool IsNuvotonVendor() + { + return Chip == Chip.NCT6687D || Chip == Chip.NCT6683D || ((ReadByte(VENDOR_ID_HIGH_REGISTER) << 8) | ReadByte(VENDOR_ID_LOW_REGISTER)) == NUVOTON_VENDOR_ID; + } + + private void SaveDefaultFanControl(int index) + { + if (!_restoreDefaultFanControlRequired[index]) { if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) { - byte bank = (byte)(address >> 8); - byte register = (byte)(address & 0xFF); - Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, BANK_SELECT_REGISTER); - Ring0.WriteIoPort(_port + DATA_REGISTER_OFFSET, bank); - Ring0.WriteIoPort(_port + ADDRESS_REGISTER_OFFSET, register); - Ring0.WriteIoPort(_port + DATA_REGISTER_OFFSET, value); + _initialFanControlMode[index] = ReadByte(FAN_CONTROL_MODE_REG[index]); } else { - byte page = (byte)(address >> 8); - byte index = (byte)(address & 0xFF); - Ring0.WriteIoPort(_port + EC_SPACE_PAGE_REGISTER_OFFSET, EC_SPACE_PAGE_SELECT); - Ring0.WriteIoPort(_port + EC_SPACE_PAGE_REGISTER_OFFSET, page); - Ring0.WriteIoPort(_port + EC_SPACE_INDEX_REGISTER_OFFSET, index); - Ring0.WriteIoPort(_port + EC_SPACE_DATA_REGISTER_OFFSET, value); - } - } - - private bool IsNuvotonVendor() - { - return Chip == Chip.NCT6687D || Chip == Chip.NCT6683D || ((ReadByte(VENDOR_ID_HIGH_REGISTER) << 8) | ReadByte(VENDOR_ID_LOW_REGISTER)) == NUVOTON_VENDOR_ID; - } - - private void SaveDefaultFanControl(int index) - { - if (!_restoreDefaultFanControlRequired[index]) - { - if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) - { - _initialFanControlMode[index] = ReadByte(FAN_CONTROL_MODE_REG[index]); - } - else - { - byte mode = ReadByte(FAN_CONTROL_MODE_REG[index]); - byte bitMask = (byte)(0x01 << index); - _initialFanControlMode[index] = (byte)(mode & bitMask); - } - - _initialFanPwmCommand[index] = ReadByte(FAN_PWM_COMMAND_REG[index]); - _restoreDefaultFanControlRequired[index] = true; - } - } - - private void RestoreDefaultFanControl(int index) - { - if (_restoreDefaultFanControlRequired[index]) - { - if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) - { - WriteByte(FAN_CONTROL_MODE_REG[index], _initialFanControlMode[index]); - WriteByte(FAN_PWM_COMMAND_REG[index], _initialFanPwmCommand[index]); - } - else - { - byte mode = ReadByte(FAN_CONTROL_MODE_REG[index]); - mode = (byte)(mode & ~_initialFanControlMode[index]); - WriteByte(FAN_CONTROL_MODE_REG[index], mode); - - WriteByte(FAN_PWM_REQUEST_REG[index], 0x80); - Thread.Sleep(50); - - WriteByte(FAN_PWM_COMMAND_REG[index], _initialFanPwmCommand[index]); - WriteByte(FAN_PWM_REQUEST_REG[index], 0x40); - Thread.Sleep(50); - } - - _restoreDefaultFanControlRequired[index] = false; - } - } - - private void DisableIOSpaceLock() - { - if (Chip is not Chip.NCT6791D and - not Chip.NCT6792D and - not Chip.NCT6792DA and - not Chip.NCT6793D and - not Chip.NCT6795D and - not Chip.NCT6796D and - not Chip.NCT6796DR and - not Chip.NCT6797D and - not Chip.NCT6798D) - { - return; + byte mode = ReadByte(FAN_CONTROL_MODE_REG[index]); + byte bitMask = (byte)(0x01 << index); + _initialFanControlMode[index] = (byte)(mode & bitMask); } - // the lock is disabled already if the vendor ID can be read - if (IsNuvotonVendor()) - return; - - _lpcPort.WinbondNuvotonFintekEnter(); - _lpcPort.NuvotonDisableIOSpaceLock(); - _lpcPort.WinbondNuvotonFintekExit(); + _initialFanPwmCommand[index] = ReadByte(FAN_PWM_COMMAND_REG[index]); + _restoreDefaultFanControlRequired[index] = true; } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum SourceNct6771F : byte - { - SYSTIN = 1, - CPUTIN = 2, - AUXTIN = 3, - PECI_0 = 5 - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum SourceNct6776F : byte - { - SYSTIN = 1, - CPUTIN = 2, - AUXTIN = 3, - PECI_0 = 12 - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum SourceNct67Xxd : byte - { - SYSTIN = 1, - CPUTIN = 2, - AUXTIN0 = 3, - AUXTIN1 = 4, - AUXTIN2 = 5, - AUXTIN3 = 6, - AUXTIN4 = 7, - SMBUSMASTER0 = 8, - SMBUSMASTER1 = 9, - PECI_0 = 16, - PECI_1 = 17, - PCH_CHIP_CPU_MAX_TEMP = 18, - PCH_CHIP_TEMP = 19, - PCH_CPU_TEMP = 20, - PCH_MCH_TEMP = 21, - AGENT0_DIMM0 = 22, - AGENT0_DIMM1 = 23, - AGENT1_DIMM0 = 24, - AGENT1_DIMM1 = 25, - BYTE_TEMP0 = 26, - BYTE_TEMP1 = 27, - PECI_0_CAL = 28, - PECI_1_CAL = 29, - VIRTUAL_TEMP = 31 - } - - [SuppressMessage("ReSharper", "InconsistentNaming")] - private enum SourceNct610X : byte - { - SYSTIN = 1, - CPUTIN = 2, - AUXTIN = 3, - PECI_0 = 12 - } - - // ReSharper disable InconsistentNaming - private const uint ADDRESS_REGISTER_OFFSET = 0x05; - private const byte BANK_SELECT_REGISTER = 0x4E; - private const uint DATA_REGISTER_OFFSET = 0x06; - - // NCT668X - private const uint EC_SPACE_PAGE_REGISTER_OFFSET = 0x04; - private const uint EC_SPACE_INDEX_REGISTER_OFFSET = 0x05; - private const uint EC_SPACE_DATA_REGISTER_OFFSET = 0x06; - private const byte EC_SPACE_PAGE_SELECT = 0xFF; - - private const ushort NUVOTON_VENDOR_ID = 0x5CA3; - - private readonly ushort[] FAN_CONTROL_MODE_REG; - private readonly ushort[] FAN_PWM_COMMAND_REG; - private readonly ushort[] FAN_PWM_OUT_REG; - private readonly ushort[] FAN_PWM_REQUEST_REG; - - private readonly ushort VENDOR_ID_HIGH_REGISTER; - private readonly ushort VENDOR_ID_LOW_REGISTER; - - // ReSharper restore InconsistentNaming } + + private void RestoreDefaultFanControl(int index) + { + if (_restoreDefaultFanControlRequired[index]) + { + if (Chip is not Chip.NCT6687D and not Chip.NCT6683D) + { + WriteByte(FAN_CONTROL_MODE_REG[index], _initialFanControlMode[index]); + WriteByte(FAN_PWM_COMMAND_REG[index], _initialFanPwmCommand[index]); + } + else + { + byte mode = ReadByte(FAN_CONTROL_MODE_REG[index]); + mode = (byte)(mode & ~_initialFanControlMode[index]); + WriteByte(FAN_CONTROL_MODE_REG[index], mode); + + WriteByte(FAN_PWM_REQUEST_REG[index], 0x80); + Thread.Sleep(50); + + WriteByte(FAN_PWM_COMMAND_REG[index], _initialFanPwmCommand[index]); + WriteByte(FAN_PWM_REQUEST_REG[index], 0x40); + Thread.Sleep(50); + } + + _restoreDefaultFanControlRequired[index] = false; + } + } + + private void DisableIOSpaceLock() + { + if (Chip is not Chip.NCT6791D and + not Chip.NCT6792D and + not Chip.NCT6792DA and + not Chip.NCT6793D and + not Chip.NCT6795D and + not Chip.NCT6796D and + not Chip.NCT6796DR and + not Chip.NCT6797D and + not Chip.NCT6798D) + { + return; + } + + // the lock is disabled already if the vendor ID can be read + if (IsNuvotonVendor()) + return; + + _lpcPort.WinbondNuvotonFintekEnter(); + _lpcPort.NuvotonDisableIOSpaceLock(); + _lpcPort.WinbondNuvotonFintekExit(); + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum SourceNct6771F : byte + { + SYSTIN = 1, + CPUTIN = 2, + AUXTIN = 3, + PECI_0 = 5 + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum SourceNct6776F : byte + { + SYSTIN = 1, + CPUTIN = 2, + AUXTIN = 3, + PECI_0 = 12 + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum SourceNct67Xxd : byte + { + SYSTIN = 1, + CPUTIN = 2, + AUXTIN0 = 3, + AUXTIN1 = 4, + AUXTIN2 = 5, + AUXTIN3 = 6, + AUXTIN4 = 7, + SMBUSMASTER0 = 8, + SMBUSMASTER1 = 9, + PECI_0 = 16, + PECI_1 = 17, + PCH_CHIP_CPU_MAX_TEMP = 18, + PCH_CHIP_TEMP = 19, + PCH_CPU_TEMP = 20, + PCH_MCH_TEMP = 21, + AGENT0_DIMM0 = 22, + AGENT0_DIMM1 = 23, + AGENT1_DIMM0 = 24, + AGENT1_DIMM1 = 25, + BYTE_TEMP0 = 26, + BYTE_TEMP1 = 27, + PECI_0_CAL = 28, + PECI_1_CAL = 29, + VIRTUAL_TEMP = 31 + } + + [SuppressMessage("ReSharper", "InconsistentNaming")] + private enum SourceNct610X : byte + { + SYSTIN = 1, + CPUTIN = 2, + AUXTIN = 3, + PECI_0 = 12 + } + + // ReSharper disable InconsistentNaming + private const uint ADDRESS_REGISTER_OFFSET = 0x05; + private const byte BANK_SELECT_REGISTER = 0x4E; + private const uint DATA_REGISTER_OFFSET = 0x06; + + // NCT668X + private const uint EC_SPACE_PAGE_REGISTER_OFFSET = 0x04; + private const uint EC_SPACE_INDEX_REGISTER_OFFSET = 0x05; + private const uint EC_SPACE_DATA_REGISTER_OFFSET = 0x06; + private const byte EC_SPACE_PAGE_SELECT = 0xFF; + + private const ushort NUVOTON_VENDOR_ID = 0x5CA3; + + private readonly ushort[] FAN_CONTROL_MODE_REG; + private readonly ushort[] FAN_PWM_COMMAND_REG; + private readonly ushort[] FAN_PWM_OUT_REG; + private readonly ushort[] FAN_PWM_REQUEST_REG; + + private readonly ushort VENDOR_ID_HIGH_REGISTER; + private readonly ushort VENDOR_ID_LOW_REGISTER; + + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/W836XX.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/W836XX.cs index 117ff3c..808488f 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/W836XX.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Lpc/W836XX.cs @@ -10,418 +10,435 @@ using System.Text; // ReSharper disable once InconsistentNaming -namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc +namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc; + +internal class W836XX : ISuperIO { - internal class W836XX : ISuperIO + private readonly ushort _address; + private readonly byte _revision; + private readonly bool[] _peciTemperature = Array.Empty(); + private readonly byte[] _voltageBank = Array.Empty(); + private readonly float _voltageGain = 0.008f; + private readonly byte[] _voltageRegister = Array.Empty(); + + // Added to control fans. + private readonly byte[] _fanPwmRegister = Array.Empty(); + private readonly byte[] _fanPrimaryControlModeRegister = Array.Empty(); + private readonly byte[] _fanPrimaryControlValue = Array.Empty(); + private readonly byte[] _fanSecondaryControlModeRegister = Array.Empty(); + private readonly byte[] _fanSecondaryControlValue = Array.Empty(); + private readonly byte[] _fanTertiaryControlModeRegister = Array.Empty(); + private readonly byte[] _fanTertiaryControlValue = Array.Empty(); + + private readonly byte[] _initialFanControlValue = Array.Empty(); + private readonly byte[] _initialFanSecondaryControlValue = Array.Empty(); + private readonly byte[] _initialFanTertiaryControlValue = Array.Empty(); + private readonly bool[] _restoreDefaultFanPwmControlRequired = Array.Empty(); + + public W836XX(Chip chip, byte revision, ushort address) { - private readonly ushort _address; - private readonly byte _revision; - private readonly bool[] _peciTemperature = Array.Empty(); - private readonly byte[] _voltageBank = Array.Empty(); - private readonly float _voltageGain = 0.008f; - private readonly byte[] _voltageRegister = Array.Empty(); + _address = address; + _revision = revision; + Chip = chip; - // Added to control fans. - private readonly byte[] _fanPwmRegister = Array.Empty(); - private readonly byte[] _fanPrimaryControlModeRegister = Array.Empty(); - private readonly byte[] _fanPrimaryControlValue = Array.Empty(); - private readonly byte[] _fanSecondaryControlModeRegister = Array.Empty(); - private readonly byte[] _fanSecondaryControlValue = Array.Empty(); - private readonly byte[] _fanTertiaryControlModeRegister = Array.Empty(); - private readonly byte[] _fanTertiaryControlValue = Array.Empty(); + if (!IsWinbondVendor()) + return; - private readonly byte[] _initialFanControlValue = Array.Empty(); - private readonly byte[] _initialFanSecondaryControlValue = Array.Empty(); - private readonly byte[] _initialFanTertiaryControlValue = Array.Empty(); - private readonly bool[] _restoreDefaultFanPwmControlRequired = Array.Empty(); - - public W836XX(Chip chip, byte revision, ushort address) + Temperatures = new float?[3]; + _peciTemperature = new bool[3]; + switch (chip) { - _address = address; - _revision = revision; - Chip = chip; + case Chip.W83667HG: + case Chip.W83667HGB: + // note temperature sensor registers that read PECI + byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG); + _peciTemperature[0] = (flag & 0x04) != 0; + _peciTemperature[1] = (flag & 0x40) != 0; + _peciTemperature[2] = false; + break; - if (!IsWinbondVendor()) - return; + case Chip.W83627DHG: + case Chip.W83627DHGP: + // note temperature sensor registers that read PECI + byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG); + _peciTemperature[0] = (sel & 0x07) != 0; + _peciTemperature[1] = (sel & 0x70) != 0; + _peciTemperature[2] = false; + break; - Temperatures = new float?[3]; - _peciTemperature = new bool[3]; - switch (chip) - { - case Chip.W83667HG: - case Chip.W83667HGB: - // note temperature sensor registers that read PECI - byte flag = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG); - _peciTemperature[0] = (flag & 0x04) != 0; - _peciTemperature[1] = (flag & 0x40) != 0; - _peciTemperature[2] = false; - break; - - case Chip.W83627DHG: - case Chip.W83627DHGP: - // note temperature sensor registers that read PECI - byte sel = ReadByte(0, TEMPERATURE_SOURCE_SELECT_REG); - _peciTemperature[0] = (sel & 0x07) != 0; - _peciTemperature[1] = (sel & 0x70) != 0; - _peciTemperature[2] = false; - break; - - default: - // no PECI support - _peciTemperature[0] = false; - _peciTemperature[1] = false; - _peciTemperature[2] = false; - break; - } - - switch (chip) - { - case Chip.W83627EHF: - Voltages = new float?[10]; - _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 }; - _voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 }; - _voltageGain = 0.008f; - - Fans = new float?[5]; - _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values. - _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register. - _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans. - _initialFanControlValue = new byte[3]; // To store primary default value. - _initialFanSecondaryControlValue = new byte[3]; // To store secondary default value. - - Controls = new float?[3]; - break; - - case Chip.W83627DHG: - case Chip.W83627DHGP: - Voltages = new float?[9]; - _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 }; - _voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 }; - - _voltageGain = 0.008f; - Fans = new float?[5]; - _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values - _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // added. Primary control register - _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans - _initialFanControlValue = new byte[3]; // To store primary default value - _initialFanSecondaryControlValue = new byte[3]; // To store secondary default value. - - Controls = new float?[3]; - break; - - case Chip.W83667HG: - case Chip.W83667HGB: - Voltages = new float?[9]; - _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 }; - _voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 }; - _voltageGain = 0.008f; - - Fans = new float?[5]; - _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values. - _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register. - _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans. - _fanSecondaryControlModeRegister = new byte[] { 0x7c, 0x7c, 0x7c }; // Secondary control register for SmartFan4. - _fanSecondaryControlValue = new byte[] { 0b11101111, 0b11011111, 0b10111111 }; // Values for secondary register to gain control of fans. - _fanTertiaryControlModeRegister = new byte[] { 0x62, 0x7c, 0x62 }; // Tertiary control register. 2nd fan doesn't have Tertiary control, same as secondary to avoid change. - _fanTertiaryControlValue = new byte[] { 0b11101111, 0b11011111, 0b11011111 }; // Values for tertiary register to gain control of fans. 2nd fan doesn't have Tertiary control, same as secondary to avoid change. - - _initialFanControlValue = new byte[3]; // To store primary default value. - _initialFanSecondaryControlValue = new byte[3]; // To store secondary default value. - _initialFanTertiaryControlValue = new byte[3]; // To store tertiary default value. - Controls = new float?[3]; - break; - - case Chip.W83627HF: - Voltages = new float?[7]; - _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 }; - _voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 }; - _voltageGain = 0.016f; - - Fans = new float?[3]; - _fanPwmRegister = new byte[] { 0x5A, 0x5B }; // Fan PWM values. - - Controls = new float?[2]; - break; - - case Chip.W83627THF: - Voltages = new float?[7]; - _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 }; - _voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 }; - _voltageGain = 0.016f; - - Fans = new float?[3]; - _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values. - _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register. - _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans. - _initialFanControlValue = new byte[3]; // To store primary default value. - - Controls = new float?[3]; - break; - - case Chip.W83687THF: - Voltages = new float?[7]; - _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 }; - _voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 }; - _voltageGain = 0.016f; - - Fans = new float?[3]; - break; - } + default: + // no PECI support + _peciTemperature[0] = false; + _peciTemperature[1] = false; + _peciTemperature[2] = false; + break; } - public Chip Chip { get; } - - public float?[] Controls { get; } = Array.Empty(); - - public float?[] Fans { get; } = Array.Empty(); - - public float?[] Temperatures { get; } = Array.Empty(); - - public float?[] Voltages { get; } = Array.Empty(); - - public byte? ReadGpio(int index) + switch (chip) { - return null; + case Chip.W83627EHF: + Voltages = new float?[10]; + _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51, 0x52 }; + _voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5, 5 }; + _voltageGain = 0.008f; + + Fans = new float?[5]; + _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values. + _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register. + _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans. + _initialFanControlValue = new byte[3]; // To store primary default value. + _initialFanSecondaryControlValue = new byte[3]; // To store secondary default value. + + Controls = new float?[3]; + break; + + case Chip.W83627DHG: + case Chip.W83627DHGP: + Voltages = new float?[9]; + _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 }; + _voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 }; + + _voltageGain = 0.008f; + Fans = new float?[5]; + _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values + _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // added. Primary control register + _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans + _initialFanControlValue = new byte[3]; // To store primary default value + _initialFanSecondaryControlValue = new byte[3]; // To store secondary default value. + + Controls = new float?[3]; + break; + + case Chip.W83667HG: + case Chip.W83667HGB: + Voltages = new float?[9]; + _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x50, 0x51 }; + _voltageBank = new byte[] { 0, 0, 0, 0, 0, 0, 0, 5, 5 }; + _voltageGain = 0.008f; + + Fans = new float?[5]; + _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values. + _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register. + _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans. + _fanSecondaryControlModeRegister = new byte[] { 0x7c, 0x7c, 0x7c }; // Secondary control register for SmartFan4. + _fanSecondaryControlValue = new byte[] { 0b11101111, 0b11011111, 0b10111111 }; // Values for secondary register to gain control of fans. + _fanTertiaryControlModeRegister = new byte[] { 0x62, 0x7c, 0x62 }; // Tertiary control register. 2nd fan doesn't have Tertiary control, same as secondary to avoid change. + _fanTertiaryControlValue = new byte[] { 0b11101111, 0b11011111, 0b11011111 }; // Values for tertiary register to gain control of fans. 2nd fan doesn't have Tertiary control, same as secondary to avoid change. + + _initialFanControlValue = new byte[3]; // To store primary default value. + _initialFanSecondaryControlValue = new byte[3]; // To store secondary default value. + _initialFanTertiaryControlValue = new byte[3]; // To store tertiary default value. + Controls = new float?[3]; + break; + + case Chip.W83627HF: + Voltages = new float?[7]; + _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 }; + _voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 }; + _voltageGain = 0.016f; + + Fans = new float?[3]; + _fanPwmRegister = new byte[] { 0x5A, 0x5B }; // Fan PWM values. + + Controls = new float?[2]; + break; + + case Chip.W83627THF: + Voltages = new float?[7]; + _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 }; + _voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 }; + _voltageGain = 0.016f; + + Fans = new float?[3]; + _fanPwmRegister = new byte[] { 0x01, 0x03, 0x11 }; // Fan PWM values. + _fanPrimaryControlModeRegister = new byte[] { 0x04, 0x04, 0x12 }; // Primary control register. + _fanPrimaryControlValue = new byte[] { 0b11110011, 0b11001111, 0b11111001 }; // Values to gain control of fans. + _initialFanControlValue = new byte[3]; // To store primary default value. + + Controls = new float?[3]; + break; + + case Chip.W83687THF: + Voltages = new float?[7]; + _voltageRegister = new byte[] { 0x20, 0x21, 0x22, 0x23, 0x24, 0x50, 0x51 }; + _voltageBank = new byte[] { 0, 0, 0, 0, 0, 5, 5 }; + _voltageGain = 0.016f; + + Fans = new float?[3]; + break; } + } - public void WriteGpio(int index, byte value) - { } + public Chip Chip { get; } - public void SetControl(int index, byte? value) + public float?[] Controls { get; } = Array.Empty(); + + public float?[] Fans { get; } = Array.Empty(); + + public float?[] Temperatures { get; } = Array.Empty(); + + public float?[] Voltages { get; } = Array.Empty(); + + public byte? ReadGpio(int index) + { + return null; + } + + public void WriteGpio(int index, byte value) + { } + + public void SetControl(int index, byte? value) + { + if (index < 0 || index >= Controls.Length) + throw new ArgumentOutOfRangeException(nameof(index)); + + if (!Ring0.WaitIsaBusMutex(10)) + return; + + if (value.HasValue) { - if (index < 0 || index >= Controls.Length) - throw new ArgumentOutOfRangeException(nameof(index)); - - if (!Ring0.WaitIsaBusMutex(10)) - return; - - if (value.HasValue) + SaveDefaultFanPwmControl(index); + if (_fanPrimaryControlModeRegister.Length > 0) { - SaveDefaultFanPwmControl(index); - if (_fanPrimaryControlModeRegister.Length > 0) + WriteByte(0, _fanPrimaryControlModeRegister[index], (byte)(_fanPrimaryControlValue[index] & ReadByte(0, _fanPrimaryControlModeRegister[index]))); + if (_fanSecondaryControlModeRegister.Length > 0) { - WriteByte(0, _fanPrimaryControlModeRegister[index], (byte)(_fanPrimaryControlValue[index] & ReadByte(0, _fanPrimaryControlModeRegister[index]))); - if (_fanSecondaryControlModeRegister.Length > 0) + if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index]) { - if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index]) - { - WriteByte(0, _fanSecondaryControlModeRegister[index], (byte)(_fanSecondaryControlValue[index] & ReadByte(0, _fanSecondaryControlModeRegister[index]))); - } + WriteByte(0, _fanSecondaryControlModeRegister[index], (byte)(_fanSecondaryControlValue[index] & ReadByte(0, _fanSecondaryControlModeRegister[index]))); + } - if (_fanTertiaryControlModeRegister.Length > 0 && _fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index]) - { - WriteByte(0, _fanTertiaryControlModeRegister[index], (byte)(_fanTertiaryControlValue[index] & ReadByte(0, _fanTertiaryControlModeRegister[index]))); - } + if (_fanTertiaryControlModeRegister.Length > 0 && _fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index]) + { + WriteByte(0, _fanTertiaryControlModeRegister[index], (byte)(_fanTertiaryControlValue[index] & ReadByte(0, _fanTertiaryControlModeRegister[index]))); } } + } - // set output value - WriteByte(0, _fanPwmRegister[index], value.Value); + // set output value + WriteByte(0, _fanPwmRegister[index], value.Value); + } + else + { + RestoreDefaultFanPwmControl(index); + } + + Ring0.ReleaseIsaBusMutex(); + } + + private void SaveDefaultFanPwmControl(int index) //added to save initial control values + { + if (_fanPrimaryControlModeRegister.Length > 0 && + _initialFanControlValue.Length > 0 && + _fanPrimaryControlValue.Length > 0 && + _restoreDefaultFanPwmControlRequired.Length > 0 && + !_restoreDefaultFanPwmControlRequired[index]) + { + _initialFanControlValue[index] = ReadByte(0, _fanPrimaryControlModeRegister[index]); + if (_fanSecondaryControlModeRegister.Length > 0 && _initialFanSecondaryControlValue.Length > 0 && _fanSecondaryControlValue.Length > 0) + { + if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index]) + { + _initialFanSecondaryControlValue[index] = ReadByte(0, _fanSecondaryControlModeRegister[index]); + } + + if (_fanTertiaryControlModeRegister.Length > 0 && + _initialFanTertiaryControlValue.Length > 0 && + _fanTertiaryControlValue.Length > 0 && + _fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index]) + { + _initialFanTertiaryControlValue[index] = ReadByte(0, _fanTertiaryControlModeRegister[index]); + } + } + + _restoreDefaultFanPwmControlRequired[index] = true; + } + } + + private void RestoreDefaultFanPwmControl(int index) //added to restore initial control values + { + if (_fanPrimaryControlModeRegister.Length > 0 && + _initialFanControlValue.Length > 0 && + _fanPrimaryControlValue.Length > 0 && + _restoreDefaultFanPwmControlRequired.Length > 0 && + _restoreDefaultFanPwmControlRequired[index]) + { + WriteByte(0, + _fanPrimaryControlModeRegister[index], + (byte)((_initialFanControlValue[index] & ~_fanPrimaryControlValue[index]) | + ReadByte(0, _fanPrimaryControlModeRegister[index]))); //bitwise operands to change only desired bits + + if (_fanSecondaryControlModeRegister.Length > 0 && _initialFanSecondaryControlValue.Length > 0 && _fanSecondaryControlValue.Length > 0) + { + if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index]) + { + WriteByte(0, + _fanSecondaryControlModeRegister[index], + (byte)((_initialFanSecondaryControlValue[index] & ~_fanSecondaryControlValue[index]) | + ReadByte(0, _fanSecondaryControlModeRegister[index]))); //bitwise operands to change only desired bits + } + + if (_fanTertiaryControlModeRegister.Length > 0 && + _initialFanTertiaryControlValue.Length > 0 && + _fanTertiaryControlValue.Length > 0 && + _fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index]) + { + WriteByte(0, + _fanTertiaryControlModeRegister[index], + (byte)((_initialFanTertiaryControlValue[index] & ~_fanTertiaryControlValue[index]) | ReadByte(0, _fanTertiaryControlModeRegister[index]))); //bitwise operands to change only desired bits + } + } + + _restoreDefaultFanPwmControlRequired[index] = false; + } + } + + public void Update() + { + if (!Ring0.WaitIsaBusMutex(10)) + return; + + for (int i = 0; i < Voltages.Length; i++) + { + if (_voltageRegister[i] != VOLTAGE_VBAT_REG) + { + // two special VCore measurement modes for W83627THF + float fValue; + if ((Chip == Chip.W83627HF || Chip == Chip.W83627THF || Chip == Chip.W83687THF) && i == 0) + { + byte vrmConfiguration = ReadByte(0, 0x18); + int value = ReadByte(_voltageBank[i], _voltageRegister[i]); + if ((vrmConfiguration & 0x01) == 0) + fValue = 0.016f * value; // VRM8 formula + else + fValue = (0.00488f * value) + 0.69f; // VRM9 formula + } + else + { + int value = ReadByte(_voltageBank[i], _voltageRegister[i]); + fValue = _voltageGain * value; + } + + if (fValue > 0) + Voltages[i] = fValue; + else + Voltages[i] = null; } else { - RestoreDefaultFanPwmControl(index); - } - - Ring0.ReleaseIsaBusMutex(); - } - - private void SaveDefaultFanPwmControl(int index) //added to save initial control values - { - if (_fanPrimaryControlModeRegister.Length > 0 && - _initialFanControlValue.Length > 0 && - _fanPrimaryControlValue.Length > 0 && - _restoreDefaultFanPwmControlRequired.Length > 0 && - !_restoreDefaultFanPwmControlRequired[index]) - { - _initialFanControlValue[index] = ReadByte(0, _fanPrimaryControlModeRegister[index]); - if (_fanSecondaryControlModeRegister.Length > 0 && _initialFanSecondaryControlValue.Length > 0 && _fanSecondaryControlValue.Length > 0) + // Battery voltage + bool valid = (ReadByte(0, 0x5D) & 0x01) > 0; + if (valid) { - if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index]) - { - _initialFanSecondaryControlValue[index] = ReadByte(0, _fanSecondaryControlModeRegister[index]); - } - - if (_fanTertiaryControlModeRegister.Length > 0 && - _initialFanTertiaryControlValue.Length > 0 && - _fanTertiaryControlValue.Length > 0 && - _fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index]) - { - _initialFanTertiaryControlValue[index] = ReadByte(0, _fanTertiaryControlModeRegister[index]); - } - } - - _restoreDefaultFanPwmControlRequired[index] = true; - } - } - - private void RestoreDefaultFanPwmControl(int index) //added to restore initial control values - { - if (_fanPrimaryControlModeRegister.Length > 0 && - _initialFanControlValue.Length > 0 && - _fanPrimaryControlValue.Length > 0 && - _restoreDefaultFanPwmControlRequired.Length > 0 && - _restoreDefaultFanPwmControlRequired[index]) - { - WriteByte(0, - _fanPrimaryControlModeRegister[index], - (byte)((_initialFanControlValue[index] & ~_fanPrimaryControlValue[index]) | - ReadByte(0, _fanPrimaryControlModeRegister[index]))); //bitwise operands to change only desired bits - - if (_fanSecondaryControlModeRegister.Length > 0 && _initialFanSecondaryControlValue.Length > 0 && _fanSecondaryControlValue.Length > 0) - { - if (_fanSecondaryControlModeRegister[index] != _fanPrimaryControlModeRegister[index]) - { - WriteByte(0, - _fanSecondaryControlModeRegister[index], - (byte)((_initialFanSecondaryControlValue[index] & ~_fanSecondaryControlValue[index]) | - ReadByte(0, _fanSecondaryControlModeRegister[index]))); //bitwise operands to change only desired bits - } - - if (_fanTertiaryControlModeRegister.Length > 0 && - _initialFanTertiaryControlValue.Length > 0 && - _fanTertiaryControlValue.Length > 0 && - _fanTertiaryControlModeRegister[index] != _fanSecondaryControlModeRegister[index]) - { - WriteByte(0, - _fanTertiaryControlModeRegister[index], - (byte)((_initialFanTertiaryControlValue[index] & ~_fanTertiaryControlValue[index]) | ReadByte(0, _fanTertiaryControlModeRegister[index]))); //bitwise operands to change only desired bits - } - } - - _restoreDefaultFanPwmControlRequired[index] = false; - } - } - - public void Update() - { - if (!Ring0.WaitIsaBusMutex(10)) - return; - - for (int i = 0; i < Voltages.Length; i++) - { - if (_voltageRegister[i] != VOLTAGE_VBAT_REG) - { - // two special VCore measurement modes for W83627THF - float fValue; - if ((Chip == Chip.W83627HF || Chip == Chip.W83627THF || Chip == Chip.W83687THF) && i == 0) - { - byte vrmConfiguration = ReadByte(0, 0x18); - int value = ReadByte(_voltageBank[i], _voltageRegister[i]); - if ((vrmConfiguration & 0x01) == 0) - fValue = 0.016f * value; // VRM8 formula - else - fValue = (0.00488f * value) + 0.69f; // VRM9 formula - } - else - { - int value = ReadByte(_voltageBank[i], _voltageRegister[i]); - fValue = _voltageGain * value; - } - - if (fValue > 0) - Voltages[i] = fValue; - else - Voltages[i] = null; + Voltages[i] = _voltageGain * ReadByte(5, VOLTAGE_VBAT_REG); } else { - // Battery voltage - bool valid = (ReadByte(0, 0x5D) & 0x01) > 0; - if (valid) - { - Voltages[i] = _voltageGain * ReadByte(5, VOLTAGE_VBAT_REG); - } - else - { - Voltages[i] = null; - } + Voltages[i] = null; } } - - for (int i = 0; i < Temperatures.Length; i++) - { - int value = (sbyte)ReadByte(TEMPERATURE_BANK[i], TEMPERATURE_REG[i]) << 1; - if (TEMPERATURE_BANK[i] > 0) - value |= ReadByte(TEMPERATURE_BANK[i], (byte)(TEMPERATURE_REG[i] + 1)) >> 7; - - float temperature = value / 2.0f; - if (temperature is <= 125 and >= -55 && !_peciTemperature[i]) - { - Temperatures[i] = temperature; - } - else - { - Temperatures[i] = null; - } - } - - ulong bits = 0; - foreach (byte t in FAN_BIT_REG) - bits = (bits << 8) | ReadByte(0, t); - - ulong newBits = bits; - for (int i = 0; i < Fans.Length; i++) - { - int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]); - - // assemble fan divisor - int divisorBits = (int)( - (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) | - (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) | - ((bits >> FAN_DIV_BIT0[i]) & 1)); - - int divisor = 1 << divisorBits; - - Fans[i] = count < 0xff ? 1.35e6f / (count * divisor) : 0; - - switch (count) - { - // update fan divisor - case > 192 when divisorBits < 7: - divisorBits++; - break; - case < 96 when divisorBits > 0: - divisorBits--; - break; - } - - newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1); - newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1); - newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1); - } - - for (int i = 0; i < Controls.Length; i++) - { - byte value = ReadByte(0, _fanPwmRegister[i]); - Controls[i] = (float)Math.Round(value * 100.0f / 0xFF); - } - - Ring0.ReleaseIsaBusMutex(); } - public string GetReport() + for (int i = 0; i < Temperatures.Length; i++) { - StringBuilder r = new(); + int value = (sbyte)ReadByte(TEMPERATURE_BANK[i], TEMPERATURE_REG[i]) << 1; + if (TEMPERATURE_BANK[i] > 0) + value |= ReadByte(TEMPERATURE_BANK[i], (byte)(TEMPERATURE_REG[i] + 1)) >> 7; - r.AppendLine("LPC " + GetType().Name); - r.AppendLine(); - r.Append("Chip Id: 0x"); - r.AppendLine(Chip.ToString("X")); - r.Append("Chip Revision: 0x"); - r.AppendLine(_revision.ToString("X", CultureInfo.InvariantCulture)); - r.Append("Base Address: 0x"); - r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture)); - r.AppendLine(); + float temperature = value / 2.0f; + if (temperature is <= 125 and >= -55 && !_peciTemperature[i]) + { + Temperatures[i] = temperature; + } + else + { + Temperatures[i] = null; + } + } - if (!Ring0.WaitIsaBusMutex(100)) - return r.ToString(); + ulong bits = 0; + foreach (byte t in FAN_BIT_REG) + bits = (bits << 8) | ReadByte(0, t); + + ulong newBits = bits; + for (int i = 0; i < Fans.Length; i++) + { + int count = ReadByte(FAN_TACHO_BANK[i], FAN_TACHO_REG[i]); + + // assemble fan divisor + int divisorBits = (int)( + (((bits >> FAN_DIV_BIT2[i]) & 1) << 2) | + (((bits >> FAN_DIV_BIT1[i]) & 1) << 1) | + ((bits >> FAN_DIV_BIT0[i]) & 1)); + + int divisor = 1 << divisorBits; + + Fans[i] = count < 0xff ? 1.35e6f / (count * divisor) : 0; + + switch (count) + { + // update fan divisor + case > 192 when divisorBits < 7: + divisorBits++; + break; + case < 96 when divisorBits > 0: + divisorBits--; + break; + } + + newBits = SetBit(newBits, FAN_DIV_BIT2[i], (divisorBits >> 2) & 1); + newBits = SetBit(newBits, FAN_DIV_BIT1[i], (divisorBits >> 1) & 1); + newBits = SetBit(newBits, FAN_DIV_BIT0[i], divisorBits & 1); + } + + for (int i = 0; i < Controls.Length; i++) + { + byte value = ReadByte(0, _fanPwmRegister[i]); + Controls[i] = (float)Math.Round(value * 100.0f / 0xFF); + } + + Ring0.ReleaseIsaBusMutex(); + } + + public string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("LPC " + GetType().Name); + r.AppendLine(); + r.Append("Chip Id: 0x"); + r.AppendLine(Chip.ToString("X")); + r.Append("Chip Revision: 0x"); + r.AppendLine(_revision.ToString("X", CultureInfo.InvariantCulture)); + r.Append("Base Address: 0x"); + r.AppendLine(_address.ToString("X4", CultureInfo.InvariantCulture)); + r.AppendLine(); + + if (!Ring0.WaitIsaBusMutex(100)) + return r.ToString(); + + r.AppendLine("Hardware Monitor Registers"); + r.AppendLine(); + r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); + r.AppendLine(); + for (int i = 0; i <= 0x7; i++) + { + r.Append(" "); + r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); + r.Append(" "); + for (int j = 0; j <= 0xF; j++) + { + r.Append(" "); + r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString("X2", CultureInfo.InvariantCulture)); + } - r.AppendLine("Hardware Monitor Registers"); r.AppendLine(); - r.AppendLine(" 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F"); - r.AppendLine(); - for (int i = 0; i <= 0x7; i++) + } + + for (int k = 1; k <= 15; k++) + { + r.AppendLine("Bank " + k); + for (int i = 0x5; i < 0x6; i++) { r.Append(" "); r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); @@ -429,89 +446,71 @@ namespace LibreHardwareMonitor.Hardware.Motherboard.Lpc for (int j = 0; j <= 0xF; j++) { r.Append(" "); - r.Append(ReadByte(0, (byte)((i << 4) | j)).ToString("X2", CultureInfo.InvariantCulture)); + r.Append(ReadByte((byte)k, (byte)((i << 4) | j)).ToString("X2", CultureInfo.InvariantCulture)); } r.AppendLine(); } - - for (int k = 1; k <= 15; k++) - { - r.AppendLine("Bank " + k); - for (int i = 0x5; i < 0x6; i++) - { - r.Append(" "); - r.Append((i << 4).ToString("X2", CultureInfo.InvariantCulture)); - r.Append(" "); - for (int j = 0; j <= 0xF; j++) - { - r.Append(" "); - r.Append(ReadByte((byte)k, (byte)((i << 4) | j)).ToString("X2", CultureInfo.InvariantCulture)); - } - - r.AppendLine(); - } - } - - r.AppendLine(); - Ring0.ReleaseIsaBusMutex(); - return r.ToString(); } - private byte ReadByte(byte bank, byte register) - { - Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER); - Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), bank); - Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); - return Ring0.ReadIoPort((ushort)(_address + DATA_REGISTER_OFFSET)); - } - - private void WriteByte(byte bank, byte register, byte value) - { - Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER); - Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), bank); - Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); - Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), value); - } - - private bool IsWinbondVendor() - { - ushort vendorId = (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) | ReadByte(0, VENDOR_ID_REGISTER)); - return vendorId == WINBOND_VENDOR_ID; - } - - private static ulong SetBit(ulong target, int bit, int value) - { - if ((value & 1) != value) - throw new ArgumentException("Value must be one bit only."); - - if (bit is < 0 or > 63) - throw new ArgumentException("Bit out of range."); - - ulong mask = (ulong)1 << bit; - return value > 0 ? target | mask : target & ~mask; - } - // ReSharper disable InconsistentNaming - - private const byte ADDRESS_REGISTER_OFFSET = 0x05; - private const byte BANK_SELECT_REGISTER = 0x4E; - private const byte DATA_REGISTER_OFFSET = 0x06; - private const byte HIGH_BYTE = 0x80; - private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49; - private const byte VENDOR_ID_REGISTER = 0x4F; - private const byte VOLTAGE_VBAT_REG = 0x51; - - private const ushort WINBOND_VENDOR_ID = 0x5CA3; - - private readonly byte[] FAN_BIT_REG = { 0x47, 0x4B, 0x4C, 0x59, 0x5D }; - private readonly byte[] FAN_DIV_BIT0 = { 36, 38, 30, 8, 10 }; - private readonly byte[] FAN_DIV_BIT1 = { 37, 39, 31, 9, 11 }; - private readonly byte[] FAN_DIV_BIT2 = { 5, 6, 7, 23, 15 }; - private readonly byte[] FAN_TACHO_BANK = { 0, 0, 0, 0, 5 }; - private readonly byte[] FAN_TACHO_REG = { 0x28, 0x29, 0x2A, 0x3F, 0x53 }; - private readonly byte[] TEMPERATURE_BANK = { 1, 2, 0 }; - private readonly byte[] TEMPERATURE_REG = { 0x50, 0x50, 0x27 }; - - // ReSharper restore InconsistentNaming + r.AppendLine(); + Ring0.ReleaseIsaBusMutex(); + return r.ToString(); } + + private byte ReadByte(byte bank, byte register) + { + Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER); + Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), bank); + Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); + return Ring0.ReadIoPort((ushort)(_address + DATA_REGISTER_OFFSET)); + } + + private void WriteByte(byte bank, byte register, byte value) + { + Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), BANK_SELECT_REGISTER); + Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), bank); + Ring0.WriteIoPort((ushort)(_address + ADDRESS_REGISTER_OFFSET), register); + Ring0.WriteIoPort((ushort)(_address + DATA_REGISTER_OFFSET), value); + } + + private bool IsWinbondVendor() + { + ushort vendorId = (ushort)((ReadByte(HIGH_BYTE, VENDOR_ID_REGISTER) << 8) | ReadByte(0, VENDOR_ID_REGISTER)); + return vendorId == WINBOND_VENDOR_ID; + } + + private static ulong SetBit(ulong target, int bit, int value) + { + if ((value & 1) != value) + throw new ArgumentException("Value must be one bit only."); + + if (bit is < 0 or > 63) + throw new ArgumentException("Bit out of range."); + + ulong mask = (ulong)1 << bit; + return value > 0 ? target | mask : target & ~mask; + } + // ReSharper disable InconsistentNaming + + private const byte ADDRESS_REGISTER_OFFSET = 0x05; + private const byte BANK_SELECT_REGISTER = 0x4E; + private const byte DATA_REGISTER_OFFSET = 0x06; + private const byte HIGH_BYTE = 0x80; + private const byte TEMPERATURE_SOURCE_SELECT_REG = 0x49; + private const byte VENDOR_ID_REGISTER = 0x4F; + private const byte VOLTAGE_VBAT_REG = 0x51; + + private const ushort WINBOND_VENDOR_ID = 0x5CA3; + + private readonly byte[] FAN_BIT_REG = { 0x47, 0x4B, 0x4C, 0x59, 0x5D }; + private readonly byte[] FAN_DIV_BIT0 = { 36, 38, 30, 8, 10 }; + private readonly byte[] FAN_DIV_BIT1 = { 37, 39, 31, 9, 11 }; + private readonly byte[] FAN_DIV_BIT2 = { 5, 6, 7, 23, 15 }; + private readonly byte[] FAN_TACHO_BANK = { 0, 0, 0, 0, 5 }; + private readonly byte[] FAN_TACHO_REG = { 0x28, 0x29, 0x2A, 0x3F, 0x53 }; + private readonly byte[] TEMPERATURE_BANK = { 1, 2, 0 }; + private readonly byte[] TEMPERATURE_REG = { 0x50, 0x50, 0x27 }; + + // ReSharper restore InconsistentNaming } diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs index a1cb6d4..70c51a7 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Manufacturer.cs @@ -6,52 +6,51 @@ using System.Diagnostics.CodeAnalysis; -namespace LibreHardwareMonitor.Hardware.Motherboard +namespace LibreHardwareMonitor.Hardware.Motherboard; + +[SuppressMessage("ReSharper", "IdentifierTypo")] +[SuppressMessage("ReSharper", "CommentTypo")] +[SuppressMessage("ReSharper", "InconsistentNaming")] +internal enum Manufacturer { - [SuppressMessage("ReSharper", "IdentifierTypo")] - [SuppressMessage("ReSharper", "CommentTypo")] - [SuppressMessage("ReSharper", "InconsistentNaming")] - internal enum Manufacturer - { - Abit, - Acer, - Alienware, - AMD, - AOpen, - Apple, - ASRock, - ASUS, - Biostar, - Clevo, - Dell, - DFI, - ECS, - EPoX, - EVGA, - FIC, - Foxconn, - Fujitsu, - Gateway, - Gigabyte, - HP, - IBM, - Intel, - Jetway, - LattePanda, - Lenovo, - Medion, - Microsoft, - MSI, - NEC, - Pegatron, - Samsung, - Sapphire, - Shuttle, - Sony, - Supermicro, - Toshiba, - XFX, - Zotac, - Unknown - } -} + Abit, + Acer, + Alienware, + AMD, + AOpen, + Apple, + ASRock, + ASUS, + Biostar, + Clevo, + Dell, + DFI, + ECS, + EPoX, + EVGA, + FIC, + Foxconn, + Fujitsu, + Gateway, + Gigabyte, + HP, + IBM, + Intel, + Jetway, + LattePanda, + Lenovo, + Medion, + Microsoft, + MSI, + NEC, + Pegatron, + Samsung, + Sapphire, + Shuttle, + Sony, + Supermicro, + Toshiba, + XFX, + Zotac, + Unknown +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs index 195a042..86995be 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Model.cs @@ -8,157 +8,156 @@ using System.Diagnostics.CodeAnalysis; -namespace LibreHardwareMonitor.Hardware.Motherboard +namespace LibreHardwareMonitor.Hardware.Motherboard; + +[SuppressMessage("ReSharper", "IdentifierTypo")] +[SuppressMessage("ReSharper", "CommentTypo")] +internal enum Model { - [SuppressMessage("ReSharper", "IdentifierTypo")] - [SuppressMessage("ReSharper", "CommentTypo")] - internal enum Model - { - // ASRock - _880GMH_USB3, - A320M_HDV, - AB350_Pro4, - AB350M, - AB350M_HDV, - AB350M_Pro4, - AOD790GX_128M, - B450_Pro4, - B450_Steel_Legend, - B450M_Pro4, - B450M_Steel_Legend, - B85M_DGS, - Fatal1ty_AB350_Gaming_K4, - P55_Deluxe, - X399_Phantom_Gaming_6, - Z77Pro4M, - X570_Pro4, - X570_Taichi, - X570_Phantom_Gaming_ITX, + // ASRock + _880GMH_USB3, + A320M_HDV, + AB350_Pro4, + AB350M, + AB350M_HDV, + AB350M_Pro4, + AOD790GX_128M, + B450_Pro4, + B450_Steel_Legend, + B450M_Pro4, + B450M_Steel_Legend, + B85M_DGS, + Fatal1ty_AB350_Gaming_K4, + P55_Deluxe, + X399_Phantom_Gaming_6, + Z77Pro4M, + X570_Pro4, + X570_Taichi, + X570_Phantom_Gaming_ITX, - // ASUS - CROSSHAIR_III_FORMULA, - ROG_CROSSHAIR_VIII_HERO, - ROG_CROSSHAIR_VIII_HERO_WIFI, - ROG_CROSSHAIR_VIII_DARK_HERO, - ROG_CROSSHAIR_VIII_FORMULA, - ROG_CROSSHAIR_VIII_IMPACT, - ROG_STRIX_X470_I, - ROG_STRIX_X570_E_GAMING, - ROG_STRIX_X570_F_GAMING, - ROG_STRIX_X570_I_GAMING, - ROG_STRIX_B550_E_GAMING, - ROG_STRIX_B550_F_GAMING_WIFI, - ROG_STRIX_B550_I_GAMING, - ROG_STRIX_Z690_A_GAMING_WIFI_D4, - ROG_MAXIMUS_Z690_EXTREME_GLACIAL, - M2N_SLI_Deluxe, - M4A79XTD_EVO, - P5W_DH_Deluxe, - P6T, - P6X58D_E, - P8P67, - P8P67_EVO, - P8P67_M_PRO, - P8P67_PRO, - P8Z77_V, - P9X79, - PRIME_X370_PRO, - PRIME_X470_PRO, - PRIME_X570_PRO, - PROART_X570_CREATOR_WIFI, - PRO_WS_X570_ACE, - RAMPAGE_EXTREME, - RAMPAGE_II_GENE, - ROG_MAXIMUS_X_APEX, - ROG_ZENITH_EXTREME, - ROG_ZENITH_II_EXTREME, - TUF_X470_PLUS_GAMING, - Z170_A, - TUF_GAMING_B550M_PLUS_WIFI, + // ASUS + CROSSHAIR_III_FORMULA, + ROG_CROSSHAIR_VIII_HERO, + ROG_CROSSHAIR_VIII_HERO_WIFI, + ROG_CROSSHAIR_VIII_DARK_HERO, + ROG_CROSSHAIR_VIII_FORMULA, + ROG_CROSSHAIR_VIII_IMPACT, + ROG_STRIX_X470_I, + ROG_STRIX_X570_E_GAMING, + ROG_STRIX_X570_F_GAMING, + ROG_STRIX_X570_I_GAMING, + ROG_STRIX_B550_E_GAMING, + ROG_STRIX_B550_F_GAMING_WIFI, + ROG_STRIX_B550_I_GAMING, + ROG_STRIX_Z690_A_GAMING_WIFI_D4, + ROG_MAXIMUS_Z690_EXTREME_GLACIAL, + M2N_SLI_Deluxe, + M4A79XTD_EVO, + P5W_DH_Deluxe, + P6T, + P6X58D_E, + P8P67, + P8P67_EVO, + P8P67_M_PRO, + P8P67_PRO, + P8Z77_V, + P9X79, + PRIME_X370_PRO, + PRIME_X470_PRO, + PRIME_X570_PRO, + PROART_X570_CREATOR_WIFI, + PRO_WS_X570_ACE, + RAMPAGE_EXTREME, + RAMPAGE_II_GENE, + ROG_MAXIMUS_X_APEX, + ROG_ZENITH_EXTREME, + ROG_ZENITH_II_EXTREME, + TUF_X470_PLUS_GAMING, + Z170_A, + TUF_GAMING_B550M_PLUS_WIFI, - //BIOSTAR - B660GTN, + //BIOSTAR + B660GTN, - // DFI - LP_BI_P45_T2RS_Elite, - LP_DK_P55_T3EH9, + // DFI + LP_BI_P45_T2RS_Elite, + LP_DK_P55_T3EH9, - // ECS - A890GXM_A, + // ECS + A890GXM_A, - // MSI - B350_Gaming_Plus, - B360M_PRO_VDH, - B450A_PRO, - Z270_PC_MATE, + // MSI + B350_Gaming_Plus, + B360M_PRO_VDH, + B450A_PRO, + Z270_PC_MATE, - // EVGA - X58_SLI_Classified, + // EVGA + X58_SLI_Classified, - // Gigabyte - _965P_S3, - _970A_UD3, - AB350_Gaming_3, - AX370_Gaming_5, - AX370_Gaming_K7, - B360_AORUS_GAMING_3_WIFI_CF, - B560M_AORUS_ELITE, - B560M_AORUS_PRO, - B560M_AORUS_PRO_AX, - EP45_DS3R, - EP45_UD3R, - EX58_EXTREME, - EX58_UD3R, - G41M_COMBO, - G41MT_S2, - G41MT_S2P, - H55_USB3, - H55N_USB3, - H61M_DS2_REV_1_2, - H61M_USB3_B3_REV_2_0, - H67A_UD3H_B3, - H67A_USB3_B3, - H81M_HD3, - MA770T_UD3, - MA770T_UD3P, - MA785GM_US2H, - MA785GMT_UD2H, - MA78LM_S2H, - MA790X_UD3P, - P35_DS3, - P35_DS3L, - P55_UD4, - P55A_UD3, - P55M_UD4, - P67A_UD3_B3, - P67A_UD3R_B3, - P67A_UD4_B3, - P8Z68_V_PRO, - X38_DS5, - X399_AORUS_Gaming_7, - X58A_UD3R, - X79_UD3, - Z390_AORUS_ULTRA, - Z390_AORUS_PRO, - Z390_M_GAMING, - Z390_UD, - Z68A_D3H_B3, - Z68AP_D3, - Z68X_UD3H_B3, - Z68X_UD7_B3, - Z68XP_UD3R, - Z690_AORUS_PRO, - Z690_GAMING_X_DDR4, - Z170N_WIFI, - X470_AORUS_GAMING_7_WIFI, - X570_AORUS_MASTER, - X570_GAMING_X, - X570_AORUS_ULTRA, + // Gigabyte + _965P_S3, + _970A_UD3, + AB350_Gaming_3, + AX370_Gaming_5, + AX370_Gaming_K7, + B360_AORUS_GAMING_3_WIFI_CF, + B560M_AORUS_ELITE, + B560M_AORUS_PRO, + B560M_AORUS_PRO_AX, + EP45_DS3R, + EP45_UD3R, + EX58_EXTREME, + EX58_UD3R, + G41M_COMBO, + G41MT_S2, + G41MT_S2P, + H55_USB3, + H55N_USB3, + H61M_DS2_REV_1_2, + H61M_USB3_B3_REV_2_0, + H67A_UD3H_B3, + H67A_USB3_B3, + H81M_HD3, + MA770T_UD3, + MA770T_UD3P, + MA785GM_US2H, + MA785GMT_UD2H, + MA78LM_S2H, + MA790X_UD3P, + P35_DS3, + P35_DS3L, + P55_UD4, + P55A_UD3, + P55M_UD4, + P67A_UD3_B3, + P67A_UD3R_B3, + P67A_UD4_B3, + P8Z68_V_PRO, + X38_DS5, + X399_AORUS_Gaming_7, + X58A_UD3R, + X79_UD3, + Z390_AORUS_ULTRA, + Z390_AORUS_PRO, + Z390_M_GAMING, + Z390_UD, + Z68A_D3H_B3, + Z68AP_D3, + Z68X_UD3H_B3, + Z68X_UD7_B3, + Z68XP_UD3R, + Z690_AORUS_PRO, + Z690_GAMING_X_DDR4, + Z170N_WIFI, + X470_AORUS_GAMING_7_WIFI, + X570_AORUS_MASTER, + X570_GAMING_X, + X570_AORUS_ULTRA, - // Shuttle - FH67, + // Shuttle + FH67, - // Unknown - Unknown - } -} + // Unknown + Unknown +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs index cdd8421..e29561a 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/Motherboard.cs @@ -11,179 +11,178 @@ using LibreHardwareMonitor.Hardware.Motherboard.Lpc; using LibreHardwareMonitor.Hardware.Motherboard.Lpc.EC; using OperatingSystem = LibreHardwareMonitor.Software.OperatingSystem; -namespace LibreHardwareMonitor.Hardware.Motherboard +namespace LibreHardwareMonitor.Hardware.Motherboard; + +/// +/// Represents the motherboard of a computer with its and as . +/// +public class Motherboard : IHardware { + private readonly LMSensors _lmSensors; + private readonly LpcIO _lpcIO; + private readonly string _name; + private readonly ISettings _settings; + private string _customName; + /// - /// Represents the motherboard of a computer with its and as . + /// Creates motherboard instance by retrieving information from and creates a new based on data from and . /// - public class Motherboard : IHardware + /// table containing motherboard data. + /// Additional settings passed by . + public Motherboard(SMBios smBios, ISettings settings) { - private readonly LMSensors _lmSensors; - private readonly LpcIO _lpcIO; - private readonly string _name; - private readonly ISettings _settings; - private string _customName; + IReadOnlyList superIO; + _settings = settings; + SMBios = smBios; - /// - /// Creates motherboard instance by retrieving information from and creates a new based on data from and . - /// - /// table containing motherboard data. - /// Additional settings passed by . - public Motherboard(SMBios smBios, ISettings settings) + Manufacturer manufacturer = smBios.Board == null ? Manufacturer.Unknown : Identification.GetManufacturer(smBios.Board.ManufacturerName); + Model model = smBios.Board == null ? Model.Unknown : Identification.GetModel(smBios.Board.ProductName); + + if (smBios.Board != null) { - IReadOnlyList superIO; - _settings = settings; - SMBios = smBios; - - Manufacturer manufacturer = smBios.Board == null ? Manufacturer.Unknown : Identification.GetManufacturer(smBios.Board.ManufacturerName); - Model model = smBios.Board == null ? Model.Unknown : Identification.GetModel(smBios.Board.ProductName); - - if (smBios.Board != null) + if (!string.IsNullOrEmpty(smBios.Board.ProductName)) { - if (!string.IsNullOrEmpty(smBios.Board.ProductName)) - { - if (manufacturer == Manufacturer.Unknown) - _name = smBios.Board.ProductName; - else - _name = manufacturer + " " + smBios.Board.ProductName; - } + if (manufacturer == Manufacturer.Unknown) + _name = smBios.Board.ProductName; else - { - _name = manufacturer.ToString(); - } + _name = manufacturer + " " + smBios.Board.ProductName; } else { - _name = nameof(Manufacturer.Unknown); - } - - _customName = settings.GetValue(new Identifier(Identifier, "name").ToString(), _name); - - if (OperatingSystem.IsUnix) - { - _lmSensors = new LMSensors(); - superIO = _lmSensors.SuperIO; - } - else - { - _lpcIO = new LpcIO(); - superIO = _lpcIO.SuperIO; - } - - EmbeddedController embeddedController = EmbeddedController.Create(model, settings); - - SubHardware = new IHardware[superIO.Count + (embeddedController != null ? 1 : 0)]; - for (int i = 0; i < superIO.Count; i++) - SubHardware[i] = new SuperIOHardware(this, superIO[i], manufacturer, model, settings); - - if (embeddedController != null) - SubHardware[superIO.Count] = embeddedController; - } - - /// - public event SensorEventHandler SensorAdded; - - /// - public event SensorEventHandler SensorRemoved; - - /// - public HardwareType HardwareType - { - get { return HardwareType.Motherboard; } - } - - /// - public Identifier Identifier - { - get { return new Identifier("motherboard"); } - } - - /// - /// Gets the name obtained from . - /// - public string Name - { - get { return _customName; } - set - { - _customName = !string.IsNullOrEmpty(value) ? value : _name; - - _settings.SetValue(new Identifier(Identifier, "name").ToString(), _customName); + _name = manufacturer.ToString(); } } - - /// - /// Always - public virtual IHardware Parent + else { - get { return null; } + _name = nameof(Manufacturer.Unknown); } - /// - public virtual IDictionary Properties => new SortedDictionary(); + _customName = settings.GetValue(new Identifier(Identifier, "name").ToString(), _name); - /// - public ISensor[] Sensors + if (OperatingSystem.IsUnix) { - get { return Array.Empty(); } + _lmSensors = new LMSensors(); + superIO = _lmSensors.SuperIO; + } + else + { + _lpcIO = new LpcIO(); + superIO = _lpcIO.SuperIO; } - /// - /// Gets the information. - /// - public SMBios SMBios { get; } + EmbeddedController embeddedController = EmbeddedController.Create(model, settings); - /// - public IHardware[] SubHardware { get; } + SubHardware = new IHardware[superIO.Count + (embeddedController != null ? 1 : 0)]; + for (int i = 0; i < superIO.Count; i++) + SubHardware[i] = new SuperIOHardware(this, superIO[i], manufacturer, model, settings); - /// - public string GetReport() + if (embeddedController != null) + SubHardware[superIO.Count] = embeddedController; + } + + /// + public event SensorEventHandler SensorAdded; + + /// + public event SensorEventHandler SensorRemoved; + + /// + public HardwareType HardwareType + { + get { return HardwareType.Motherboard; } + } + + /// + public Identifier Identifier + { + get { return new Identifier("motherboard"); } + } + + /// + /// Gets the name obtained from . + /// + public string Name + { + get { return _customName; } + set { - StringBuilder r = new(); + _customName = !string.IsNullOrEmpty(value) ? value : _name; - r.AppendLine("Motherboard"); - r.AppendLine(); - r.Append(SMBios.GetReport()); - - if (_lpcIO != null) - r.Append(_lpcIO.GetReport()); - - return r.ToString(); - } - - /// - /// Motherboard itself cannot be updated. Update instead. - /// - public void Update() - {} - - /// - public void Accept(IVisitor visitor) - { - if (visitor == null) - throw new ArgumentNullException(nameof(visitor)); - - visitor.VisitHardware(this); - } - - /// - public void Traverse(IVisitor visitor) - { - foreach (IHardware hardware in SubHardware) - hardware.Accept(visitor); - } - - /// - /// Closes using . - /// - public void Close() - { - _lmSensors?.Close(); - foreach (IHardware iHardware in SubHardware) - { - if (iHardware is Hardware hardware) - hardware.Close(); - } + _settings.SetValue(new Identifier(Identifier, "name").ToString(), _customName); } } -} + + /// + /// Always + public virtual IHardware Parent + { + get { return null; } + } + + /// + public virtual IDictionary Properties => new SortedDictionary(); + + /// + public ISensor[] Sensors + { + get { return Array.Empty(); } + } + + /// + /// Gets the information. + /// + public SMBios SMBios { get; } + + /// + public IHardware[] SubHardware { get; } + + /// + public string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("Motherboard"); + r.AppendLine(); + r.Append(SMBios.GetReport()); + + if (_lpcIO != null) + r.Append(_lpcIO.GetReport()); + + return r.ToString(); + } + + /// + /// Motherboard itself cannot be updated. Update instead. + /// + public void Update() + {} + + /// + public void Accept(IVisitor visitor) + { + if (visitor == null) + throw new ArgumentNullException(nameof(visitor)); + + visitor.VisitHardware(this); + } + + /// + public void Traverse(IVisitor visitor) + { + foreach (IHardware hardware in SubHardware) + hardware.Accept(visitor); + } + + /// + /// Closes using . + /// + public void Close() + { + _lmSensors?.Close(); + foreach (IHardware iHardware in SubHardware) + { + if (iHardware is Hardware hardware) + hardware.Close(); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/MotherboardGroup.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/MotherboardGroup.cs index 52c5dc6..39fc164 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/MotherboardGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/MotherboardGroup.cs @@ -6,29 +6,28 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Motherboard +namespace LibreHardwareMonitor.Hardware.Motherboard; + +internal class MotherboardGroup : IGroup { - internal class MotherboardGroup : IGroup + private readonly Motherboard[] _motherboards; + + public MotherboardGroup(SMBios smbios, ISettings settings) { - private readonly Motherboard[] _motherboards; - - public MotherboardGroup(SMBios smbios, ISettings settings) - { - _motherboards = new Motherboard[1]; - _motherboards[0] = new Motherboard(smbios, settings); - } - - public IReadOnlyList Hardware => _motherboards; - - public void Close() - { - foreach (Motherboard mainboard in _motherboards) - mainboard.Close(); - } - - public string GetReport() - { - return null; - } + _motherboards = new Motherboard[1]; + _motherboards[0] = new Motherboard(smbios, settings); } -} + + public IReadOnlyList Hardware => _motherboards; + + public void Close() + { + foreach (Motherboard mainboard in _motherboards) + mainboard.Close(); + } + + public string GetReport() + { + return null; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs b/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs index 025e28b..d15b828 100644 --- a/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs +++ b/LibreHardwareMonitorLib/Hardware/Motherboard/SuperIOHardware.cs @@ -9,1907 +9,2017 @@ using System.Collections.Generic; using System.Threading; using LibreHardwareMonitor.Hardware.Motherboard.Lpc; -namespace LibreHardwareMonitor.Hardware.Motherboard +namespace LibreHardwareMonitor.Hardware.Motherboard; + +internal sealed class SuperIOHardware : Hardware { - internal sealed class SuperIOHardware : Hardware + private readonly List _controls = new(); + private readonly List _fans = new(); + private readonly Motherboard _motherboard; + + private readonly UpdateDelegate _postUpdate; + private readonly ReadValueDelegate _readControl; + private readonly ReadValueDelegate _readFan; + private readonly ReadValueDelegate _readTemperature; + private readonly ReadValueDelegate _readVoltage; + + private readonly ISuperIO _superIO; + private readonly List _temperatures = new(); + private readonly List _voltages = new(); + + public SuperIOHardware(Motherboard motherboard, ISuperIO superIO, Manufacturer manufacturer, Model model, ISettings settings) + : base(ChipName.GetName(superIO.Chip), new Identifier("lpc", superIO.Chip.ToString().ToLowerInvariant()), settings) { - private readonly List _controls = new(); - private readonly List _fans = new(); - private readonly Motherboard _motherboard; + _motherboard = motherboard; + _superIO = superIO; - private readonly UpdateDelegate _postUpdate; - private readonly ReadValueDelegate _readControl; - private readonly ReadValueDelegate _readFan; - private readonly ReadValueDelegate _readTemperature; - private readonly ReadValueDelegate _readVoltage; + GetBoardSpecificConfiguration(superIO, + manufacturer, + model, + out IList v, + out IList t, + out IList f, + out IList c, + out _readVoltage, + out _readTemperature, + out _readFan, + out _readControl, + out _postUpdate, + out _); - private readonly ISuperIO _superIO; - private readonly List _temperatures = new(); - private readonly List _voltages = new(); + CreateVoltageSensors(superIO, settings, v); + CreateTemperatureSensors(superIO, settings, t); + CreateFanSensors(superIO, settings, f); + CreateControlSensors(superIO, settings, c); + } - public SuperIOHardware(Motherboard motherboard, ISuperIO superIO, Manufacturer manufacturer, Model model, ISettings settings) - : base(ChipName.GetName(superIO.Chip), new Identifier("lpc", superIO.Chip.ToString().ToLowerInvariant()), settings) + public override HardwareType HardwareType + { + get { return HardwareType.SuperIO; } + } + + public override IHardware Parent + { + get { return _motherboard; } + } + + private void CreateControlSensors(ISuperIO superIO, ISettings settings, IList c) + { + foreach (Ctrl ctrl in c) { - _motherboard = motherboard; - _superIO = superIO; - - GetBoardSpecificConfiguration(superIO, - manufacturer, - model, - out IList v, - out IList t, - out IList f, - out IList c, - out _readVoltage, - out _readTemperature, - out _readFan, - out _readControl, - out _postUpdate, - out _); - - CreateVoltageSensors(superIO, settings, v); - CreateTemperatureSensors(superIO, settings, t); - CreateFanSensors(superIO, settings, f); - CreateControlSensors(superIO, settings, c); - } - - public override HardwareType HardwareType - { - get { return HardwareType.SuperIO; } - } - - public override IHardware Parent - { - get { return _motherboard; } - } - - private void CreateControlSensors(ISuperIO superIO, ISettings settings, IList c) - { - foreach (Ctrl ctrl in c) + int index = ctrl.Index; + if (index < superIO.Controls.Length) { - int index = ctrl.Index; - if (index < superIO.Controls.Length) + Sensor sensor = new(ctrl.Name, index, SensorType.Control, this, settings); + Control control = new(sensor, settings, 0, 100); + control.ControlModeChanged += cc => { - Sensor sensor = new(ctrl.Name, index, SensorType.Control, this, settings); - Control control = new(sensor, settings, 0, 100); - control.ControlModeChanged += cc => - { - switch (cc.ControlMode) - { - case ControlMode.Undefined: - return; - case ControlMode.Default: - superIO.SetControl(index, null); - break; - case ControlMode.Software: - superIO.SetControl(index, GetSoftwareValueAsByte(cc)); - break; - default: - return; - } - }; - - control.SoftwareControlValueChanged += cc => - { - if (cc.ControlMode == ControlMode.Software) - superIO.SetControl(index, GetSoftwareValueAsByte(cc)); - }; - - switch (control.ControlMode) + switch (cc.ControlMode) { case ControlMode.Undefined: - break; + return; case ControlMode.Default: superIO.SetControl(index, null); break; case ControlMode.Software: - superIO.SetControl(index, GetSoftwareValueAsByte(control)); + superIO.SetControl(index, GetSoftwareValueAsByte(cc)); break; - } - - sensor.Control = control; - _controls.Add(sensor); - ActivateSensor(sensor); - } - } - } - - private static byte GetSoftwareValueAsByte(Control control) - { - const float percentToByteRatio = 2.55f; - float value = control.SoftwareValue * percentToByteRatio; - return (byte)value; - } - - private void CreateFanSensors(ISuperIO superIO, ISettings settings, IList f) - { - foreach (Fan fan in f) - { - if (fan.Index < superIO.Fans.Length) - { - Sensor sensor = new(fan.Name, fan.Index, SensorType.Fan, this, settings); - _fans.Add(sensor); - } - } - } - - private void CreateTemperatureSensors(ISuperIO superIO, ISettings settings, IList t) - { - foreach (Temperature temperature in t) - { - if (temperature.Index < superIO.Temperatures.Length) - { - Sensor sensor = new(temperature.Name, - temperature.Index, - SensorType.Temperature, - this, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset.", 0) }, - settings); - - _temperatures.Add(sensor); - } - } - } - - private void CreateVoltageSensors(ISuperIO superIO, ISettings settings, IList v) - { - const string formula = "Voltage = value + (value - Vf) * Ri / Rf."; - foreach (Voltage voltage in v) - { - if (voltage.Index < superIO.Voltages.Length) - { - Sensor sensor = new(voltage.Name, - voltage.Index, - voltage.Hidden, - SensorType.Voltage, - this, - new[] - { - new ParameterDescription("Ri [kΩ]", "Input resistance.\n" + formula, voltage.Ri), - new ParameterDescription("Rf [kΩ]", "Reference resistance.\n" + formula, voltage.Rf), - new ParameterDescription("Vf [V]", "Reference voltage.\n" + formula, voltage.Vf) - }, - settings); - - _voltages.Add(sensor); - } - } - } - - private static void GetBoardSpecificConfiguration - ( - ISuperIO superIO, - Manufacturer manufacturer, - Model model, - out IList v, - out IList t, - out IList f, - out IList c, - out ReadValueDelegate readVoltage, - out ReadValueDelegate readTemperature, - out ReadValueDelegate readFan, - out ReadValueDelegate readControl, - out UpdateDelegate postUpdate, - out Mutex mutex) - { - readVoltage = index => superIO.Voltages[index]; - readTemperature = index => superIO.Temperatures[index]; - readFan = index => superIO.Fans[index]; - readControl = index => superIO.Controls[index]; - - postUpdate = () => { }; - mutex = null; - - v = new List(); - t = new List(); - f = new List(); - c = new List(); - - switch (superIO.Chip) - { - case Chip.IT8705F: - case Chip.IT8712F: - case Chip.IT8716F: - case Chip.IT8718F: - case Chip.IT8720F: - case Chip.IT8726F: - GetIteConfigurationsA(superIO, manufacturer, model, v, t, f, c, ref readFan, ref postUpdate, ref mutex); - break; - - case Chip.IT8613E: - case Chip.IT8620E: - case Chip.IT8628E: - case Chip.IT8631E: - case Chip.IT8655E: - case Chip.IT8665E: - case Chip.IT8686E: - case Chip.IT8688E: - case Chip.IT8689E: - case Chip.IT8721F: - case Chip.IT8728F: - case Chip.IT8771E: - case Chip.IT8772E: - GetIteConfigurationsB(superIO, manufacturer, model, v, t, f, c); - break; - - case Chip.IT8695E: - case Chip.IT879XE: - GetIteConfigurationsC(superIO, manufacturer, model, v, t, f, c); - break; - - case Chip.F71858: - v.Add(new Voltage("VCC3V", 0, 150, 150)); - v.Add(new Voltage("VSB3V", 1, 150, 150)); - v.Add(new Voltage("Battery", 2, 150, 150)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - break; - - case Chip.F71808E: - case Chip.F71862: - case Chip.F71869: - case Chip.F71869A: - case Chip.F71882: - case Chip.F71889AD: - case Chip.F71889ED: - case Chip.F71889F: - GetFintekConfiguration(superIO, manufacturer, model, v, t, f, c); - break; - - case Chip.W83627EHF: - GetWinbondConfigurationEhf(manufacturer, model, v, t, f, c); - break; - - case Chip.W83627DHG: - case Chip.W83627DHGP: - case Chip.W83667HG: - case Chip.W83667HGB: - GetWinbondConfigurationHg(manufacturer, model, v, t, f, c); - break; - - case Chip.W83627HF: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("AVCC", 3, 34, 51)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("+5VSB", 5, 34, 51)); - v.Add(new Voltage("VBat", 6)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("System Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Auxiliary Fan", 2)); - c.Add(new Ctrl("Fan 1", 0)); - c.Add(new Ctrl("Fan 2", 1)); - break; - - case Chip.W83627THF: - case Chip.W83687THF: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("AVCC", 3, 34, 51)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("+5VSB", 5, 34, 51)); - v.Add(new Voltage("VBat", 6)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("System Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Auxiliary Fan", 2)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - break; - - case Chip.NCT6771F: - case Chip.NCT6776F: - GetNuvotonConfigurationF(superIO, manufacturer, model, v, t, f, c); - break; - - case Chip.NCT610XD: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #0", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #1", 4, true)); - v.Add(new Voltage("Voltage #2", 5, true)); - v.Add(new Voltage("Reserved", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("Voltage #10", 9, true)); - t.Add(new Temperature("System", 1)); - t.Add(new Temperature("CPU Core", 2)); - t.Add(new Temperature("Auxiliary", 3)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Chip.NCT6779D: - case Chip.NCT6791D: - case Chip.NCT6792D: - case Chip.NCT6792DA: - case Chip.NCT6793D: - case Chip.NCT6795D: - case Chip.NCT6796D: - case Chip.NCT6796DR: - case Chip.NCT6797D: - case Chip.NCT6798D: - case Chip.NCT6683D: - GetNuvotonConfigurationD(superIO, manufacturer, model, v, t, f, c); - break; - - case Chip.NCT6687D: - v.Add(new Voltage("+12V", 0)); - v.Add(new Voltage("+5V", 1)); - v.Add(new Voltage("Vcore", 2)); - v.Add(new Voltage("Voltage #1", 3)); - v.Add(new Voltage("DIMM", 4)); - v.Add(new Voltage("CPU I/O", 5)); - v.Add(new Voltage("CPU SA", 6)); - v.Add(new Voltage("Voltage #2", 7)); - v.Add(new Voltage("AVCC3", 8)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("VRef", 10)); - v.Add(new Voltage("VSB", 11)); - v.Add(new Voltage("AVSB", 12)); - v.Add(new Voltage("VBat", 13)); - - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("System", 1)); - t.Add(new Temperature("VRM MOS", 2)); - t.Add(new Temperature("PCH", 3)); - t.Add(new Temperature("CPU Socket", 4)); - t.Add(new Temperature("PCIe x1", 5)); - t.Add(new Temperature("M2_1", 6)); - - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Pump Fan", 1)); - f.Add(new Fan("System Fan #1", 2)); - f.Add(new Fan("System Fan #2", 3)); - f.Add(new Fan("System Fan #3", 4)); - f.Add(new Fan("System Fan #4", 5)); - f.Add(new Fan("System Fan #5", 6)); - f.Add(new Fan("System Fan #6", 7)); - - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("Pump Fan", 1)); - c.Add(new Ctrl("System Fan #1", 2)); - c.Add(new Ctrl("System Fan #2", 3)); - c.Add(new Ctrl("System Fan #3", 4)); - c.Add(new Ctrl("System Fan #4", 5)); - c.Add(new Ctrl("System Fan #5", 6)); - c.Add(new Ctrl("System Fan #6", 7)); - - break; - - default: - GetDefaultConfiguration(superIO, v, t, f, c); - break; - } - } - - private static void GetDefaultConfiguration(ISuperIO superIO, ICollection v, ICollection t, ICollection f, ICollection c) - { - for (int i = 0; i < superIO.Voltages.Length; i++) - v.Add(new Voltage("Voltage #" + (i + 1), i, true)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - } - - private static void GetIteConfigurationsA - ( - ISuperIO superIO, - Manufacturer manufacturer, - Model model, - IList v, - IList t, - IList f, - ICollection c, - ref ReadValueDelegate readFan, - ref UpdateDelegate postUpdate, - ref Mutex mutex) - { - switch (manufacturer) - { - case Manufacturer.ASUS: - switch (model) - { - case Model.CROSSHAIR_III_FORMULA: // IT8720F - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("CPU", 0)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - break; - - case Model.M2N_SLI_Deluxe: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 4, 30, 10)); - v.Add(new Voltage("+5VSB", 7, 6.8f, 10)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Chassis Fan #1", 1)); - f.Add(new Fan("Power Fan", 2)); - - break; - - case Model.M4A79XTD_EVO: // IT8720F - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Chassis Fan #1", 1)); - f.Add(new Fan("Chassis Fan #2", 2)); - - break; - - case Model.PRIME_X370_PRO: // IT8665E - case Model.TUF_X470_PLUS_GAMING: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("SB 2.5V", 1)); - v.Add(new Voltage("+12V", 2, 5, 1)); - v.Add(new Voltage("+5V", 3, 1.5f, 1)); - v.Add(new Voltage("Voltage #4", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("+3.3V", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - v.Add(new Voltage("Voltage #10", 9, true)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 1)); - t.Add(new Temperature("PCH", 2)); - - for (int i = 3; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - f.Add(new Fan("CPU Fan", 0)); - - for (int i = 1; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - break; - - case Model.ROG_ZENITH_EXTREME: // IT8665E - v.Add(new Voltage("Vcore", 0, 10, 10)); - v.Add(new Voltage("DIMM AB", 1, 10, 10)); - v.Add(new Voltage("+12V", 2, 5, 1)); - v.Add(new Voltage("+5V", 3, 1.5f, 1)); - v.Add(new Voltage("SB 1.05V", 4, 10, 10)); - v.Add(new Voltage("DIMM CD", 5, 10, 10)); - v.Add(new Voltage("1.8V PLL", 6, 10, 10)); - v.Add(new Voltage("+3.3V", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 1)); - t.Add(new Temperature("CPU Socket", 2)); - t.Add(new Temperature("Temperature #4", 3)); - t.Add(new Temperature("Temperature #5", 4)); - t.Add(new Temperature("VRM", 5)); - - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Chassis Fan #1", 1)); - f.Add(new Fan("Chassis Fan #2", 2)); - f.Add(new Fan("High Amp Fan", 3)); - f.Add(new Fan("Fan 5", 4)); - f.Add(new Fan("Fan 6", 5)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("Voltage #8", 7, true)); - v.Add(new Voltage("VBat", 8)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; + return; } - - break; - case Manufacturer.ASRock: - switch (model) - { - case Model.P55_Deluxe: // IT8720F - GetASRockConfiguration(superIO, - v, - t, - f, - ref readFan, - ref postUpdate, - out mutex); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("Voltage #8", 7, true)); - v.Add(new Voltage("VBat", 8)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.DFI: - switch (model) - { - case Model.LP_BI_P45_T2RS_Elite: // IT8718F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("VTT", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 4, 30, 10)); - v.Add(new Voltage("NB Core", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("+5VSB", 7, 6.8f, 10)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("System", 1)); - t.Add(new Temperature("Chipset", 2)); - f.Add(new Fan("Fan #1", 0)); - f.Add(new Fan("Fan #2", 1)); - f.Add(new Fan("Fan #3", 2)); - - break; - - case Model.LP_DK_P55_T3EH9: // IT8720F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("VTT", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 4, 30, 10)); - v.Add(new Voltage("CPU PLL", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("+5VSB", 7, 6.8f, 10)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("Chipset", 0)); - t.Add(new Temperature("CPU PWM", 1)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("Fan #1", 0)); - f.Add(new Fan("Fan #2", 1)); - f.Add(new Fan("Fan #3", 2)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("VTT", 1, true)); - v.Add(new Voltage("+3.3V", 2, true)); - v.Add(new Voltage("+5V", 3, 6.8f, 10, 0, true)); - v.Add(new Voltage("+12V", 4, 30, 10, 0, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("DIMM", 6, true)); - v.Add(new Voltage("+5VSB", 7, 6.8f, 10, 0, true)); - v.Add(new Voltage("VBat", 8)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.Gigabyte: - switch (model) - { - case Model._965P_S3: // IT8718F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - - break; - - case Model.EP45_DS3R: // IT8718F - case Model.EP45_UD3R: - case Model.X38_DS5: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #2", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("System Fan #1", 3)); - - break; - - case Model.EX58_EXTREME: // IT8720F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Northbridge", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #2", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("System Fan #1", 3)); - - break; - - case Model.P35_DS3: // IT8718F - case Model.P35_DS3L: // IT8718F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("Power Fan", 3)); - - break; - - case Model.P55_UD4: // IT8720F - case Model.P55A_UD3: // IT8720F - case Model.P55M_UD4: // IT8720F - case Model.H55_USB3: // IT8720F - case Model.EX58_UD3R: // IT8720F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 5, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #2", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("System Fan #1", 3)); - - break; - - case Model.H55N_USB3: // IT8720F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 5, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - - break; - - case Model.G41M_COMBO: // IT8718F - case Model.G41MT_S2: // IT8718F - case Model.G41MT_S2P: // IT8718F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - - break; - - case Model._970A_UD3: // IT8720F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("Power Fan", 4)); - c.Add(new Ctrl("PWM #1", 0)); - c.Add(new Ctrl("PWM #2", 1)); - c.Add(new Ctrl("PWM #3", 2)); - - break; - - case Model.MA770T_UD3: // IT8720F - case Model.MA770T_UD3P: // IT8720F - case Model.MA790X_UD3P: // IT8720F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("Power Fan", 3)); - - break; - - case Model.MA78LM_S2H: // IT8718F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("VRM", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("Power Fan", 3)); - - break; - - case Model.MA785GM_US2H: // IT8718F - case Model.MA785GMT_UD2H: // IT8718F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - f.Add(new Fan("NB Fan", 2)); - - break; - - case Model.X58A_UD3R: // IT8720F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+5V", 3, 6.8f, 10)); - v.Add(new Voltage("+12V", 5, 24.3f, 8.2f)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Northbridge", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #2", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("System Fan #1", 3)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1, true)); - v.Add(new Voltage("+3.3V", 2, true)); - v.Add(new Voltage("+5V", 3, 6.8f, 10, 0, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("Voltage #8", 7, true)); - v.Add(new Voltage("VBat", 8)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("Voltage #8", 7, true)); - v.Add(new Voltage("VBat", 8)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - } - - private static void GetASRockConfiguration - ( - ISuperIO superIO, - IList v, - IList t, - IList f, - ref ReadValueDelegate readFan, - ref UpdateDelegate postUpdate, - out Mutex mutex) - { - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 2)); - v.Add(new Voltage("+12V", 4, 30, 10)); - v.Add(new Voltage("+5V", 5, 6.8f, 10)); - v.Add(new Voltage("VBat", 8)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 1)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Chassis Fan #1", 1)); - - // this mutex is also used by the official ASRock tool - mutex = new Mutex(false, "ASRockOCMark"); - - bool exclusiveAccess = false; - try - { - exclusiveAccess = mutex.WaitOne(10, false); - } - catch (AbandonedMutexException) - { } - catch (InvalidOperationException) - { } - - // only read additional fans if we get exclusive access - if (exclusiveAccess) - { - f.Add(new Fan("Chassis Fan #2", 2)); - f.Add(new Fan("Chassis Fan #3", 3)); - f.Add(new Fan("Power Fan", 4)); - - readFan = index => - { - if (index < 2) - { - return superIO.Fans[index]; - } - - // get GPIO 80-87 - byte? gpio = superIO.ReadGpio(7); - if (!gpio.HasValue) - return null; - - // read the last 3 fans based on GPIO 83-85 - int[] masks = { 0x05, 0x03, 0x06 }; - return ((gpio.Value >> 3) & 0x07) == masks[index - 2] ? superIO.Fans[2] : null; }; - int fanIndex = 0; - - postUpdate = () => + control.SoftwareControlValueChanged += cc => { - // get GPIO 80-87 - byte? gpio = superIO.ReadGpio(7); - if (!gpio.HasValue) - return; - - // prepare the GPIO 83-85 for the next update - int[] masks = { 0x05, 0x03, 0x06 }; - superIO.WriteGpio(7, (byte)((gpio.Value & 0xC7) | (masks[fanIndex] << 3))); - fanIndex = (fanIndex + 1) % 3; + if (cc.ControlMode == ControlMode.Software) + superIO.SetControl(index, GetSoftwareValueAsByte(cc)); }; + + switch (control.ControlMode) + { + case ControlMode.Undefined: + break; + case ControlMode.Default: + superIO.SetControl(index, null); + break; + case ControlMode.Software: + superIO.SetControl(index, GetSoftwareValueAsByte(control)); + break; + } + + sensor.Control = control; + _controls.Add(sensor); + ActivateSensor(sensor); } } + } - private static void GetIteConfigurationsB(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + private static byte GetSoftwareValueAsByte(Control control) + { + const float percentToByteRatio = 2.55f; + float value = control.SoftwareValue * percentToByteRatio; + return (byte)value; + } + + private void CreateFanSensors(ISuperIO superIO, ISettings settings, IList f) + { + foreach (Fan fan in f) { - switch (manufacturer) + if (fan.Index < superIO.Fans.Length) { - case Manufacturer.ASUS: - switch (model) - { - case Model.ROG_STRIX_X470_I: // IT8665E - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("SB 2.5V", 1)); - v.Add(new Voltage("+12V", 2, 5, 1)); - v.Add(new Voltage("+5V", 3, 1.5f, 1)); - v.Add(new Voltage("+3.3V", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 1)); - t.Add(new Temperature("T_Sensor", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM", 4)); - t.Add(new Temperature("Temperature #6", 5)); - - f.Add(new Fan("CPU Fan", 0)); - - //Does not work when in AIO pump mode (shows 0). I don't know how to fix it. - f.Add(new Fan("Chassis Fan #1", 1)); - f.Add(new Fan("Chassis Fan #2", 2)); - - //offset: 2, because the first two always show zero - for (int i = 2; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i - 1), i)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("Voltage #8", 7, true)); - v.Add(new Voltage("VBat", 8)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.ECS: - switch (model) - { - case Model.A890GXM_A: // IT8721F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("NB Voltage", 2)); - v.Add(new Voltage("AVCC", 3, 10, 10)); - // v.Add(new Voltage("DIMM", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("System", 1)); - t.Add(new Temperature("Northbridge", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - f.Add(new Fan("Power Fan", 2)); - - break; - - default: - v.Add(new Voltage("Voltage #1", 0, true)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("AVCC", 3, 10, 10, 0, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); - v.Add(new Voltage("VBat", 8, 10, 10)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.Gigabyte: - switch (model) - { - case Model.H61M_DS2_REV_1_2: // IT8728F - case Model.H61M_USB3_B3_REV_2_0: // IT8728F - v.Add(new Voltage("VTT", 0)); - v.Add(new Voltage("+12V", 2, 30.9f, 10)); - v.Add(new Voltage("Vcore", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - - break; - - case Model.H67A_UD3H_B3: // IT8728F - case Model.H67A_USB3_B3: // IT8728F - v.Add(new Voltage("VTT", 0)); - v.Add(new Voltage("+5V", 1, 15, 10)); - v.Add(new Voltage("+12V", 2, 30.9f, 10)); - v.Add(new Voltage("Vcore", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("System Fan #2", 3)); - - break; - - case Model.H81M_HD3: //IT8620E - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("iGPU", 4)); - v.Add(new Voltage("CPU VRIN", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("System", 0)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan", 1)); - - break; - - case Model.Z170N_WIFI: // ITE IT8628E - v.Add(new Voltage("Vcore", 0, 0, 1)); - v.Add(new Voltage("+3.3V", 1, 6.5F, 10)); - v.Add(new Voltage("+12V", 2, 5, 1)); - v.Add(new Voltage("+5V", 3, 1.5F, 1)); - // NO DIMM CD channels on this motherboard; gives a very tiny voltage reading - // v.Add(new Voltage("DIMM CD", 4, 0, 1)); - v.Add(new Voltage("iGPU VAXG", 5, 0, 1)); - v.Add(new Voltage("DIMM AB", 6, 0, 1)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - v.Add(new Voltage("AVCC3", 9, 54, 10)); - - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("PCH", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM", 4)); - t.Add(new Temperature("System #2", 5)); - - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan", 1)); - - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan", 1)); - - break; - - case Model.AX370_Gaming_K7: // IT8686E - case Model.AX370_Gaming_5: - case Model.AB350_Gaming_3: // IT8686E - // Note: v3.3, v12, v5, and AVCC3 might be slightly off. - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 0.65f, 1)); - v.Add(new Voltage("+12V", 2, 5, 1)); - v.Add(new Voltage("+5V", 3, 1.5f, 1)); - v.Add(new Voltage("VSOC", 4)); - v.Add(new Voltage("VDDP", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - v.Add(new Voltage("AVCC3", 9, 7.53f, 1)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("Chipset", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - break; - - case Model.X399_AORUS_Gaming_7: // ITE IT8686E - v.Add(new Voltage("Vcore", 0, 0, 1)); - v.Add(new Voltage("+3.3V", 1, 6.5F, 10)); - v.Add(new Voltage("+12V", 2, 5, 1)); - v.Add(new Voltage("+5V", 3, 1.5F, 1)); - v.Add(new Voltage("DIMM CD", 4, 0, 1)); - v.Add(new Voltage("Vcore SoC", 5, 0, 1)); - v.Add(new Voltage("DIMM AB", 6, 0, 1)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - v.Add(new Voltage("AVCC3", 9, 54, 10)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("Chipset", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM", 4)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.X470_AORUS_GAMING_7_WIFI: // ITE IT8686E - v.Add(new Voltage("Vcore", 0, 0, 1)); - v.Add(new Voltage("+3.3V", 1, 6.5F, 10)); - v.Add(new Voltage("+12V", 2, 5, 1)); - v.Add(new Voltage("+5V", 3, 1.5F, 1)); - v.Add(new Voltage("Vcore SoC", 4, 0, 1)); - v.Add(new Voltage("VDDP", 5, 0, 1)); - v.Add(new Voltage("DIMM AB", 6, 0, 1)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - v.Add(new Voltage("AVCC3", 9, 54, 10)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("Chipset", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM", 4)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.B560M_AORUS_ELITE: // IT8689E - case Model.B560M_AORUS_PRO: - case Model.B560M_AORUS_PRO_AX: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); - v.Add(new Voltage("+12V", 2, 10f, 2f)); - v.Add(new Voltage("+5V", 3, 15f, 10f)); - v.Add(new Voltage("iGPU VAGX", 4)); - v.Add(new Voltage("VCCSA", 5)); - v.Add(new Voltage("DRAM", 6)); - v.Add(new Voltage("3VSB", 7, 10f, 10f)); - v.Add(new Voltage("VBat", 8, 10f, 10f)); - v.Add(new Voltage("AVCC3", 9, 59.9f, 9.8f)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("PCH", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("System #2", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("System Fan #3", 3)); - f.Add(new Fan("CPU Optional Fan", 4)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("System Fan #3", 3)); - c.Add(new Ctrl("CPU Optional Fan", 4)); - - break; - - case Model.B360_AORUS_GAMING_3_WIFI_CF: // IT8688E - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); - v.Add(new Voltage("+12V", 2, 10f, 2f)); - v.Add(new Voltage("+5V", 3, 15f, 10f)); - v.Add(new Voltage("CPU Vcore", 4, 0, 1)); - v.Add(new Voltage("CPU VCCSA", 5, 0, 1)); - v.Add(new Voltage("DIMM AB", 6, 0, 1)); - v.Add(new Voltage("3VSB", 7, 1, 1)); - v.Add(new Voltage("VBat", 8, 1, 1)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("EC_TEMP1", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("PCH", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("PCH Fan", 3)); - f.Add(new Fan("CPU Optional Fan", 4)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("PCH Fan", 3)); - c.Add(new Ctrl("CPU Optional Fan", 4)); - - break; - - case Model.X570_AORUS_MASTER: // IT8688E - case Model.X570_AORUS_ULTRA: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); - v.Add(new Voltage("+12V", 2, 10f, 2f)); - v.Add(new Voltage("+5V", 3, 15f, 10f)); - v.Add(new Voltage("Vcore SoC", 4)); - v.Add(new Voltage("VDDP", 5)); - v.Add(new Voltage("DIMM AB", 6)); - v.Add(new Voltage("3VSB", 7, 1f, 10f)); - v.Add(new Voltage("VBat", 8, 1f, 10f)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("EC_TEMP1", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("PCH", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("PCH Fan", 3)); - f.Add(new Fan("CPU Optional Fan", 4)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("PCH Fan", 3)); - c.Add(new Ctrl("CPU Optional Fan", 4)); - - break; - - case Model.X570_GAMING_X: // IT8688E - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); - v.Add(new Voltage("+12V", 2, 10f, 2f)); - v.Add(new Voltage("+5V", 3, 15f, 10f)); - v.Add(new Voltage("Vcore SoC", 4)); - v.Add(new Voltage("VDDP", 5)); - v.Add(new Voltage("DIMM AB", 6)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("System #2", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("PCH", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("PCH Fan", 3)); - f.Add(new Fan("CPU Optional Fan", 4)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("PCH Fan", 3)); - c.Add(new Ctrl("CPU Optional Fan", 4)); - - break; - - case Model.Z390_M_GAMING: // IT8688E - case Model.Z390_AORUS_ULTRA: - case Model.Z390_UD: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); - v.Add(new Voltage("+12V", 2, 5f, 1)); - v.Add(new Voltage("+5V", 3, 1.5f, 1)); - v.Add(new Voltage("CPU VCCGT", 4)); - v.Add(new Voltage("CPU VCCSA", 5)); - v.Add(new Voltage("VDDQ", 6)); - v.Add(new Voltage("DDRVTT", 7)); - v.Add(new Voltage("PCHCore", 8)); - v.Add(new Voltage("CPU VCCIO", 9)); - v.Add(new Voltage("DDRVPP", 10)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("PCH", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("System #2", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("System Fan #3", 3)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("System Fan #3", 3)); - - break; - - case Model.Z390_AORUS_PRO: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); - v.Add(new Voltage("+12V", 2, 5f, 1)); - v.Add(new Voltage("+5V", 3, 1.5f, 1)); - v.Add(new Voltage("CPU VCCGT", 4)); - v.Add(new Voltage("CPU VCCSA", 5)); - v.Add(new Voltage("DDR", 6)); - v.Add(new Voltage("Voltage #7", 7, true)); - v.Add(new Voltage("3VSB", 8, 1f, 1f, -0.312f)); - v.Add(new Voltage("VBat", 9, 6f, 1f, 0.01f)); - v.Add(new Voltage("AVCC3", 10, 6f, 1f, 0.048f)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("PCH", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("EC_TEMP1/System #2", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("System Fan #3", 3)); - f.Add(new Fan("CPU Optional Fan", 4)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("System Fan #3", 3)); - c.Add(new Ctrl("CPU Optional Fan", 4)); - - break; - - case Model.Z690_AORUS_PRO: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); - v.Add(new Voltage("+12V", 2, 5f, 1)); - v.Add(new Voltage("+5V", 3, 1.5f, 1)); - v.Add(new Voltage("iGPU VAXG", 4)); - v.Add(new Voltage("CPU VCCIN_AUX", 5)); - v.Add(new Voltage("Voltage #6", 6, true)); - v.Add(new Voltage("3VSB", 7, 1f, 1f)); - v.Add(new Voltage("VBat", 8, 1f, 1f)); - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("PCH", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("EC_TEMP1", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("System Fan #3", 3)); - f.Add(new Fan("CPU Optional Fan", 4)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("System Fan #3", 3)); - c.Add(new Ctrl("CPU Optional Fan", 4)); - break; - - case Model.Z690_GAMING_X_DDR4: - t.Add(new Temperature("System #1", 0)); - t.Add(new Temperature("PCH", 1)); - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("PCIe x16", 3)); - t.Add(new Temperature("VRM MOS", 4)); - t.Add(new Temperature("System #2", 5)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("System Fan #3", 3)); - f.Add(new Fan("CPU Optional Fan", 4)); - f.Add(new Fan("System Fan #4 / Pump", 5)); - c.Add(new Ctrl("CPU Fan", 0)); - c.Add(new Ctrl("System Fan #1", 1)); - c.Add(new Ctrl("System Fan #2", 2)); - c.Add(new Ctrl("System Fan #3", 3)); - c.Add(new Ctrl("CPU Optional Fan", 4)); - c.Add(new Ctrl("System Fan #4 / Pump", 5)); - break; - - case Model.Z68A_D3H_B3: // IT8728F - v.Add(new Voltage("VTT", 0)); - v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); - v.Add(new Voltage("+12V", 2, 30.9f, 10)); - v.Add(new Voltage("+5V", 3, 7.15f, 10)); - v.Add(new Voltage("Vcore", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("System Fan #2", 3)); - - break; - - case Model.P67A_UD3_B3: // IT8728F - case Model.P67A_UD3R_B3: // IT8728F - case Model.P67A_UD4_B3: // IT8728F - case Model.Z68AP_D3: // IT8728F - case Model.Z68X_UD3H_B3: // IT8728F - case Model.Z68XP_UD3R: // IT8728F - v.Add(new Voltage("VTT", 0)); - v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); - v.Add(new Voltage("+12V", 2, 30.9f, 10)); - v.Add(new Voltage("+5V", 3, 7.15f, 10)); - v.Add(new Voltage("Vcore", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #2", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("System Fan #1", 3)); - - break; - - case Model.Z68X_UD7_B3: // IT8728F - v.Add(new Voltage("VTT", 0)); - v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); - v.Add(new Voltage("+12V", 2, 30.9f, 10)); - v.Add(new Voltage("+5V", 3, 7.15f, 10)); - v.Add(new Voltage("Vcore", 5)); - v.Add(new Voltage("DIMM", 6)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("System #3", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Power Fan", 1)); - f.Add(new Fan("System Fan #1", 2)); - f.Add(new Fan("System Fan #2", 3)); - f.Add(new Fan("System Fan #3", 4)); - - break; - - case Model.X79_UD3: // IT8728F - v.Add(new Voltage("VTT", 0)); - v.Add(new Voltage("DIMM AB", 1)); - v.Add(new Voltage("+12V", 2, 10, 2)); - v.Add(new Voltage("+5V", 3, 15, 10)); - v.Add(new Voltage("VIN4", 4)); - v.Add(new Voltage("VCore", 5)); - v.Add(new Voltage("DIMM CD", 6)); - v.Add(new Voltage("+3V Standby", 7, 1, 1)); - v.Add(new Voltage("VBat", 8, 1, 1)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Northbridge", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("System Fan #1", 1)); - f.Add(new Fan("System Fan #2", 2)); - f.Add(new Fan("System Fan #3", 3)); - - break; - - default: - v.Add(new Voltage("Voltage #1", 0, true)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); - v.Add(new Voltage("VBat", 8, 10, 10)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.Biostar: - switch (model) - { - case Model.B660GTN: //IT8613E - // This board has some problems with their app controlling fans that I was able to replicate here so I guess is a BIOS problem with the pins. - // Biostar is aware so expect changes in the control pins with new bios. - // In the meantime, it's possible to control CPUFAN and CPUOPT1m but not SYSFAN1. - // The parameters are extracted from the Biostar app config file. - v.Add(new Voltage("Vcore", 0, 0, 1)); - v.Add(new Voltage("DIMM", 1, 0, 1)); - v.Add(new Voltage("+12V", 2, 5, 1)); // Reads higher than it should. - v.Add(new Voltage("+5V", 3, 147, 100)); // Reads higher than it should. - // Commented because I don't know if it makes sense. - //v.Add(new Voltage("VCC ST", 4)); // Reads 4.2V. - //v.Add(new Voltage("VCCIN AUX", 5)); // Reads 2.2V. - //v.Add(new Voltage("CPU GT", 6)); // Reads 2.6V. - //v.Add(new Voltage("3VSB", 7, 10, 10)); // Reads 5.8V ? - v.Add(new Voltage("VBat", 8, 10, 10)); // Reads higher than it should at 3.4V. - t.Add(new Temperature("System 1", 0)); - t.Add(new Temperature("System 2", 1)); // Not sure what sensor is this. - t.Add(new Temperature("CPU", 2)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("CPU Optional fan", 2)); - f.Add(new Fan("System Fan", 4)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("CPU Optional Fan", 2)); - c.Add(new Ctrl("System Fan", 4)); - - break; - - default: - v.Add(new Voltage("Voltage #1", 0, true)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); - v.Add(new Voltage("VBat", 8, 10, 10)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.Shuttle: - switch (model) - { - case Model.FH67: // IT8772E - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("DIMM", 1)); - v.Add(new Voltage("PCH VCCIO", 2)); - v.Add(new Voltage("CPU VCCIO", 3)); - v.Add(new Voltage("Graphic Voltage", 4)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("System", 0)); - t.Add(new Temperature("CPU", 1)); - f.Add(new Fan("Fan #1", 0)); - f.Add(new Fan("CPU Fan", 1)); - - break; - - default: - v.Add(new Voltage("Voltage #1", 0, true)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); - v.Add(new Voltage("VBat", 8, 10, 10)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - - default: - v.Add(new Voltage("Voltage #1", 0, true)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); - v.Add(new Voltage("VBat", 8, 10, 10)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; + Sensor sensor = new(fan.Name, fan.Index, SensorType.Fan, this, settings); + _fans.Add(sensor); } } + } - private static void GetIteConfigurationsC(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + private void CreateTemperatureSensors(ISuperIO superIO, ISettings settings, IList t) + { + foreach (Temperature temperature in t) { - switch (manufacturer) + if (temperature.Index < superIO.Temperatures.Length) { - case Manufacturer.Gigabyte: - switch (model) - { - case Model.X570_AORUS_MASTER: // IT879XE - case Model.X570_AORUS_ULTRA: - v.Add(new Voltage("CPU VDD18", 0)); - v.Add(new Voltage("DDRVTT AB", 1)); - v.Add(new Voltage("Chipset Core", 2)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("CPU VDD18", 4)); - v.Add(new Voltage("PM_CLDO12", 5)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 1f, 1f)); - v.Add(new Voltage("VBat", 8, 1f, 1f)); - t.Add(new Temperature("PCIe x8", 0)); - t.Add(new Temperature("EC_TEMP2", 1)); - t.Add(new Temperature("System #2", 2)); - f.Add(new Fan("System Fan #5 Pump", 0)); - f.Add(new Fan("System Fan #6 Pump", 1)); - f.Add(new Fan("System Fan #4", 2)); + Sensor sensor = new(temperature.Name, + temperature.Index, + SensorType.Temperature, + this, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset.", 0) }, + settings); - break; - - case Model.X470_AORUS_GAMING_7_WIFI: // ITE IT8792 - v.Add(new Voltage("VIN0", 0, 0, 1)); - v.Add(new Voltage("DDR VTT", 1, 0, 1)); - v.Add(new Voltage("Chipset Core", 2, 0, 1)); - v.Add(new Voltage("VIN3", 3, 0, 1)); - v.Add(new Voltage("CPU VDD18", 4, 0, 1)); - v.Add(new Voltage("Chipset Core +2.5V", 5, 0.5F, 1)); - v.Add(new Voltage("3VSB", 6, 1, 10)); - v.Add(new Voltage("VBat", 7, 0.7F, 1)); - t.Add(new Temperature("PCIe x8", 0)); - t.Add(new Temperature("System #2", 2)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.Z390_AORUS_PRO: // IT879XE - v.Add(new Voltage("VCore", 0)); - v.Add(new Voltage("DDRVTT AB", 1)); - v.Add(new Voltage("Chipset Core", 2)); - v.Add(new Voltage("VIN3", 3, true)); - v.Add(new Voltage("VCCIO", 4)); - v.Add(new Voltage("Voltage #7", 5, true)); - v.Add(new Voltage("DDR VPP", 6)); - v.Add(new Voltage("3VSB", 7, 1f, 1f)); - v.Add(new Voltage("VBat", 8, 1f, 1f)); - t.Add(new Temperature("PCIe x8", 0)); - t.Add(new Temperature("EC_TEMP2", 1)); - t.Add(new Temperature("System #2", 2)); - f.Add(new Fan("System Fan #5 Pump", 0)); - f.Add(new Fan("System Fan #6 Pump", 1)); - f.Add(new Fan("System Fan #4", 2)); - c.Add(new Ctrl("Fan #5", 0)); - c.Add(new Ctrl("Fan #6", 1)); - c.Add(new Ctrl("Fan #4", 2)); - - break; - - case Model.Z690_AORUS_PRO: - t.Add(new Temperature("PCIe x4", 0)); - t.Add(new Temperature("EC_TEMP2", 1)); - t.Add(new Temperature("System #2", 2)); - f.Add(new Fan("System Fan #5 Pump", 0)); - f.Add(new Fan("System Fan #6 Pump", 1)); - f.Add(new Fan("System Fan #4", 2)); - c.Add(new Ctrl("System Fan #5 Pump", 0)); - c.Add(new Ctrl("System Fan #6 Pump", 1)); - c.Add(new Ctrl("System Fan #4", 2)); - break; - - default: - v.Add(new Voltage("Voltage #1", 0, true)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); - v.Add(new Voltage("VBat", 8, 10, 10)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - - default: - v.Add(new Voltage("Voltage #1", 0, true)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); - v.Add(new Voltage("VBat", 8, 10, 10)); - - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; + _temperatures.Add(sensor); } } + } - private static void GetFintekConfiguration(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + private void CreateVoltageSensors(ISuperIO superIO, ISettings settings, IList v) + { + const string formula = "Voltage = value + (value - Vf) * Ri / Rf."; + foreach (Voltage voltage in v) { - switch (manufacturer) + if (voltage.Index < superIO.Voltages.Length) { - case Manufacturer.EVGA: - switch (model) - { - case Model.X58_SLI_Classified: // F71882 - v.Add(new Voltage("VCC3V", 0, 150, 150)); - v.Add(new Voltage("Vcore", 1, 47, 100)); - v.Add(new Voltage("DIMM", 2, 47, 100)); - v.Add(new Voltage("CPU VTT", 3, 24, 100)); - v.Add(new Voltage("IOH Vcore", 4, 24, 100)); - v.Add(new Voltage("+5V", 5, 51, 12)); - v.Add(new Voltage("+12V", 6, 56, 6.8f)); - v.Add(new Voltage("3VSB", 7, 150, 150)); - v.Add(new Voltage("VBat", 8, 150, 150)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("VREG", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Power Fan", 1)); - f.Add(new Fan("Chassis Fan", 2)); + Sensor sensor = new(voltage.Name, + voltage.Index, + voltage.Hidden, + SensorType.Voltage, + this, + new[] + { + new ParameterDescription("Ri [kΩ]", "Input resistance.\n" + formula, voltage.Ri), + new ParameterDescription("Rf [kΩ]", "Reference resistance.\n" + formula, voltage.Rf), + new ParameterDescription("Vf [V]", "Reference voltage.\n" + formula, voltage.Vf) + }, + settings); - break; + _voltages.Add(sensor); + } + } + } - default: - v.Add(new Voltage("VCC3V", 0, 150, 150)); - v.Add(new Voltage("Vcore", 1)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("VSB3V", 7, 150, 150)); - v.Add(new Voltage("VBat", 8, 150, 150)); + private static void GetBoardSpecificConfiguration + ( + ISuperIO superIO, + Manufacturer manufacturer, + Model model, + out IList v, + out IList t, + out IList f, + out IList c, + out ReadValueDelegate readVoltage, + out ReadValueDelegate readTemperature, + out ReadValueDelegate readFan, + out ReadValueDelegate readControl, + out UpdateDelegate postUpdate, + out Mutex mutex) + { + readVoltage = index => superIO.Voltages[index]; + readTemperature = index => superIO.Temperatures[index]; + readFan = index => superIO.Fans[index]; + readControl = index => superIO.Controls[index]; - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); + postUpdate = () => { }; + mutex = null; - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); + v = new List(); + t = new List(); + f = new List(); + c = new List(); - break; - } + switch (superIO.Chip) + { + case Chip.IT8705F: + case Chip.IT8712F: + case Chip.IT8716F: + case Chip.IT8718F: + case Chip.IT8720F: + case Chip.IT8726F: + GetIteConfigurationsA(superIO, manufacturer, model, v, t, f, c, ref readFan, ref postUpdate, ref mutex); + break; - break; + case Chip.IT8613E: + case Chip.IT8620E: + case Chip.IT8628E: + case Chip.IT8631E: + case Chip.IT8655E: + case Chip.IT8665E: + case Chip.IT8686E: + case Chip.IT8688E: + case Chip.IT8689E: + case Chip.IT8721F: + case Chip.IT8728F: + case Chip.IT8771E: + case Chip.IT8772E: + GetIteConfigurationsB(superIO, manufacturer, model, v, t, f, c); + break; - default: - v.Add(new Voltage("VCC3V", 0, 150, 150)); - v.Add(new Voltage("Vcore", 1)); - v.Add(new Voltage("Voltage #3", 2, true)); - v.Add(new Voltage("Voltage #4", 3, true)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - if (superIO.Chip != Chip.F71808E) + case Chip.IT8695E: + case Chip.IT879XE: + GetIteConfigurationsC(superIO, manufacturer, model, v, t, f, c); + break; + + case Chip.F71858: + v.Add(new Voltage("VCC3V", 0, 150, 150)); + v.Add(new Voltage("VSB3V", 1, 150, 150)); + v.Add(new Voltage("Battery", 2, 150, 150)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + break; + + case Chip.F71808E: + case Chip.F71862: + case Chip.F71869: + case Chip.F71869A: + case Chip.F71882: + case Chip.F71889AD: + case Chip.F71889ED: + case Chip.F71889F: + GetFintekConfiguration(superIO, manufacturer, model, v, t, f, c); + break; + + case Chip.W83627EHF: + GetWinbondConfigurationEhf(manufacturer, model, v, t, f, c); + break; + + case Chip.W83627DHG: + case Chip.W83627DHGP: + case Chip.W83667HG: + case Chip.W83667HGB: + GetWinbondConfigurationHg(manufacturer, model, v, t, f, c); + break; + + case Chip.W83627HF: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("AVCC", 3, 34, 51)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("+5VSB", 5, 34, 51)); + v.Add(new Voltage("VBat", 6)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("System Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Auxiliary Fan", 2)); + c.Add(new Ctrl("Fan 1", 0)); + c.Add(new Ctrl("Fan 2", 1)); + break; + + case Chip.W83627THF: + case Chip.W83687THF: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("AVCC", 3, 34, 51)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("+5VSB", 5, 34, 51)); + v.Add(new Voltage("VBat", 6)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("System Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Auxiliary Fan", 2)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + break; + + case Chip.NCT6771F: + case Chip.NCT6776F: + GetNuvotonConfigurationF(superIO, manufacturer, model, v, t, f, c); + break; + + case Chip.NCT610XD: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #0", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #1", 4, true)); + v.Add(new Voltage("Voltage #2", 5, true)); + v.Add(new Voltage("Reserved", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("Voltage #10", 9, true)); + t.Add(new Temperature("System", 1)); + t.Add(new Temperature("CPU Core", 2)); + t.Add(new Temperature("Auxiliary", 3)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Chip.NCT6779D: + case Chip.NCT6791D: + case Chip.NCT6792D: + case Chip.NCT6792DA: + case Chip.NCT6793D: + case Chip.NCT6795D: + case Chip.NCT6796D: + case Chip.NCT6796DR: + case Chip.NCT6797D: + case Chip.NCT6798D: + case Chip.NCT6683D: + GetNuvotonConfigurationD(superIO, manufacturer, model, v, t, f, c); + break; + + case Chip.NCT6687D: + v.Add(new Voltage("+12V", 0)); + v.Add(new Voltage("+5V", 1)); + v.Add(new Voltage("Vcore", 2)); + v.Add(new Voltage("Voltage #1", 3)); + v.Add(new Voltage("DIMM", 4)); + v.Add(new Voltage("CPU I/O", 5)); + v.Add(new Voltage("CPU SA", 6)); + v.Add(new Voltage("Voltage #2", 7)); + v.Add(new Voltage("AVCC3", 8)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("VRef", 10)); + v.Add(new Voltage("VSB", 11)); + v.Add(new Voltage("AVSB", 12)); + v.Add(new Voltage("VBat", 13)); + + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("System", 1)); + t.Add(new Temperature("VRM MOS", 2)); + t.Add(new Temperature("PCH", 3)); + t.Add(new Temperature("CPU Socket", 4)); + t.Add(new Temperature("PCIe x1", 5)); + t.Add(new Temperature("M2_1", 6)); + + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Pump Fan", 1)); + f.Add(new Fan("System Fan #1", 2)); + f.Add(new Fan("System Fan #2", 3)); + f.Add(new Fan("System Fan #3", 4)); + f.Add(new Fan("System Fan #4", 5)); + f.Add(new Fan("System Fan #5", 6)); + f.Add(new Fan("System Fan #6", 7)); + + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("Pump Fan", 1)); + c.Add(new Ctrl("System Fan #1", 2)); + c.Add(new Ctrl("System Fan #2", 3)); + c.Add(new Ctrl("System Fan #3", 4)); + c.Add(new Ctrl("System Fan #4", 5)); + c.Add(new Ctrl("System Fan #5", 6)); + c.Add(new Ctrl("System Fan #6", 7)); + + break; + + default: + GetDefaultConfiguration(superIO, v, t, f, c); + break; + } + } + + private static void GetDefaultConfiguration(ISuperIO superIO, ICollection v, ICollection t, ICollection f, ICollection c) + { + for (int i = 0; i < superIO.Voltages.Length; i++) + v.Add(new Voltage("Voltage #" + (i + 1), i, true)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + } + + private static void GetIteConfigurationsA + ( + ISuperIO superIO, + Manufacturer manufacturer, + Model model, + IList v, + IList t, + IList f, + ICollection c, + ref ReadValueDelegate readFan, + ref UpdateDelegate postUpdate, + ref Mutex mutex) + { + switch (manufacturer) + { + case Manufacturer.ASUS: + switch (model) + { + case Model.CROSSHAIR_III_FORMULA: // IT8720F + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("CPU", 0)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + break; + + case Model.M2N_SLI_Deluxe: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 4, 30, 10)); + v.Add(new Voltage("+5VSB", 7, 6.8f, 10)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Chassis Fan #1", 1)); + f.Add(new Fan("Power Fan", 2)); + + break; + + case Model.M4A79XTD_EVO: // IT8720F + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Chassis Fan #1", 1)); + f.Add(new Fan("Chassis Fan #2", 2)); + + break; + + case Model.PRIME_X370_PRO: // IT8665E + case Model.TUF_X470_PLUS_GAMING: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("SB 2.5V", 1)); + v.Add(new Voltage("+12V", 2, 5, 1)); + v.Add(new Voltage("+5V", 3, 1.5f, 1)); + v.Add(new Voltage("Voltage #4", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("+3.3V", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + v.Add(new Voltage("Voltage #10", 9, true)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 1)); + t.Add(new Temperature("PCH", 2)); - v.Add(new Voltage("VSB3V", 7, 150, 150)); - v.Add(new Voltage("VBat", 8, 150, 150)); + for (int i = 3; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); - for (int i = 0; i < superIO.Temperatures.Length; i++) - t.Add(new Temperature("Temperature #" + (i + 1), i)); + f.Add(new Fan("CPU Fan", 0)); - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); + for (int i = 1; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); + break; - break; - } + case Model.ROG_ZENITH_EXTREME: // IT8665E + v.Add(new Voltage("Vcore", 0, 10, 10)); + v.Add(new Voltage("DIMM AB", 1, 10, 10)); + v.Add(new Voltage("+12V", 2, 5, 1)); + v.Add(new Voltage("+5V", 3, 1.5f, 1)); + v.Add(new Voltage("SB 1.05V", 4, 10, 10)); + v.Add(new Voltage("DIMM CD", 5, 10, 10)); + v.Add(new Voltage("1.8V PLL", 6, 10, 10)); + v.Add(new Voltage("+3.3V", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 1)); + t.Add(new Temperature("CPU Socket", 2)); + t.Add(new Temperature("Temperature #4", 3)); + t.Add(new Temperature("Temperature #5", 4)); + t.Add(new Temperature("VRM", 5)); + + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Chassis Fan #1", 1)); + f.Add(new Fan("Chassis Fan #2", 2)); + f.Add(new Fan("High Amp Fan", 3)); + f.Add(new Fan("Fan 5", 4)); + f.Add(new Fan("Fan 6", 5)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("Voltage #8", 7, true)); + v.Add(new Voltage("VBat", 8)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.ASRock: + switch (model) + { + case Model.P55_Deluxe: // IT8720F + GetASRockConfiguration(superIO, + v, + t, + f, + ref readFan, + ref postUpdate, + out mutex); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("Voltage #8", 7, true)); + v.Add(new Voltage("VBat", 8)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.DFI: + switch (model) + { + case Model.LP_BI_P45_T2RS_Elite: // IT8718F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("VTT", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 4, 30, 10)); + v.Add(new Voltage("NB Core", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("+5VSB", 7, 6.8f, 10)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("System", 1)); + t.Add(new Temperature("Chipset", 2)); + f.Add(new Fan("Fan #1", 0)); + f.Add(new Fan("Fan #2", 1)); + f.Add(new Fan("Fan #3", 2)); + + break; + + case Model.LP_DK_P55_T3EH9: // IT8720F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("VTT", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 4, 30, 10)); + v.Add(new Voltage("CPU PLL", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("+5VSB", 7, 6.8f, 10)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("Chipset", 0)); + t.Add(new Temperature("CPU PWM", 1)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("Fan #1", 0)); + f.Add(new Fan("Fan #2", 1)); + f.Add(new Fan("Fan #3", 2)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("VTT", 1, true)); + v.Add(new Voltage("+3.3V", 2, true)); + v.Add(new Voltage("+5V", 3, 6.8f, 10, 0, true)); + v.Add(new Voltage("+12V", 4, 30, 10, 0, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("DIMM", 6, true)); + v.Add(new Voltage("+5VSB", 7, 6.8f, 10, 0, true)); + v.Add(new Voltage("VBat", 8)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.Gigabyte: + switch (model) + { + case Model._965P_S3: // IT8718F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + + break; + + case Model.EP45_DS3R: // IT8718F + case Model.EP45_UD3R: + case Model.X38_DS5: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #2", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("System Fan #1", 3)); + + break; + + case Model.EX58_EXTREME: // IT8720F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Northbridge", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #2", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("System Fan #1", 3)); + + break; + + case Model.P35_DS3: // IT8718F + case Model.P35_DS3L: // IT8718F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("Power Fan", 3)); + + break; + + case Model.P55_UD4: // IT8720F + case Model.P55A_UD3: // IT8720F + case Model.P55M_UD4: // IT8720F + case Model.H55_USB3: // IT8720F + case Model.EX58_UD3R: // IT8720F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 5, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #2", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("System Fan #1", 3)); + + break; + + case Model.H55N_USB3: // IT8720F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 5, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + + break; + + case Model.G41M_COMBO: // IT8718F + case Model.G41MT_S2: // IT8718F + case Model.G41MT_S2P: // IT8718F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 7, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + + break; + + case Model._970A_UD3: // IT8720F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("Power Fan", 4)); + c.Add(new Ctrl("PWM #1", 0)); + c.Add(new Ctrl("PWM #2", 1)); + c.Add(new Ctrl("PWM #3", 2)); + + break; + + case Model.MA770T_UD3: // IT8720F + case Model.MA770T_UD3P: // IT8720F + case Model.MA790X_UD3P: // IT8720F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("Power Fan", 3)); + + break; + + case Model.MA78LM_S2H: // IT8718F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("VRM", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("Power Fan", 3)); + + break; + + case Model.MA785GM_US2H: // IT8718F + case Model.MA785GMT_UD2H: // IT8718F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 4, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + f.Add(new Fan("NB Fan", 2)); + + break; + + case Model.X58A_UD3R: // IT8720F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+5V", 3, 6.8f, 10)); + v.Add(new Voltage("+12V", 5, 24.3f, 8.2f)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Northbridge", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #2", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("System Fan #1", 3)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1, true)); + v.Add(new Voltage("+3.3V", 2, true)); + v.Add(new Voltage("+5V", 3, 6.8f, 10, 0, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("Voltage #8", 7, true)); + v.Add(new Voltage("VBat", 8)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("Voltage #8", 7, true)); + v.Add(new Voltage("VBat", 8)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; } + } - private static void GetNuvotonConfigurationF(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + private static void GetASRockConfiguration + ( + ISuperIO superIO, + IList v, + IList t, + IList f, + ref ReadValueDelegate readFan, + ref UpdateDelegate postUpdate, + out Mutex mutex) + { + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 2)); + v.Add(new Voltage("+12V", 4, 30, 10)); + v.Add(new Voltage("+5V", 5, 6.8f, 10)); + v.Add(new Voltage("VBat", 8)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 1)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Chassis Fan #1", 1)); + + // this mutex is also used by the official ASRock tool + mutex = new Mutex(false, "ASRockOCMark"); + + bool exclusiveAccess = false; + try { - switch (manufacturer) + exclusiveAccess = mutex.WaitOne(10, false); + } + catch (AbandonedMutexException) + { } + catch (InvalidOperationException) + { } + + // only read additional fans if we get exclusive access + if (exclusiveAccess) + { + f.Add(new Fan("Chassis Fan #2", 2)); + f.Add(new Fan("Chassis Fan #3", 3)); + f.Add(new Fan("Power Fan", 4)); + + readFan = index => { - case Manufacturer.ASUS: - switch (model) - { - case Model.P8P67: // NCT6776F - case Model.P8P67_EVO: // NCT6776F - case Model.P8P67_PRO: // NCT6776F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+12V", 1, 11, 1)); + if (index < 2) + { + return superIO.Fans[index]; + } + + // get GPIO 80-87 + byte? gpio = superIO.ReadGpio(7); + if (!gpio.HasValue) + return null; + + // read the last 3 fans based on GPIO 83-85 + int[] masks = { 0x05, 0x03, 0x06 }; + return ((gpio.Value >> 3) & 0x07) == masks[index - 2] ? superIO.Fans[2] : null; + }; + + int fanIndex = 0; + + postUpdate = () => + { + // get GPIO 80-87 + byte? gpio = superIO.ReadGpio(7); + if (!gpio.HasValue) + return; + + // prepare the GPIO 83-85 for the next update + int[] masks = { 0x05, 0x03, 0x06 }; + superIO.WriteGpio(7, (byte)((gpio.Value & 0xC7) | (masks[fanIndex] << 3))); + fanIndex = (fanIndex + 1) % 3; + }; + } + } + + private static void GetIteConfigurationsB(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + { + switch (manufacturer) + { + case Manufacturer.ASUS: + switch (model) + { + case Model.ROG_STRIX_X470_I: // IT8665E + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("SB 2.5V", 1)); + v.Add(new Voltage("+12V", 2, 5, 1)); + v.Add(new Voltage("+5V", 3, 1.5f, 1)); + v.Add(new Voltage("+3.3V", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 1)); + t.Add(new Temperature("T_Sensor", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM", 4)); + t.Add(new Temperature("Temperature #6", 5)); + + f.Add(new Fan("CPU Fan", 0)); + + //Does not work when in AIO pump mode (shows 0). I don't know how to fix it. + f.Add(new Fan("Chassis Fan #1", 1)); + f.Add(new Fan("Chassis Fan #2", 2)); + + //offset: 2, because the first two always show zero + for (int i = 2; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i - 1), i)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("Voltage #8", 7, true)); + v.Add(new Voltage("VBat", 8)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.ECS: + switch (model) + { + case Model.A890GXM_A: // IT8721F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("NB Voltage", 2)); + v.Add(new Voltage("AVCC", 3, 10, 10)); + // v.Add(new Voltage("DIMM", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("System", 1)); + t.Add(new Temperature("Northbridge", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + f.Add(new Fan("Power Fan", 2)); + + break; + + default: + v.Add(new Voltage("Voltage #1", 0, true)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("AVCC", 3, 10, 10, 0, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); + v.Add(new Voltage("VBat", 8, 10, 10)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.Gigabyte: + switch (model) + { + case Model.H61M_DS2_REV_1_2: // IT8728F + case Model.H61M_USB3_B3_REV_2_0: // IT8728F + v.Add(new Voltage("VTT", 0)); + v.Add(new Voltage("+12V", 2, 30.9f, 10)); + v.Add(new Voltage("Vcore", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + + break; + + case Model.H67A_UD3H_B3: // IT8728F + case Model.H67A_USB3_B3: // IT8728F + v.Add(new Voltage("VTT", 0)); + v.Add(new Voltage("+5V", 1, 15, 10)); + v.Add(new Voltage("+12V", 2, 30.9f, 10)); + v.Add(new Voltage("Vcore", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("System Fan #2", 3)); + + break; + + case Model.H81M_HD3: //IT8620E + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("iGPU", 4)); + v.Add(new Voltage("CPU VRIN", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("System", 0)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan", 1)); + + break; + + case Model.Z170N_WIFI: // ITE IT8628E + v.Add(new Voltage("Vcore", 0, 0, 1)); + v.Add(new Voltage("+3.3V", 1, 6.5F, 10)); + v.Add(new Voltage("+12V", 2, 5, 1)); + v.Add(new Voltage("+5V", 3, 1.5F, 1)); + // NO DIMM CD channels on this motherboard; gives a very tiny voltage reading + // v.Add(new Voltage("DIMM CD", 4, 0, 1)); + v.Add(new Voltage("iGPU VAXG", 5, 0, 1)); + v.Add(new Voltage("DIMM AB", 6, 0, 1)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + v.Add(new Voltage("AVCC3", 9, 54, 10)); + + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("PCH", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM", 4)); + t.Add(new Temperature("System #2", 5)); + + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan", 1)); + + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan", 1)); + + break; + + case Model.AX370_Gaming_K7: // IT8686E + case Model.AX370_Gaming_5: + case Model.AB350_Gaming_3: // IT8686E + // Note: v3.3, v12, v5, and AVCC3 might be slightly off. + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 0.65f, 1)); + v.Add(new Voltage("+12V", 2, 5, 1)); + v.Add(new Voltage("+5V", 3, 1.5f, 1)); + v.Add(new Voltage("VSOC", 4)); + v.Add(new Voltage("VDDP", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + v.Add(new Voltage("AVCC3", 9, 7.53f, 1)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("Chipset", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + break; + + case Model.X399_AORUS_Gaming_7: // ITE IT8686E + v.Add(new Voltage("Vcore", 0, 0, 1)); + v.Add(new Voltage("+3.3V", 1, 6.5F, 10)); + v.Add(new Voltage("+12V", 2, 5, 1)); + v.Add(new Voltage("+5V", 3, 1.5F, 1)); + v.Add(new Voltage("DIMM CD", 4, 0, 1)); + v.Add(new Voltage("Vcore SoC", 5, 0, 1)); + v.Add(new Voltage("DIMM AB", 6, 0, 1)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + v.Add(new Voltage("AVCC3", 9, 54, 10)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("Chipset", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM", 4)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.X470_AORUS_GAMING_7_WIFI: // ITE IT8686E + v.Add(new Voltage("Vcore", 0, 0, 1)); + v.Add(new Voltage("+3.3V", 1, 6.5F, 10)); + v.Add(new Voltage("+12V", 2, 5, 1)); + v.Add(new Voltage("+5V", 3, 1.5F, 1)); + v.Add(new Voltage("Vcore SoC", 4, 0, 1)); + v.Add(new Voltage("VDDP", 5, 0, 1)); + v.Add(new Voltage("DIMM AB", 6, 0, 1)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + v.Add(new Voltage("AVCC3", 9, 54, 10)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("Chipset", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM", 4)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.B560M_AORUS_ELITE: // IT8689E + case Model.B560M_AORUS_PRO: + case Model.B560M_AORUS_PRO_AX: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); + v.Add(new Voltage("+12V", 2, 10f, 2f)); + v.Add(new Voltage("+5V", 3, 15f, 10f)); + v.Add(new Voltage("iGPU VAGX", 4)); + v.Add(new Voltage("VCCSA", 5)); + v.Add(new Voltage("DRAM", 6)); + v.Add(new Voltage("3VSB", 7, 10f, 10f)); + v.Add(new Voltage("VBat", 8, 10f, 10f)); + v.Add(new Voltage("AVCC3", 9, 59.9f, 9.8f)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("PCH", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("System #2", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("System Fan #3", 3)); + f.Add(new Fan("CPU Optional Fan", 4)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("System Fan #3", 3)); + c.Add(new Ctrl("CPU Optional Fan", 4)); + + break; + + case Model.B360_AORUS_GAMING_3_WIFI_CF: // IT8688E + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); + v.Add(new Voltage("+12V", 2, 10f, 2f)); + v.Add(new Voltage("+5V", 3, 15f, 10f)); + v.Add(new Voltage("CPU Vcore", 4, 0, 1)); + v.Add(new Voltage("CPU VCCSA", 5, 0, 1)); + v.Add(new Voltage("DIMM AB", 6, 0, 1)); + v.Add(new Voltage("3VSB", 7, 1, 1)); + v.Add(new Voltage("VBat", 8, 1, 1)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("EC_TEMP1", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("PCH", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("PCH Fan", 3)); + f.Add(new Fan("CPU Optional Fan", 4)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("PCH Fan", 3)); + c.Add(new Ctrl("CPU Optional Fan", 4)); + + break; + + case Model.X570_AORUS_MASTER: // IT8688E + case Model.X570_AORUS_ULTRA: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); + v.Add(new Voltage("+12V", 2, 10f, 2f)); + v.Add(new Voltage("+5V", 3, 15f, 10f)); + v.Add(new Voltage("Vcore SoC", 4)); + v.Add(new Voltage("VDDP", 5)); + v.Add(new Voltage("DIMM AB", 6)); + v.Add(new Voltage("3VSB", 7, 1f, 10f)); + v.Add(new Voltage("VBat", 8, 1f, 10f)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("EC_TEMP1", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("PCH", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("PCH Fan", 3)); + f.Add(new Fan("CPU Optional Fan", 4)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("PCH Fan", 3)); + c.Add(new Ctrl("CPU Optional Fan", 4)); + + break; + + case Model.X570_GAMING_X: // IT8688E + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 29.4f, 45.3f)); + v.Add(new Voltage("+12V", 2, 10f, 2f)); + v.Add(new Voltage("+5V", 3, 15f, 10f)); + v.Add(new Voltage("Vcore SoC", 4)); + v.Add(new Voltage("VDDP", 5)); + v.Add(new Voltage("DIMM AB", 6)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("System #2", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("PCH", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("PCH Fan", 3)); + f.Add(new Fan("CPU Optional Fan", 4)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("PCH Fan", 3)); + c.Add(new Ctrl("CPU Optional Fan", 4)); + + break; + + case Model.Z390_M_GAMING: // IT8688E + case Model.Z390_AORUS_ULTRA: + case Model.Z390_UD: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); + v.Add(new Voltage("+12V", 2, 5f, 1)); + v.Add(new Voltage("+5V", 3, 1.5f, 1)); + v.Add(new Voltage("CPU VCCGT", 4)); + v.Add(new Voltage("CPU VCCSA", 5)); + v.Add(new Voltage("VDDQ", 6)); + v.Add(new Voltage("DDRVTT", 7)); + v.Add(new Voltage("PCHCore", 8)); + v.Add(new Voltage("CPU VCCIO", 9)); + v.Add(new Voltage("DDRVPP", 10)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("PCH", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("System #2", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("System Fan #3", 3)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("System Fan #3", 3)); + + break; + + case Model.Z390_AORUS_PRO: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); + v.Add(new Voltage("+12V", 2, 5f, 1)); + v.Add(new Voltage("+5V", 3, 1.5f, 1)); + v.Add(new Voltage("CPU VCCGT", 4)); + v.Add(new Voltage("CPU VCCSA", 5)); + v.Add(new Voltage("DDR", 6)); + v.Add(new Voltage("Voltage #7", 7, true)); + v.Add(new Voltage("3VSB", 8, 1f, 1f, -0.312f)); + v.Add(new Voltage("VBat", 9, 6f, 1f, 0.01f)); + v.Add(new Voltage("AVCC3", 10, 6f, 1f, 0.048f)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("PCH", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("EC_TEMP1/System #2", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("System Fan #3", 3)); + f.Add(new Fan("CPU Optional Fan", 4)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("System Fan #3", 3)); + c.Add(new Ctrl("CPU Optional Fan", 4)); + + break; + + case Model.Z690_AORUS_PRO: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); + v.Add(new Voltage("+12V", 2, 5f, 1)); + v.Add(new Voltage("+5V", 3, 1.5f, 1)); + v.Add(new Voltage("iGPU VAXG", 4)); + v.Add(new Voltage("CPU VCCIN_AUX", 5)); + v.Add(new Voltage("Voltage #6", 6, true)); + v.Add(new Voltage("3VSB", 7, 1f, 1f)); + v.Add(new Voltage("VBat", 8, 1f, 1f)); + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("PCH", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("EC_TEMP1", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("System Fan #3", 3)); + f.Add(new Fan("CPU Optional Fan", 4)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("System Fan #3", 3)); + c.Add(new Ctrl("CPU Optional Fan", 4)); + break; + + case Model.Z690_GAMING_X_DDR4: + t.Add(new Temperature("System #1", 0)); + t.Add(new Temperature("PCH", 1)); + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("PCIe x16", 3)); + t.Add(new Temperature("VRM MOS", 4)); + t.Add(new Temperature("System #2", 5)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("System Fan #3", 3)); + f.Add(new Fan("CPU Optional Fan", 4)); + f.Add(new Fan("System Fan #4 / Pump", 5)); + c.Add(new Ctrl("CPU Fan", 0)); + c.Add(new Ctrl("System Fan #1", 1)); + c.Add(new Ctrl("System Fan #2", 2)); + c.Add(new Ctrl("System Fan #3", 3)); + c.Add(new Ctrl("CPU Optional Fan", 4)); + c.Add(new Ctrl("System Fan #4 / Pump", 5)); + break; + + case Model.Z68A_D3H_B3: // IT8728F + v.Add(new Voltage("VTT", 0)); + v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); + v.Add(new Voltage("+12V", 2, 30.9f, 10)); + v.Add(new Voltage("+5V", 3, 7.15f, 10)); + v.Add(new Voltage("Vcore", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("System Fan #2", 3)); + + break; + + case Model.P67A_UD3_B3: // IT8728F + case Model.P67A_UD3R_B3: // IT8728F + case Model.P67A_UD4_B3: // IT8728F + case Model.Z68AP_D3: // IT8728F + case Model.Z68X_UD3H_B3: // IT8728F + case Model.Z68XP_UD3R: // IT8728F + v.Add(new Voltage("VTT", 0)); + v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); + v.Add(new Voltage("+12V", 2, 30.9f, 10)); + v.Add(new Voltage("+5V", 3, 7.15f, 10)); + v.Add(new Voltage("Vcore", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #2", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("System Fan #1", 3)); + + break; + + case Model.Z68X_UD7_B3: // IT8728F + v.Add(new Voltage("VTT", 0)); + v.Add(new Voltage("+3.3V", 1, 6.49f, 10)); + v.Add(new Voltage("+12V", 2, 30.9f, 10)); + v.Add(new Voltage("+5V", 3, 7.15f, 10)); + v.Add(new Voltage("Vcore", 5)); + v.Add(new Voltage("DIMM", 6)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("System #3", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Power Fan", 1)); + f.Add(new Fan("System Fan #1", 2)); + f.Add(new Fan("System Fan #2", 3)); + f.Add(new Fan("System Fan #3", 4)); + + break; + + case Model.X79_UD3: // IT8728F + v.Add(new Voltage("VTT", 0)); + v.Add(new Voltage("DIMM AB", 1)); + v.Add(new Voltage("+12V", 2, 10, 2)); + v.Add(new Voltage("+5V", 3, 15, 10)); + v.Add(new Voltage("VIN4", 4)); + v.Add(new Voltage("VCore", 5)); + v.Add(new Voltage("DIMM CD", 6)); + v.Add(new Voltage("+3V Standby", 7, 1, 1)); + v.Add(new Voltage("VBat", 8, 1, 1)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Northbridge", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("System Fan #1", 1)); + f.Add(new Fan("System Fan #2", 2)); + f.Add(new Fan("System Fan #3", 3)); + + break; + + default: + v.Add(new Voltage("Voltage #1", 0, true)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); + v.Add(new Voltage("VBat", 8, 10, 10)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.Biostar: + switch (model) + { + case Model.B660GTN: //IT8613E + // This board has some problems with their app controlling fans that I was able to replicate here so I guess is a BIOS problem with the pins. + // Biostar is aware so expect changes in the control pins with new bios. + // In the meantime, it's possible to control CPUFAN and CPUOPT1m but not SYSFAN1. + // The parameters are extracted from the Biostar app config file. + v.Add(new Voltage("Vcore", 0, 0, 1)); + v.Add(new Voltage("DIMM", 1, 0, 1)); + v.Add(new Voltage("+12V", 2, 5, 1)); // Reads higher than it should. + v.Add(new Voltage("+5V", 3, 147, 100)); // Reads higher than it should. + // Commented because I don't know if it makes sense. + //v.Add(new Voltage("VCC ST", 4)); // Reads 4.2V. + //v.Add(new Voltage("VCCIN AUX", 5)); // Reads 2.2V. + //v.Add(new Voltage("CPU GT", 6)); // Reads 2.6V. + //v.Add(new Voltage("3VSB", 7, 10, 10)); // Reads 5.8V ? + v.Add(new Voltage("VBat", 8, 10, 10)); // Reads higher than it should at 3.4V. + t.Add(new Temperature("System 1", 0)); + t.Add(new Temperature("System 2", 1)); // Not sure what sensor is this. + t.Add(new Temperature("CPU", 2)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("CPU Optional fan", 2)); + f.Add(new Fan("System Fan", 4)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("CPU Optional Fan", 2)); + c.Add(new Ctrl("System Fan", 4)); + + break; + + default: + v.Add(new Voltage("Voltage #1", 0, true)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); + v.Add(new Voltage("VBat", 8, 10, 10)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.Shuttle: + switch (model) + { + case Model.FH67: // IT8772E + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("DIMM", 1)); + v.Add(new Voltage("PCH VCCIO", 2)); + v.Add(new Voltage("CPU VCCIO", 3)); + v.Add(new Voltage("Graphic Voltage", 4)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("System", 0)); + t.Add(new Temperature("CPU", 1)); + f.Add(new Fan("Fan #1", 0)); + f.Add(new Fan("CPU Fan", 1)); + + break; + + default: + v.Add(new Voltage("Voltage #1", 0, true)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); + v.Add(new Voltage("VBat", 8, 10, 10)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + + default: + v.Add(new Voltage("Voltage #1", 0, true)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); + v.Add(new Voltage("VBat", 8, 10, 10)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + } + + private static void GetIteConfigurationsC(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + { + switch (manufacturer) + { + case Manufacturer.Gigabyte: + switch (model) + { + case Model.X570_AORUS_MASTER: // IT879XE + case Model.X570_AORUS_ULTRA: + v.Add(new Voltage("CPU VDD18", 0)); + v.Add(new Voltage("DDRVTT AB", 1)); + v.Add(new Voltage("Chipset Core", 2)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("CPU VDD18", 4)); + v.Add(new Voltage("PM_CLDO12", 5)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 1f, 1f)); + v.Add(new Voltage("VBat", 8, 1f, 1f)); + t.Add(new Temperature("PCIe x8", 0)); + t.Add(new Temperature("EC_TEMP2", 1)); + t.Add(new Temperature("System #2", 2)); + f.Add(new Fan("System Fan #5 Pump", 0)); + f.Add(new Fan("System Fan #6 Pump", 1)); + f.Add(new Fan("System Fan #4", 2)); + + break; + + case Model.X470_AORUS_GAMING_7_WIFI: // ITE IT8792 + v.Add(new Voltage("VIN0", 0, 0, 1)); + v.Add(new Voltage("DDR VTT", 1, 0, 1)); + v.Add(new Voltage("Chipset Core", 2, 0, 1)); + v.Add(new Voltage("VIN3", 3, 0, 1)); + v.Add(new Voltage("CPU VDD18", 4, 0, 1)); + v.Add(new Voltage("Chipset Core +2.5V", 5, 0.5F, 1)); + v.Add(new Voltage("3VSB", 6, 1, 10)); + v.Add(new Voltage("VBat", 7, 0.7F, 1)); + t.Add(new Temperature("PCIe x8", 0)); + t.Add(new Temperature("System #2", 2)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.Z390_AORUS_PRO: // IT879XE + v.Add(new Voltage("VCore", 0)); + v.Add(new Voltage("DDRVTT AB", 1)); + v.Add(new Voltage("Chipset Core", 2)); + v.Add(new Voltage("VIN3", 3, true)); + v.Add(new Voltage("VCCIO", 4)); + v.Add(new Voltage("Voltage #7", 5, true)); + v.Add(new Voltage("DDR VPP", 6)); + v.Add(new Voltage("3VSB", 7, 1f, 1f)); + v.Add(new Voltage("VBat", 8, 1f, 1f)); + t.Add(new Temperature("PCIe x8", 0)); + t.Add(new Temperature("EC_TEMP2", 1)); + t.Add(new Temperature("System #2", 2)); + f.Add(new Fan("System Fan #5 Pump", 0)); + f.Add(new Fan("System Fan #6 Pump", 1)); + f.Add(new Fan("System Fan #4", 2)); + c.Add(new Ctrl("Fan #5", 0)); + c.Add(new Ctrl("Fan #6", 1)); + c.Add(new Ctrl("Fan #4", 2)); + + break; + + case Model.Z690_AORUS_PRO: + t.Add(new Temperature("PCIe x4", 0)); + t.Add(new Temperature("EC_TEMP2", 1)); + t.Add(new Temperature("System #2", 2)); + f.Add(new Fan("System Fan #5 Pump", 0)); + f.Add(new Fan("System Fan #6 Pump", 1)); + f.Add(new Fan("System Fan #4", 2)); + c.Add(new Ctrl("System Fan #5 Pump", 0)); + c.Add(new Ctrl("System Fan #6 Pump", 1)); + c.Add(new Ctrl("System Fan #4", 2)); + break; + + default: + v.Add(new Voltage("Voltage #1", 0, true)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); + v.Add(new Voltage("VBat", 8, 10, 10)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + + default: + v.Add(new Voltage("Voltage #1", 0, true)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 10, 10, 0, true)); + v.Add(new Voltage("VBat", 8, 10, 10)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + } + + private static void GetFintekConfiguration(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + { + switch (manufacturer) + { + case Manufacturer.EVGA: + switch (model) + { + case Model.X58_SLI_Classified: // F71882 + v.Add(new Voltage("VCC3V", 0, 150, 150)); + v.Add(new Voltage("Vcore", 1, 47, 100)); + v.Add(new Voltage("DIMM", 2, 47, 100)); + v.Add(new Voltage("CPU VTT", 3, 24, 100)); + v.Add(new Voltage("IOH Vcore", 4, 24, 100)); + v.Add(new Voltage("+5V", 5, 51, 12)); + v.Add(new Voltage("+12V", 6, 56, 6.8f)); + v.Add(new Voltage("3VSB", 7, 150, 150)); + v.Add(new Voltage("VBat", 8, 150, 150)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("VREG", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Power Fan", 1)); + f.Add(new Fan("Chassis Fan", 2)); + + break; + + default: + v.Add(new Voltage("VCC3V", 0, 150, 150)); + v.Add(new Voltage("Vcore", 1)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("VSB3V", 7, 150, 150)); + v.Add(new Voltage("VBat", 8, 150, 150)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + break; + } + + break; + + default: + v.Add(new Voltage("VCC3V", 0, 150, 150)); + v.Add(new Voltage("Vcore", 1)); + v.Add(new Voltage("Voltage #3", 2, true)); + v.Add(new Voltage("Voltage #4", 3, true)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + if (superIO.Chip != Chip.F71808E) + v.Add(new Voltage("Voltage #7", 6, true)); + + v.Add(new Voltage("VSB3V", 7, 150, 150)); + v.Add(new Voltage("VBat", 8, 150, 150)); + + for (int i = 0; i < superIO.Temperatures.Length; i++) + t.Add(new Temperature("Temperature #" + (i + 1), i)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + } + + private static void GetNuvotonConfigurationF(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + { + switch (manufacturer) + { + case Manufacturer.ASUS: + switch (model) + { + case Model.P8P67: // NCT6776F + case Model.P8P67_EVO: // NCT6776F + case Model.P8P67_PRO: // NCT6776F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+12V", 1, 11, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+5V", 4, 12, 3)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 2)); + t.Add(new Temperature("Motherboard", 3)); + f.Add(new Fan("Chassis Fan #1", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("Chassis Fan #2", 3)); + c.Add(new Ctrl("Chassis Fan #2", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Chassis Fan #1", 2)); + + break; + + case Model.P8P67_M_PRO: // NCT6776F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+12V", 1, 11, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+5V", 4, 12, 3)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 3)); + f.Add(new Fan("Chassis Fan #1", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Chassis Fan #2", 2)); + f.Add(new Fan("Power Fan", 3)); + f.Add(new Fan("Auxiliary Fan", 4)); + + break; + + case Model.P8Z68_V_PRO: // NCT6776F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+12V", 1, 11, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+5V", 4, 12, 3)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 2)); + t.Add(new Temperature("Motherboard", 3)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.P9X79: // NCT6776F + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+12V", 1, 11, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+5V", 4, 12, 3)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 3)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Temperature #1", 1)); + t.Add(new Temperature("Temperature #2", 2)); + t.Add(new Temperature("Temperature #3", 3)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.ASRock: + switch (model) + { + case Model.B85M_DGS: + { + v.Add(new Voltage("Vcore", 0, 1, 1)); + v.Add(new Voltage("+12V", 1, 56, 10)); v.Add(new Voltage("AVCC", 2, 34, 34)); v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+5V", 4, 12, 3)); + v.Add(new Voltage("VIN1", 4, true)); + v.Add(new Voltage("+5V", 5, 12, 3)); + v.Add(new Voltage("VIN3", 6, true)); v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); t.Add(new Temperature("CPU", 0)); t.Add(new Temperature("Auxiliary", 2)); t.Add(new Temperature("Motherboard", 3)); @@ -1920,1425 +2030,1314 @@ namespace LibreHardwareMonitor.Hardware.Motherboard c.Add(new Ctrl("Chassis Fan #2", 0)); c.Add(new Ctrl("CPU Fan", 1)); c.Add(new Ctrl("Chassis Fan #1", 2)); - - break; - - case Model.P8P67_M_PRO: // NCT6776F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+12V", 1, 11, 1)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+5V", 4, 12, 3)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 3)); - f.Add(new Fan("Chassis Fan #1", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Chassis Fan #2", 2)); - f.Add(new Fan("Power Fan", 3)); - f.Add(new Fan("Auxiliary Fan", 4)); - - break; - - case Model.P8Z68_V_PRO: // NCT6776F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+12V", 1, 11, 1)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+5V", 4, 12, 3)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 2)); - t.Add(new Temperature("Motherboard", 3)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.P9X79: // NCT6776F - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+12V", 1, 11, 1)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+5V", 4, 12, 3)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 3)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Temperature #1", 1)); - t.Add(new Temperature("Temperature #2", 2)); - t.Add(new Temperature("Temperature #3", 3)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.ASRock: - switch (model) - { - case Model.B85M_DGS: - { - v.Add(new Voltage("Vcore", 0, 1, 1)); - v.Add(new Voltage("+12V", 1, 56, 10)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("VIN1", 4, true)); - v.Add(new Voltage("+5V", 5, 12, 3)); - v.Add(new Voltage("VIN3", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 2)); - t.Add(new Temperature("Motherboard", 3)); - f.Add(new Fan("Chassis Fan #1", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("Chassis Fan #2", 3)); - c.Add(new Ctrl("Chassis Fan #2", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Chassis Fan #1", 2)); - } - - break; - case Model.Z77Pro4M: //NCT6776F - v.Add(new Voltage("Vcore", 0, 0, 1)); - v.Add(new Voltage("+12V", 1, 56, 10)); - v.Add(new Voltage("AVCC", 2, 10, 10)); - v.Add(new Voltage("+3.3V", 3, 10, 10)); - //v.Add(new Voltage("#Unused #4", 4, 0, 1, 0, true)); - v.Add(new Voltage("+5V", 5, 20, 10)); - //v.Add(new Voltage("#Unused #6", 6, 0, 1, 0, true)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Auxiliary", 2)); - t.Add(new Temperature("Motherboard", 3)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Temperature #1", 1)); - t.Add(new Temperature("Temperature #2", 2)); - t.Add(new Temperature("Temperature #3", 3)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Temperature #1", 1)); - t.Add(new Temperature("Temperature #2", 2)); - t.Add(new Temperature("Temperature #3", 3)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - } - - private static void GetNuvotonConfigurationD(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) - { - switch (manufacturer) - { - case Manufacturer.ASRock: - switch (model) - { - case Model.A320M_HDV: //NCT6779D - v.Add(new Voltage("Vcore", 0, 10, 10)); - v.Add(new Voltage("Chipset 1.05V", 1, 0, 1)); - v.Add(new Voltage("AVCC", 2, 10, 10)); - v.Add(new Voltage("+3.3V", 3, 10, 10)); - v.Add(new Voltage("+12V", 4, 56, 10)); - v.Add(new Voltage("VcoreRef", 5, 0, 1)); - v.Add(new Voltage("DIMM", 6, 0, 1)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - //v.Add(new Voltage("#Unused #9", 9, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #10", 10, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #11", 11, 34, 34, 0, true)); - v.Add(new Voltage("+5V", 12, 20, 10)); - //v.Add(new Voltage("#Unused #13", 13, 10, 10, 0, true)); - //v.Add(new Voltage("#Unused #14", 14, 0, 1, 0, true)); - - //t.Add(new Temperature("#Unused #0", 0)); - //t.Add(new Temperature("#Unused #1", 1)); - t.Add(new Temperature("Motherboard", 2)); - //t.Add(new Temperature("#Unused #3", 3)); - //t.Add(new Temperature("#Unused #4", 4)); - t.Add(new Temperature("Auxiliary", 5)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.AB350_Pro4: //NCT6779D - case Model.AB350M_Pro4: - case Model.AB350M: - case Model.Fatal1ty_AB350_Gaming_K4: - case Model.AB350M_HDV: - case Model.B450_Steel_Legend: - case Model.B450M_Steel_Legend: - case Model.B450_Pro4: - case Model.B450M_Pro4: - v.Add(new Voltage("Vcore", 0, 10, 10)); - //v.Add(new Voltage("#Unused", 1, 0, 1, 0, true)); - v.Add(new Voltage("AVCC", 2, 10, 10)); - v.Add(new Voltage("+3.3V", 3, 10, 10)); - v.Add(new Voltage("+12V", 4, 28, 5)); - v.Add(new Voltage("Vcore Refin", 5, 0, 1)); - //v.Add(new Voltage("#Unused #6", 6, 0, 1, 0, true)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 34, 34)); - //v.Add(new Voltage("#Unused #9", 9, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #10", 10, 0, 1, 0, true)); - v.Add(new Voltage("Chipset 1.05V", 11, 0, 1)); - v.Add(new Voltage("+5V", 12, 20, 10)); - //v.Add(new Voltage("#Unused #13", 13, 0, 1, 0, true)); - v.Add(new Voltage("+1.8V", 14, 0, 1)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Motherboard", 2)); - t.Add(new Temperature("Auxiliary", 3)); - t.Add(new Temperature("VRM", 4)); - t.Add(new Temperature("AUXTIN2", 5)); - //t.Add(new Temperature("Temperature #6", 6)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.X399_Phantom_Gaming_6: //NCT6779D - v.Add(new Voltage("Vcore", 0, 10, 10)); - v.Add(new Voltage("Chipset 1.05V", 1, 0, 1)); - v.Add(new Voltage("AVCC", 2, 10, 10)); - v.Add(new Voltage("+3.3V", 3, 10, 10)); - v.Add(new Voltage("+12V", 4, 56, 10)); - v.Add(new Voltage("VDDCR_SOC", 5, 0, 1)); - v.Add(new Voltage("DIMM", 6, 0, 1)); - v.Add(new Voltage("3VSB", 7, 10, 10)); - v.Add(new Voltage("VBat", 8, 10, 10)); - //v.Add(new Voltage("#Unused", 9, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused", 10, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused", 11, 0, 1, 0, true)); - v.Add(new Voltage("+5V", 12, 20, 10)); - v.Add(new Voltage("+1.8V", 13, 10, 10)); - //v.Add(new Voltage("unused", 14, 34, 34, 0, true)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Motherboard", 1)); - t.Add(new Temperature("Auxiliary", 2)); - t.Add(new Temperature("Chipset", 3)); - t.Add(new Temperature("Core VRM", 4)); - t.Add(new Temperature("Core SoC", 5)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.X570_Taichi: - v.Add(new Voltage("Vcore", 0, 10, 10)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - - t.Add(new Temperature("Motherboard", 2)); - t.Add(new Temperature("CPU", 8)); - t.Add(new Temperature("SB (Chipset)", 9)); - - f.Add(new Fan("Chassis #3", 0)); - f.Add(new Fan("CPU #1", 1)); - f.Add(new Fan("CPU #2", 2)); - f.Add(new Fan("Chassis #1", 3)); - f.Add(new Fan("Chassis #2", 4)); - f.Add(new Fan("SB Fan", 5)); - f.Add(new Fan("Chassis #4", 6)); - - c.Add(new Ctrl("Chassis #3", 0)); - c.Add(new Ctrl("CPU #1", 1)); - c.Add(new Ctrl("CPU #2", 2)); - c.Add(new Ctrl("Chassis #1", 3)); - c.Add(new Ctrl("Chassis #2", 4)); - c.Add(new Ctrl("SB Fan", 5)); - c.Add(new Ctrl("Chassis #4", 6)); - - break; - - case Model.X570_Phantom_Gaming_ITX: - v.Add(new Voltage("+12V", 0)); - v.Add(new Voltage("+5V", 1)); - v.Add(new Voltage("Vcore", 2)); - v.Add(new Voltage("Voltage #1", 3)); - v.Add(new Voltage("DIMM", 4)); - v.Add(new Voltage("CPU I/O", 5)); - v.Add(new Voltage("CPU SA", 6)); - v.Add(new Voltage("Voltage #2", 7)); - v.Add(new Voltage("AVCC3", 8)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("VRef", 10)); - v.Add(new Voltage("VSB", 11)); - v.Add(new Voltage("AVSB", 12)); - v.Add(new Voltage("VBat", 13)); - - t.Add(new Temperature("Motherboard", 0)); - //t.Add(new Temperature("System", 1)); //Unused - t.Add(new Temperature("CPU", 2)); - t.Add(new Temperature("SB (Chipset)", 3)); - f.Add(new Fan("CPU Fan #1", 0)); //CPU_FAN1 - f.Add(new Fan("Chassis Fan #1", 1)); //CHA_FAN1/WP - f.Add(new Fan("CPU Fan #2", 2)); //CPU_FAN2 (WP) - f.Add(new Fan("Chipset Fan", 3)); - - c.Add(new Ctrl("CPU Fan #1", 0)); - c.Add(new Ctrl("Chassis Fan", 1)); - c.Add(new Ctrl("CPU Fan #2", 2)); - c.Add(new Ctrl("Chipset Fan", 3)); - break; - - default: - v.Add(new Voltage("Vcore", 0, 10, 10)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Temperature #1", 1)); - t.Add(new Temperature("Temperature #2", 2)); - t.Add(new Temperature("Temperature #3", 3)); - t.Add(new Temperature("Temperature #4", 4)); - t.Add(new Temperature("Temperature #5", 5)); - t.Add(new Temperature("Temperature #6", 6)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.ASUS: - string[] fanControlNames; - switch (model) - { - case Model.P8Z77_V: // NCT6779D - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("Motherboard", 2)); - f.Add(new Fan("Chassis Fan #1", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Chassis Fan #2", 2)); - f.Add(new Fan("Chassis Fan #3", 3)); - c.Add(new Ctrl("Chassis Fan #1", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Chassis Fan #2", 2)); - c.Add(new Ctrl("Chassis Fan #3", 3)); - - break; - - case Model.ROG_MAXIMUS_X_APEX: // NCT6793D - v.Add(new Voltage("Vcore", 0, 2, 2)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("AVSB", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("CPU GFX", 6, 2, 2)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("DIMM", 10, 1, 1)); - v.Add(new Voltage("VCCSA", 11)); - v.Add(new Voltage("PCH Core", 12)); - v.Add(new Voltage("CPU PLLs", 13)); - v.Add(new Voltage("CPU VCCIO/IMC", 14)); - t.Add(new Temperature("CPU (PECI)", 0)); - t.Add(new Temperature("T2", 1)); - t.Add(new Temperature("T1", 2)); - t.Add(new Temperature("CPU", 3)); - t.Add(new Temperature("PCH", 4)); - t.Add(new Temperature("Temperature #4", 5)); - t.Add(new Temperature("Temperature #5", 6)); - f.Add(new Fan("Chassis Fan #1", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Chassis Fan #2", 2)); - f.Add(new Fan("Chassis Fan #3", 3)); - f.Add(new Fan("AIO Pump", 4)); - c.Add(new Ctrl("Chassis Fan #1", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Chassis Fan #2", 2)); - c.Add(new Ctrl("Chassis Fan #3", 3)); - c.Add(new Ctrl("AIO Pump", 4)); - - break; - - case Model.Z170_A: //NCT6793D - v.Add(new Voltage("Vcore", 0, 2, 2)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("AVSB", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); - v.Add(new Voltage("Voltage #6", 5, 0, 1, 0, true)); - v.Add(new Voltage("CPU GFX", 6, 2, 2)); - v.Add(new Voltage("3VSB_ATX", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("DIMM", 10, 1, 1)); - v.Add(new Voltage("VCCSA", 11)); - v.Add(new Voltage("PCH Core", 12)); - v.Add(new Voltage("CPU PLLs", 13)); - v.Add(new Voltage("CPU VCCIO/IMC", 14)); - t.Add(new Temperature("CPU (PECI)", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Motherboard", 2)); - t.Add(new Temperature("CPU", 3)); - t.Add(new Temperature("PCH", 4)); - t.Add(new Temperature("Temperature #4", 5)); - t.Add(new Temperature("Temperature #5", 6)); - - // CPU Fan Optional uses the same fancontrol as CPU Fan. - // Water Pump speed can only be read from the EC. - string[] fanNames = { "Chassis Fan 1", "CPU Fan", "Chassis Fan 2", "Chassis Fan 3", "Chassis Fan 4", "CPU Fan Optional" }; - fanControlNames = new[] { "Chassis Fan 1", "CPU Fan", "Chassis Fan 2", "Chassis Fan 3", "Chassis Fan 4", "Water Pump" }; - - for (int i = 0; i < fanNames.Length; i++) - f.Add(new Fan(fanNames[i], i)); - - for (int i = 0; i < fanControlNames.Length; i++) - c.Add(new Ctrl(fanControlNames[i], i)); - - break; - - case Model.TUF_GAMING_B550M_PLUS_WIFI: //NCT6798D - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("PECI 0", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("System", 2)); - t.Add(new Temperature("AUX 0", 3)); - t.Add(new Temperature("AUX 1", 4)); - t.Add(new Temperature("AUX 2", 5)); - t.Add(new Temperature("AUX 3", 6)); - t.Add(new Temperature("AUX 4", 7)); - t.Add(new Temperature("SMBus 0", 8)); - t.Add(new Temperature("SMBus 1", 9)); - t.Add(new Temperature("PECI 1", 10)); - t.Add(new Temperature("PCH Chip CPU Max", 11)); - t.Add(new Temperature("PCH Chip", 12)); - t.Add(new Temperature("PCH CPU", 13)); - t.Add(new Temperature("PCH MCH", 14)); - t.Add(new Temperature("Agent 0 DIMM 0", 15)); - t.Add(new Temperature("Agent 0 DIMM 1", 16)); - t.Add(new Temperature("Agent 1 DIMM 0", 17)); - t.Add(new Temperature("Agent 1 DIMM 1", 18)); - t.Add(new Temperature("Device 0", 19)); - t.Add(new Temperature("Device 1", 20)); - t.Add(new Temperature("PECI 0 Calibrated", 21)); - t.Add(new Temperature("PECI 1 Calibrated", 22)); - t.Add(new Temperature("Virtual", 23)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - case Model.ROG_CROSSHAIR_VIII_HERO: // NCT6798D - case Model.ROG_CROSSHAIR_VIII_HERO_WIFI: // NCT6798D - case Model.ROG_CROSSHAIR_VIII_DARK_HERO: // NCT6798D - case Model.ROG_CROSSHAIR_VIII_FORMULA: // NCT6798D - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("CPU SoC", 6)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("DRAM", 13)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("PECI 0", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Motherboard", 2)); - t.Add(new Temperature("AUX 0", 3)); - t.Add(new Temperature("AUX 1", 4)); - t.Add(new Temperature("AUX 2", 5)); - t.Add(new Temperature("AUX 3", 6)); - t.Add(new Temperature("AUX 4", 7)); - t.Add(new Temperature("SMBus 0", 8)); - t.Add(new Temperature("SMBus 1", 9)); - t.Add(new Temperature("PECI 1", 10)); - t.Add(new Temperature("PCH Chip CPU Max", 11)); - t.Add(new Temperature("PCH Chip", 12)); - t.Add(new Temperature("PCH CPU", 13)); - t.Add(new Temperature("PCH MCH", 14)); - t.Add(new Temperature("Agent 0 DIMM 0", 15)); - t.Add(new Temperature("Agent 0 DIMM 1", 16)); - t.Add(new Temperature("Agent 1 DIMM 0", 17)); - t.Add(new Temperature("Agent 1 DIMM 1", 18)); - t.Add(new Temperature("Device 0", 19)); - t.Add(new Temperature("Device 1", 20)); - t.Add(new Temperature("PECI 0 Calibrated", 21)); - t.Add(new Temperature("PECI 1 Calibrated", 22)); - t.Add(new Temperature("Virtual", 23)); - - fanControlNames = new[] {"Chassis Fan 1", "CPU Fan", "Chassis Fan 2", - "Chassis Fan 3", "High Amp Fan", "W_PUMP+", "AIO Pump"}; - System.Diagnostics.Debug.Assert(fanControlNames.Length == superIO.Fans.Length, - $"Expected {fanControlNames.Length} fan register in the SuperIO chip"); - System.Diagnostics.Debug.Assert(superIO.Fans.Length == superIO.Controls.Length, - "Expected counts of cans controls and fan speed registers to be equal"); - - for (int i = 0; i < fanControlNames.Length; i++) - f.Add(new Fan(fanControlNames[i], i)); - - for (int i = 0; i < fanControlNames.Length; i++) - c.Add(new Ctrl(fanControlNames[i], i)); - - break; - - case Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL: //NCT6798D - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("AVSB", 2, 34, 34)); - v.Add(new Voltage("3VCC", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); - v.Add(new Voltage("IVR Atom L2 Cluster #1", 5)); - v.Add(new Voltage("Voltage #7", 6)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9, 1, 1)); - v.Add(new Voltage("Voltage #11", 10)); - v.Add(new Voltage("IVR Atom L2 Cluster #0", 11, 1, 1)); - v.Add(new Voltage("PCH", 12)); - v.Add(new Voltage("Voltage #14", 13)); - v.Add(new Voltage("Voltage #15", 14)); - - t.Add(new Temperature("Temperature #1", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Motherboard", 2)); - //t.Add(new Temperature("Temperature 03", 3)); - t.Add(new Temperature("Temperature #4", 4)); - t.Add(new Temperature("Temperature #5", 5)); - t.Add(new Temperature("Temperature #6", 6)); - t.Add(new Temperature("Temperature #7", 7)); - //t.Add(new Temperature("Temperature 08", 8)); - //t.Add(new Temperature("Temperature 09", 9)); - //t.Add(new Temperature("Temperature 10", 10)); - //t.Add(new Temperature("Temperature 11", 11)); - t.Add(new Temperature("PCH", 12)); - //t.Add(new Temperature("Temperature 13", 13)); - //t.Add(new Temperature("Temperature 14", 14)); - //t.Add(new Temperature("Temperature 15", 15)); - //t.Add(new Temperature("Temperature 16", 16)); - //t.Add(new Temperature("Temperature 17", 17)); - //t.Add(new Temperature("Temperature 18", 18)); - //t.Add(new Temperature("Temperature 19", 19)); - //t.Add(new Temperature("Temperature 20", 20)); - t.Add(new Temperature("Temperature #9", 21)); - - fanControlNames = new[] { "Chassis Fan 1", "CPU Fan", "Radiator Fan 1", "Radiator Fan 2", "Chassis Fan 2", "Water Pump 1", "Water Pump 2" }; - System.Diagnostics.Debug.Assert(fanControlNames.Length == superIO.Fans.Length, - $"Expected {fanControlNames.Length} fan register in the SuperIO chip"); - System.Diagnostics.Debug.Assert(superIO.Fans.Length == superIO.Controls.Length, - "Expected counts of fan controls and fan speed registers to be equal"); - - for (int i = 0; i < fanControlNames.Length; i++) - f.Add(new Fan(fanControlNames[i], i)); - - for (int i = 0; i < fanControlNames.Length; i++) - c.Add(new Ctrl(fanControlNames[i], i)); - - break; - - case Model.ROG_STRIX_B550_I_GAMING: //NCT6798D - v.Add(new Voltage("Vcore", 0, 10, 10)); - v.Add(new Voltage("+5V", 1, 4, 1)); //Probably not updating properly - v.Add(new Voltage("AVCC", 2, 10, 10)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); //Probably not updating properly - //v.Add(new Voltage("#Unused #5", 5, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #6", 6, 0, 1, 0, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - //v.Add(new Voltage("#Unused #9", 9, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #10", 10, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #11", 11, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #12", 12, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #13", 13, 0, 1, 0, true)); - //v.Add(new Voltage("#Unused #14", 14, 0, 1, 0, true)); - - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Motherboard", 2)); - //t.Add(new Temperature("AUX 0", 3)); //No software from Asus reports this temperature ~82C - //t.Add(new Temperature("#Unused 4", 4)); - //t.Add(new Temperature("#Unused 5", 5)); - //t.Add(new Temperature("#Unused 6", 6)); - //t.Add(new Temperature("#Unused 7", 7)); - //t.Add(new Temperature("#Unused 8", 8)); - //t.Add(new Temperature("#Unused 9", 9)); - //t.Add(new Temperature("#Unused 10", 10)); - t.Add(new Temperature("PCH Chip CPU Max", 11)); - t.Add(new Temperature("PCH Chip", 12)); - t.Add(new Temperature("PCH CPU", 13)); - t.Add(new Temperature("PCH MCH", 14)); - t.Add(new Temperature("Agent 0 DIMM 0", 15)); - //t.Add(new Temperature("Agent 0 DIMM 1", 16)); - t.Add(new Temperature("Agent 1 DIMM 0", 17)); - //t.Add(new Temperature("Agent 1 DIMM 1", 18)); - t.Add(new Temperature("Device 0", 19)); - t.Add(new Temperature("Device 1", 20)); - t.Add(new Temperature("PECI 0 Calibrated", 21)); - t.Add(new Temperature("PECI 1 Calibrated", 22)); - t.Add(new Temperature("Virtual", 23)); - - for (int i = 0; i < superIO.Fans.Length; i++) - { - switch (i) - { - case 0: - f.Add(new Fan("Chassis Fan", 0)); - break; - case 1: - f.Add(new Fan("CPU Fan", 1)); - break; - case 4: - f.Add(new Fan("AIO Pump", 4)); - break; - } - } - - for (int i = 0; i < superIO.Controls.Length; i++) - { - switch (i) - { - case 0: - c.Add(new Ctrl("Chassis Fan", 0)); - break; - case 1: - c.Add(new Ctrl("CPU Fan", 1)); - break; - case 4: - c.Add(new Ctrl("AIO Pump", 4)); - break; - } - } - - break; - - case Model.ROG_ZENITH_II_EXTREME: // NCT6798D - // Voltage = value + (value - Vf) * Ri / Rf. - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 6, 1)); - v.Add(new Voltage("DIMM Voltage CD", 11, 10, 10)); - v.Add(new Voltage("DIMM Voltage AB", 13)); - v.Add(new Voltage("1.8V PPL Voltage", 14)); - - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Motherboard", 2)); - t.Add(new Temperature("Temperature #3", 3)); - t.Add(new Temperature("Temperature #4", 4)); - t.Add(new Temperature("Temperature #5", 5)); - t.Add(new Temperature("Temperature #6", 6)); - t.Add(new Temperature("Temperature #7", 7)); - t.Add(new Temperature("Temperature #21", 21)); - - for (int i = 0; i < superIO.Fans.Length; i++) - { - switch (i) - { - case 0: f.Add(new Fan("Chassis Fan", 0)); break; - case 1: f.Add(new Fan("CPU Fan", 1)); break; - case 2: f.Add(new Fan("CPU Optional Fan", 2)); break; - case 4: f.Add(new Fan("AIO Pump", 4)); break; - } - } - - for (int i = 0; i < superIO.Controls.Length; i++) - { - switch (i) - { - case 0: c.Add(new Ctrl("Chassis Fan", 0)); break; - case 1: c.Add(new Ctrl("CPU Fan", 1)); break; - case 2: c.Add(new Ctrl("CPU Optional Fan", 2)); break; - case 4: c.Add(new Ctrl("AIO Pump", 4)); break; - } - } - - break; - - case Model.ROG_STRIX_X570_I_GAMING: //NCT6798D - v.Add(new Voltage("Vcore", 0, 10, 10)); - v.Add(new Voltage("+5V", 1, 4, 1)); //Probably not updating properly - v.Add(new Voltage("AVCC", 2, 10, 10)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); //Probably not updating properly - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("Motherboard", 2)); - t.Add(new Temperature("Temperature #3", 3)); - t.Add(new Temperature("Temperature #4", 4)); - t.Add(new Temperature("Temperature #5", 5)); - t.Add(new Temperature("Temperature #6", 6)); - t.Add(new Temperature("Temperature #7", 7)); - t.Add(new Temperature("Temperature #21", 21)); - - for (int i = 0; i < superIO.Fans.Length; i++) - { - switch (i) - { - case 0: - f.Add(new Fan("Chassis Fan", 0)); - break; - case 1: - f.Add(new Fan("CPU Fan", 1)); - break; - case 4: - f.Add(new Fan("AIO Pump", 4)); - break; - } - } - - for (int i = 0; i < superIO.Controls.Length; i++) - { - switch (i) - { - case 0: - c.Add(new Ctrl("Chassis Fan", 0)); - break; - case 1: - c.Add(new Ctrl("CPU Fan", 1)); - break; - case 4: - c.Add(new Ctrl("AIO Pump", 4)); - break; - } - } - break; - - case Model.ROG_STRIX_B550_F_GAMING_WIFI: // NCT6798D-R - v.Add(new Voltage("Vcore", 0, 2, 2)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU Core", 0)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Temperature #1", 1)); - t.Add(new Temperature("Temperature #2", 2)); - t.Add(new Temperature("Temperature #3", 3)); - t.Add(new Temperature("Temperature #4", 4)); - t.Add(new Temperature("Temperature #5", 5)); - t.Add(new Temperature("Temperature #6", 6)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - case Manufacturer.MSI: - switch (model) - { - case Model.B360M_PRO_VDH: // NCT6797D - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); - //v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("CPU I/O", 6)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("CPU SA", 10)); - //v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("NB/SoC", 12)); - v.Add(new Voltage("DIMM", 13, 1, 1)); - //v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("Motherboard", 2)); - t.Add(new Temperature("Temperature #1", 5)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("System Fan #1", 2)); - f.Add(new Fan("System Fan #2", 3)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("System Fan #1", 2)); - c.Add(new Ctrl("System Fan #2", 3)); - - break; - - case Model.B450A_PRO: // NCT6797D - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); - //v.Add(new Voltage("Voltage #6", 5, false)); - //v.Add(new Voltage("CPU I/O", 6)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("CPU SA", 10)); - //v.Add(new Voltage("Voltage #12", 11, false)); - v.Add(new Voltage("NB/SoC", 12)); - v.Add(new Voltage("DIMM", 13, 1, 1)); - //v.Add(new Voltage("Voltage #15", 14, false)); - //t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("CPU", 1)); - t.Add(new Temperature("System", 2)); - t.Add(new Temperature("VRM MOS", 3)); - t.Add(new Temperature("PCH", 5)); - t.Add(new Temperature("SMBus 0", 8)); - f.Add(new Fan("Pump Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("System Fan #1", 2)); - f.Add(new Fan("System Fan #2", 3)); - f.Add(new Fan("System Fan #3", 4)); - f.Add(new Fan("System Fan #4", 5)); - c.Add(new Ctrl("Pump Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("System Fan #1", 2)); - c.Add(new Ctrl("System Fan #2", 3)); - c.Add(new Ctrl("System Fan #3", 4)); - c.Add(new Ctrl("System Fan #4", 5)); - - break; - - case Model.Z270_PC_MATE: // NCT6795D - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+5V", 1, 4, 1)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+12V", 4, 11, 1)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("CPU I/O", 6)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("CPU SA", 10)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("PCH", 12)); - v.Add(new Voltage("DIMM", 13, 1, 1)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("Motherboard", 2)); - f.Add(new Fan("Pump Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("System Fan #1", 2)); - f.Add(new Fan("System Fan #2", 3)); - f.Add(new Fan("System Fan #3", 4)); - f.Add(new Fan("System Fan #4", 5)); - c.Add(new Ctrl("Pump Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("System Fan #1", 2)); - c.Add(new Ctrl("System Fan #2", 3)); - c.Add(new Ctrl("System Fan #3", 4)); - c.Add(new Ctrl("System Fan #4", 5)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Temperature #1", 1)); - t.Add(new Temperature("Temperature #2", 2)); - t.Add(new Temperature("Temperature #3", 3)); - t.Add(new Temperature("Temperature #4", 4)); - t.Add(new Temperature("Temperature #5", 5)); - t.Add(new Temperature("Temperature #6", 6)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("VTT", 9)); - v.Add(new Voltage("Voltage #11", 10, true)); - v.Add(new Voltage("Voltage #12", 11, true)); - v.Add(new Voltage("Voltage #13", 12, true)); - v.Add(new Voltage("Voltage #14", 13, true)); - v.Add(new Voltage("Voltage #15", 14, true)); - t.Add(new Temperature("CPU Core", 0)); - t.Add(new Temperature("Temperature #1", 1)); - t.Add(new Temperature("Temperature #2", 2)); - t.Add(new Temperature("Temperature #3", 3)); - t.Add(new Temperature("Temperature #4", 4)); - t.Add(new Temperature("Temperature #5", 5)); - t.Add(new Temperature("Temperature #6", 6)); - - for (int i = 0; i < superIO.Fans.Length; i++) - f.Add(new Fan("Fan #" + (i + 1), i)); - - for (int i = 0; i < superIO.Controls.Length; i++) - c.Add(new Ctrl("Fan #" + (i + 1), i)); - - break; - } - } - - private static void GetWinbondConfigurationEhf(Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) - { - switch (manufacturer) - { - case Manufacturer.ASRock: - switch (model) - { - case Model.AOD790GX_128M: // W83627EHF - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 4, 10, 10)); - v.Add(new Voltage("+5V", 5, 20, 10)); - v.Add(new Voltage("+12V", 6, 28, 5)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 2)); - f.Add(new Fan("CPU Fan", 0)); - f.Add(new Fan("Chassis Fan", 1)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("Voltage #10", 9, true)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("System Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Auxiliary Fan", 2)); - f.Add(new Fan("CPU Fan #2", 3)); - f.Add(new Fan("Auxiliary Fan #2", 4)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - } - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - v.Add(new Voltage("Voltage #10", 9, true)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("System Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Auxiliary Fan", 2)); - f.Add(new Fan("CPU Fan #2", 3)); - f.Add(new Fan("Auxiliary Fan #2", 4)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - } - } - - private static void GetWinbondConfigurationHg(Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) - { - switch (manufacturer) - { - case Manufacturer.ASRock: - switch (model) - { - case Model._880GMH_USB3: // W83627DHG-P - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+5V", 5, 15, 7.5f)); - v.Add(new Voltage("+12V", 6, 56, 10)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 2)); - f.Add(new Fan("Chassis Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Power Fan", 2)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("System Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Auxiliary Fan", 2)); - f.Add(new Fan("CPU Fan #2", 3)); - f.Add(new Fan("Auxiliary Fan #2", 4)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - } - - break; - case Manufacturer.ASUS: - switch (model) - { - case Model.P6T: // W83667HG - case Model.P6X58D_E: // W83667HG - case Model.RAMPAGE_II_GENE: // W83667HG - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+12V", 1, 11.5f, 1.91f)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+5V", 4, 15, 7.5f)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 2)); - f.Add(new Fan("Chassis Fan #1", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("Chassis Fan #2", 3)); - f.Add(new Fan("Chassis Fan #3", 4)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - - case Model.RAMPAGE_EXTREME: // W83667HG - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("+12V", 1, 12, 2)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("+5V", 4, 15, 7.5f)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Motherboard", 2)); - f.Add(new Fan("Chassis Fan #1", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Power Fan", 2)); - f.Add(new Fan("Chassis Fan #2", 3)); - f.Add(new Fan("Chassis Fan #3", 4)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("System Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Auxiliary Fan", 2)); - f.Add(new Fan("CPU Fan #2", 3)); - f.Add(new Fan("Auxiliary Fan #2", 4)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - } - - break; - - default: - v.Add(new Voltage("Vcore", 0)); - v.Add(new Voltage("Voltage #2", 1, true)); - v.Add(new Voltage("AVCC", 2, 34, 34)); - v.Add(new Voltage("+3.3V", 3, 34, 34)); - v.Add(new Voltage("Voltage #5", 4, true)); - v.Add(new Voltage("Voltage #6", 5, true)); - v.Add(new Voltage("Voltage #7", 6, true)); - v.Add(new Voltage("3VSB", 7, 34, 34)); - v.Add(new Voltage("VBat", 8, 34, 34)); - t.Add(new Temperature("CPU", 0)); - t.Add(new Temperature("Auxiliary", 1)); - t.Add(new Temperature("System", 2)); - f.Add(new Fan("System Fan", 0)); - f.Add(new Fan("CPU Fan", 1)); - f.Add(new Fan("Auxiliary Fan", 2)); - f.Add(new Fan("CPU Fan #2", 3)); - f.Add(new Fan("Auxiliary Fan #2", 4)); - c.Add(new Ctrl("System Fan", 0)); - c.Add(new Ctrl("CPU Fan", 1)); - c.Add(new Ctrl("Auxiliary Fan", 2)); - - break; - } - } - - public override string GetReport() - { - return _superIO.GetReport(); - } - - public override void Update() - { - _superIO.Update(); - - foreach (Sensor sensor in _voltages) - { - float? value = _readVoltage(sensor.Index); - if (value.HasValue) - { - sensor.Value = value + ((value - sensor.Parameters[2].Value) * sensor.Parameters[0].Value / sensor.Parameters[1].Value); - ActivateSensor(sensor); + } + + break; + case Model.Z77Pro4M: //NCT6776F + v.Add(new Voltage("Vcore", 0, 0, 1)); + v.Add(new Voltage("+12V", 1, 56, 10)); + v.Add(new Voltage("AVCC", 2, 10, 10)); + v.Add(new Voltage("+3.3V", 3, 10, 10)); + //v.Add(new Voltage("#Unused #4", 4, 0, 1, 0, true)); + v.Add(new Voltage("+5V", 5, 20, 10)); + //v.Add(new Voltage("#Unused #6", 6, 0, 1, 0, true)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Auxiliary", 2)); + t.Add(new Temperature("Motherboard", 3)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Temperature #1", 1)); + t.Add(new Temperature("Temperature #2", 2)); + t.Add(new Temperature("Temperature #3", 3)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; } - } - foreach (Sensor sensor in _temperatures) - { - float? value = _readTemperature(sensor.Index); - if (value.HasValue) + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Temperature #1", 1)); + t.Add(new Temperature("Temperature #2", 2)); + t.Add(new Temperature("Temperature #3", 3)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + } + + private static void GetNuvotonConfigurationD(ISuperIO superIO, Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + { + switch (manufacturer) + { + case Manufacturer.ASRock: + switch (model) { - sensor.Value = value + sensor.Parameters[0].Value; - ActivateSensor(sensor); - } - } + case Model.A320M_HDV: //NCT6779D + v.Add(new Voltage("Vcore", 0, 10, 10)); + v.Add(new Voltage("Chipset 1.05V", 1, 0, 1)); + v.Add(new Voltage("AVCC", 2, 10, 10)); + v.Add(new Voltage("+3.3V", 3, 10, 10)); + v.Add(new Voltage("+12V", 4, 56, 10)); + v.Add(new Voltage("VcoreRef", 5, 0, 1)); + v.Add(new Voltage("DIMM", 6, 0, 1)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + //v.Add(new Voltage("#Unused #9", 9, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #10", 10, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #11", 11, 34, 34, 0, true)); + v.Add(new Voltage("+5V", 12, 20, 10)); + //v.Add(new Voltage("#Unused #13", 13, 10, 10, 0, true)); + //v.Add(new Voltage("#Unused #14", 14, 0, 1, 0, true)); - foreach (Sensor sensor in _fans) - { - float? value = _readFan(sensor.Index); - if (value.HasValue) + //t.Add(new Temperature("#Unused #0", 0)); + //t.Add(new Temperature("#Unused #1", 1)); + t.Add(new Temperature("Motherboard", 2)); + //t.Add(new Temperature("#Unused #3", 3)); + //t.Add(new Temperature("#Unused #4", 4)); + t.Add(new Temperature("Auxiliary", 5)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.AB350_Pro4: //NCT6779D + case Model.AB350M_Pro4: + case Model.AB350M: + case Model.Fatal1ty_AB350_Gaming_K4: + case Model.AB350M_HDV: + case Model.B450_Steel_Legend: + case Model.B450M_Steel_Legend: + case Model.B450_Pro4: + case Model.B450M_Pro4: + v.Add(new Voltage("Vcore", 0, 10, 10)); + //v.Add(new Voltage("#Unused", 1, 0, 1, 0, true)); + v.Add(new Voltage("AVCC", 2, 10, 10)); + v.Add(new Voltage("+3.3V", 3, 10, 10)); + v.Add(new Voltage("+12V", 4, 28, 5)); + v.Add(new Voltage("Vcore Refin", 5, 0, 1)); + //v.Add(new Voltage("#Unused #6", 6, 0, 1, 0, true)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 34, 34)); + //v.Add(new Voltage("#Unused #9", 9, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #10", 10, 0, 1, 0, true)); + v.Add(new Voltage("Chipset 1.05V", 11, 0, 1)); + v.Add(new Voltage("+5V", 12, 20, 10)); + //v.Add(new Voltage("#Unused #13", 13, 0, 1, 0, true)); + v.Add(new Voltage("+1.8V", 14, 0, 1)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Motherboard", 2)); + t.Add(new Temperature("Auxiliary", 3)); + t.Add(new Temperature("VRM", 4)); + t.Add(new Temperature("AUXTIN2", 5)); + //t.Add(new Temperature("Temperature #6", 6)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.X399_Phantom_Gaming_6: //NCT6779D + v.Add(new Voltage("Vcore", 0, 10, 10)); + v.Add(new Voltage("Chipset 1.05V", 1, 0, 1)); + v.Add(new Voltage("AVCC", 2, 10, 10)); + v.Add(new Voltage("+3.3V", 3, 10, 10)); + v.Add(new Voltage("+12V", 4, 56, 10)); + v.Add(new Voltage("VDDCR_SOC", 5, 0, 1)); + v.Add(new Voltage("DIMM", 6, 0, 1)); + v.Add(new Voltage("3VSB", 7, 10, 10)); + v.Add(new Voltage("VBat", 8, 10, 10)); + //v.Add(new Voltage("#Unused", 9, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused", 10, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused", 11, 0, 1, 0, true)); + v.Add(new Voltage("+5V", 12, 20, 10)); + v.Add(new Voltage("+1.8V", 13, 10, 10)); + //v.Add(new Voltage("unused", 14, 34, 34, 0, true)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Motherboard", 1)); + t.Add(new Temperature("Auxiliary", 2)); + t.Add(new Temperature("Chipset", 3)); + t.Add(new Temperature("Core VRM", 4)); + t.Add(new Temperature("Core SoC", 5)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.X570_Taichi: + v.Add(new Voltage("Vcore", 0, 10, 10)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + + t.Add(new Temperature("Motherboard", 2)); + t.Add(new Temperature("CPU", 8)); + t.Add(new Temperature("SB (Chipset)", 9)); + + f.Add(new Fan("Chassis #3", 0)); + f.Add(new Fan("CPU #1", 1)); + f.Add(new Fan("CPU #2", 2)); + f.Add(new Fan("Chassis #1", 3)); + f.Add(new Fan("Chassis #2", 4)); + f.Add(new Fan("SB Fan", 5)); + f.Add(new Fan("Chassis #4", 6)); + + c.Add(new Ctrl("Chassis #3", 0)); + c.Add(new Ctrl("CPU #1", 1)); + c.Add(new Ctrl("CPU #2", 2)); + c.Add(new Ctrl("Chassis #1", 3)); + c.Add(new Ctrl("Chassis #2", 4)); + c.Add(new Ctrl("SB Fan", 5)); + c.Add(new Ctrl("Chassis #4", 6)); + + break; + + case Model.X570_Phantom_Gaming_ITX: + v.Add(new Voltage("+12V", 0)); + v.Add(new Voltage("+5V", 1)); + v.Add(new Voltage("Vcore", 2)); + v.Add(new Voltage("Voltage #1", 3)); + v.Add(new Voltage("DIMM", 4)); + v.Add(new Voltage("CPU I/O", 5)); + v.Add(new Voltage("CPU SA", 6)); + v.Add(new Voltage("Voltage #2", 7)); + v.Add(new Voltage("AVCC3", 8)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("VRef", 10)); + v.Add(new Voltage("VSB", 11)); + v.Add(new Voltage("AVSB", 12)); + v.Add(new Voltage("VBat", 13)); + + t.Add(new Temperature("Motherboard", 0)); + //t.Add(new Temperature("System", 1)); //Unused + t.Add(new Temperature("CPU", 2)); + t.Add(new Temperature("SB (Chipset)", 3)); + f.Add(new Fan("CPU Fan #1", 0)); //CPU_FAN1 + f.Add(new Fan("Chassis Fan #1", 1)); //CHA_FAN1/WP + f.Add(new Fan("CPU Fan #2", 2)); //CPU_FAN2 (WP) + f.Add(new Fan("Chipset Fan", 3)); + + c.Add(new Ctrl("CPU Fan #1", 0)); + c.Add(new Ctrl("Chassis Fan", 1)); + c.Add(new Ctrl("CPU Fan #2", 2)); + c.Add(new Ctrl("Chipset Fan", 3)); + break; + + default: + v.Add(new Voltage("Vcore", 0, 10, 10)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Temperature #1", 1)); + t.Add(new Temperature("Temperature #2", 2)); + t.Add(new Temperature("Temperature #3", 3)); + t.Add(new Temperature("Temperature #4", 4)); + t.Add(new Temperature("Temperature #5", 5)); + t.Add(new Temperature("Temperature #6", 6)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + case Manufacturer.ASUS: + string[] fanControlNames; + switch (model) { - sensor.Value = value; - ActivateSensor(sensor); + case Model.P8Z77_V: // NCT6779D + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("Motherboard", 2)); + f.Add(new Fan("Chassis Fan #1", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Chassis Fan #2", 2)); + f.Add(new Fan("Chassis Fan #3", 3)); + c.Add(new Ctrl("Chassis Fan #1", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Chassis Fan #2", 2)); + c.Add(new Ctrl("Chassis Fan #3", 3)); + + break; + + case Model.ROG_MAXIMUS_X_APEX: // NCT6793D + v.Add(new Voltage("Vcore", 0, 2, 2)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("AVSB", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("CPU GFX", 6, 2, 2)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("DIMM", 10, 1, 1)); + v.Add(new Voltage("VCCSA", 11)); + v.Add(new Voltage("PCH Core", 12)); + v.Add(new Voltage("CPU PLLs", 13)); + v.Add(new Voltage("CPU VCCIO/IMC", 14)); + t.Add(new Temperature("CPU (PECI)", 0)); + t.Add(new Temperature("T2", 1)); + t.Add(new Temperature("T1", 2)); + t.Add(new Temperature("CPU", 3)); + t.Add(new Temperature("PCH", 4)); + t.Add(new Temperature("Temperature #4", 5)); + t.Add(new Temperature("Temperature #5", 6)); + f.Add(new Fan("Chassis Fan #1", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Chassis Fan #2", 2)); + f.Add(new Fan("Chassis Fan #3", 3)); + f.Add(new Fan("AIO Pump", 4)); + c.Add(new Ctrl("Chassis Fan #1", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Chassis Fan #2", 2)); + c.Add(new Ctrl("Chassis Fan #3", 3)); + c.Add(new Ctrl("AIO Pump", 4)); + + break; + + case Model.Z170_A: //NCT6793D + v.Add(new Voltage("Vcore", 0, 2, 2)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("AVSB", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); + v.Add(new Voltage("Voltage #6", 5, 0, 1, 0, true)); + v.Add(new Voltage("CPU GFX", 6, 2, 2)); + v.Add(new Voltage("3VSB_ATX", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("DIMM", 10, 1, 1)); + v.Add(new Voltage("VCCSA", 11)); + v.Add(new Voltage("PCH Core", 12)); + v.Add(new Voltage("CPU PLLs", 13)); + v.Add(new Voltage("CPU VCCIO/IMC", 14)); + t.Add(new Temperature("CPU (PECI)", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Motherboard", 2)); + t.Add(new Temperature("CPU", 3)); + t.Add(new Temperature("PCH", 4)); + t.Add(new Temperature("Temperature #4", 5)); + t.Add(new Temperature("Temperature #5", 6)); + + // CPU Fan Optional uses the same fancontrol as CPU Fan. + // Water Pump speed can only be read from the EC. + string[] fanNames = { "Chassis Fan 1", "CPU Fan", "Chassis Fan 2", "Chassis Fan 3", "Chassis Fan 4", "CPU Fan Optional" }; + fanControlNames = new[] { "Chassis Fan 1", "CPU Fan", "Chassis Fan 2", "Chassis Fan 3", "Chassis Fan 4", "Water Pump" }; + + for (int i = 0; i < fanNames.Length; i++) + f.Add(new Fan(fanNames[i], i)); + + for (int i = 0; i < fanControlNames.Length; i++) + c.Add(new Ctrl(fanControlNames[i], i)); + + break; + + case Model.TUF_GAMING_B550M_PLUS_WIFI: //NCT6798D + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("PECI 0", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("System", 2)); + t.Add(new Temperature("AUX 0", 3)); + t.Add(new Temperature("AUX 1", 4)); + t.Add(new Temperature("AUX 2", 5)); + t.Add(new Temperature("AUX 3", 6)); + t.Add(new Temperature("AUX 4", 7)); + t.Add(new Temperature("SMBus 0", 8)); + t.Add(new Temperature("SMBus 1", 9)); + t.Add(new Temperature("PECI 1", 10)); + t.Add(new Temperature("PCH Chip CPU Max", 11)); + t.Add(new Temperature("PCH Chip", 12)); + t.Add(new Temperature("PCH CPU", 13)); + t.Add(new Temperature("PCH MCH", 14)); + t.Add(new Temperature("Agent 0 DIMM 0", 15)); + t.Add(new Temperature("Agent 0 DIMM 1", 16)); + t.Add(new Temperature("Agent 1 DIMM 0", 17)); + t.Add(new Temperature("Agent 1 DIMM 1", 18)); + t.Add(new Temperature("Device 0", 19)); + t.Add(new Temperature("Device 1", 20)); + t.Add(new Temperature("PECI 0 Calibrated", 21)); + t.Add(new Temperature("PECI 1 Calibrated", 22)); + t.Add(new Temperature("Virtual", 23)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + case Model.ROG_CROSSHAIR_VIII_HERO: // NCT6798D + case Model.ROG_CROSSHAIR_VIII_HERO_WIFI: // NCT6798D + case Model.ROG_CROSSHAIR_VIII_DARK_HERO: // NCT6798D + case Model.ROG_CROSSHAIR_VIII_FORMULA: // NCT6798D + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("CPU SoC", 6)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("DRAM", 13)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("PECI 0", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Motherboard", 2)); + t.Add(new Temperature("AUX 0", 3)); + t.Add(new Temperature("AUX 1", 4)); + t.Add(new Temperature("AUX 2", 5)); + t.Add(new Temperature("AUX 3", 6)); + t.Add(new Temperature("AUX 4", 7)); + t.Add(new Temperature("SMBus 0", 8)); + t.Add(new Temperature("SMBus 1", 9)); + t.Add(new Temperature("PECI 1", 10)); + t.Add(new Temperature("PCH Chip CPU Max", 11)); + t.Add(new Temperature("PCH Chip", 12)); + t.Add(new Temperature("PCH CPU", 13)); + t.Add(new Temperature("PCH MCH", 14)); + t.Add(new Temperature("Agent 0 DIMM 0", 15)); + t.Add(new Temperature("Agent 0 DIMM 1", 16)); + t.Add(new Temperature("Agent 1 DIMM 0", 17)); + t.Add(new Temperature("Agent 1 DIMM 1", 18)); + t.Add(new Temperature("Device 0", 19)); + t.Add(new Temperature("Device 1", 20)); + t.Add(new Temperature("PECI 0 Calibrated", 21)); + t.Add(new Temperature("PECI 1 Calibrated", 22)); + t.Add(new Temperature("Virtual", 23)); + + fanControlNames = new[] {"Chassis Fan 1", "CPU Fan", "Chassis Fan 2", + "Chassis Fan 3", "High Amp Fan", "W_PUMP+", "AIO Pump"}; + System.Diagnostics.Debug.Assert(fanControlNames.Length == superIO.Fans.Length, + $"Expected {fanControlNames.Length} fan register in the SuperIO chip"); + System.Diagnostics.Debug.Assert(superIO.Fans.Length == superIO.Controls.Length, + "Expected counts of cans controls and fan speed registers to be equal"); + + for (int i = 0; i < fanControlNames.Length; i++) + f.Add(new Fan(fanControlNames[i], i)); + + for (int i = 0; i < fanControlNames.Length; i++) + c.Add(new Ctrl(fanControlNames[i], i)); + + break; + + case Model.ROG_MAXIMUS_Z690_EXTREME_GLACIAL: //NCT6798D + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("AVSB", 2, 34, 34)); + v.Add(new Voltage("3VCC", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); + v.Add(new Voltage("IVR Atom L2 Cluster #1", 5)); + v.Add(new Voltage("Voltage #7", 6)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9, 1, 1)); + v.Add(new Voltage("Voltage #11", 10)); + v.Add(new Voltage("IVR Atom L2 Cluster #0", 11, 1, 1)); + v.Add(new Voltage("PCH", 12)); + v.Add(new Voltage("Voltage #14", 13)); + v.Add(new Voltage("Voltage #15", 14)); + + t.Add(new Temperature("Temperature #1", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Motherboard", 2)); + //t.Add(new Temperature("Temperature 03", 3)); + t.Add(new Temperature("Temperature #4", 4)); + t.Add(new Temperature("Temperature #5", 5)); + t.Add(new Temperature("Temperature #6", 6)); + t.Add(new Temperature("Temperature #7", 7)); + //t.Add(new Temperature("Temperature 08", 8)); + //t.Add(new Temperature("Temperature 09", 9)); + //t.Add(new Temperature("Temperature 10", 10)); + //t.Add(new Temperature("Temperature 11", 11)); + t.Add(new Temperature("PCH", 12)); + //t.Add(new Temperature("Temperature 13", 13)); + //t.Add(new Temperature("Temperature 14", 14)); + //t.Add(new Temperature("Temperature 15", 15)); + //t.Add(new Temperature("Temperature 16", 16)); + //t.Add(new Temperature("Temperature 17", 17)); + //t.Add(new Temperature("Temperature 18", 18)); + //t.Add(new Temperature("Temperature 19", 19)); + //t.Add(new Temperature("Temperature 20", 20)); + t.Add(new Temperature("Temperature #9", 21)); + + fanControlNames = new[] { "Chassis Fan 1", "CPU Fan", "Radiator Fan 1", "Radiator Fan 2", "Chassis Fan 2", "Water Pump 1", "Water Pump 2" }; + System.Diagnostics.Debug.Assert(fanControlNames.Length == superIO.Fans.Length, + $"Expected {fanControlNames.Length} fan register in the SuperIO chip"); + System.Diagnostics.Debug.Assert(superIO.Fans.Length == superIO.Controls.Length, + "Expected counts of fan controls and fan speed registers to be equal"); + + for (int i = 0; i < fanControlNames.Length; i++) + f.Add(new Fan(fanControlNames[i], i)); + + for (int i = 0; i < fanControlNames.Length; i++) + c.Add(new Ctrl(fanControlNames[i], i)); + + break; + + case Model.ROG_STRIX_B550_I_GAMING: //NCT6798D + v.Add(new Voltage("Vcore", 0, 10, 10)); + v.Add(new Voltage("+5V", 1, 4, 1)); //Probably not updating properly + v.Add(new Voltage("AVCC", 2, 10, 10)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); //Probably not updating properly + //v.Add(new Voltage("#Unused #5", 5, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #6", 6, 0, 1, 0, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + //v.Add(new Voltage("#Unused #9", 9, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #10", 10, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #11", 11, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #12", 12, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #13", 13, 0, 1, 0, true)); + //v.Add(new Voltage("#Unused #14", 14, 0, 1, 0, true)); + + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Motherboard", 2)); + //t.Add(new Temperature("AUX 0", 3)); //No software from Asus reports this temperature ~82C + //t.Add(new Temperature("#Unused 4", 4)); + //t.Add(new Temperature("#Unused 5", 5)); + //t.Add(new Temperature("#Unused 6", 6)); + //t.Add(new Temperature("#Unused 7", 7)); + //t.Add(new Temperature("#Unused 8", 8)); + //t.Add(new Temperature("#Unused 9", 9)); + //t.Add(new Temperature("#Unused 10", 10)); + t.Add(new Temperature("PCH Chip CPU Max", 11)); + t.Add(new Temperature("PCH Chip", 12)); + t.Add(new Temperature("PCH CPU", 13)); + t.Add(new Temperature("PCH MCH", 14)); + t.Add(new Temperature("Agent 0 DIMM 0", 15)); + //t.Add(new Temperature("Agent 0 DIMM 1", 16)); + t.Add(new Temperature("Agent 1 DIMM 0", 17)); + //t.Add(new Temperature("Agent 1 DIMM 1", 18)); + t.Add(new Temperature("Device 0", 19)); + t.Add(new Temperature("Device 1", 20)); + t.Add(new Temperature("PECI 0 Calibrated", 21)); + t.Add(new Temperature("PECI 1 Calibrated", 22)); + t.Add(new Temperature("Virtual", 23)); + + for (int i = 0; i < superIO.Fans.Length; i++) + { + switch (i) + { + case 0: + f.Add(new Fan("Chassis Fan", 0)); + break; + case 1: + f.Add(new Fan("CPU Fan", 1)); + break; + case 4: + f.Add(new Fan("AIO Pump", 4)); + break; + } + } + + for (int i = 0; i < superIO.Controls.Length; i++) + { + switch (i) + { + case 0: + c.Add(new Ctrl("Chassis Fan", 0)); + break; + case 1: + c.Add(new Ctrl("CPU Fan", 1)); + break; + case 4: + c.Add(new Ctrl("AIO Pump", 4)); + break; + } + } + + break; + + case Model.ROG_ZENITH_II_EXTREME: // NCT6798D + // Voltage = value + (value - Vf) * Ri / Rf. + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 6, 1)); + v.Add(new Voltage("DIMM Voltage CD", 11, 10, 10)); + v.Add(new Voltage("DIMM Voltage AB", 13)); + v.Add(new Voltage("1.8V PPL Voltage", 14)); + + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Motherboard", 2)); + t.Add(new Temperature("Temperature #3", 3)); + t.Add(new Temperature("Temperature #4", 4)); + t.Add(new Temperature("Temperature #5", 5)); + t.Add(new Temperature("Temperature #6", 6)); + t.Add(new Temperature("Temperature #7", 7)); + t.Add(new Temperature("Temperature #21", 21)); + + for (int i = 0; i < superIO.Fans.Length; i++) + { + switch (i) + { + case 0: f.Add(new Fan("Chassis Fan", 0)); break; + case 1: f.Add(new Fan("CPU Fan", 1)); break; + case 2: f.Add(new Fan("CPU Optional Fan", 2)); break; + case 4: f.Add(new Fan("AIO Pump", 4)); break; + } + } + + for (int i = 0; i < superIO.Controls.Length; i++) + { + switch (i) + { + case 0: c.Add(new Ctrl("Chassis Fan", 0)); break; + case 1: c.Add(new Ctrl("CPU Fan", 1)); break; + case 2: c.Add(new Ctrl("CPU Optional Fan", 2)); break; + case 4: c.Add(new Ctrl("AIO Pump", 4)); break; + } + } + + break; + + case Model.ROG_STRIX_X570_I_GAMING: //NCT6798D + v.Add(new Voltage("Vcore", 0, 10, 10)); + v.Add(new Voltage("+5V", 1, 4, 1)); //Probably not updating properly + v.Add(new Voltage("AVCC", 2, 10, 10)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); //Probably not updating properly + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("Motherboard", 2)); + t.Add(new Temperature("Temperature #3", 3)); + t.Add(new Temperature("Temperature #4", 4)); + t.Add(new Temperature("Temperature #5", 5)); + t.Add(new Temperature("Temperature #6", 6)); + t.Add(new Temperature("Temperature #7", 7)); + t.Add(new Temperature("Temperature #21", 21)); + + for (int i = 0; i < superIO.Fans.Length; i++) + { + switch (i) + { + case 0: + f.Add(new Fan("Chassis Fan", 0)); + break; + case 1: + f.Add(new Fan("CPU Fan", 1)); + break; + case 4: + f.Add(new Fan("AIO Pump", 4)); + break; + } + } + + for (int i = 0; i < superIO.Controls.Length; i++) + { + switch (i) + { + case 0: + c.Add(new Ctrl("Chassis Fan", 0)); + break; + case 1: + c.Add(new Ctrl("CPU Fan", 1)); + break; + case 4: + c.Add(new Ctrl("AIO Pump", 4)); + break; + } + } + break; + + case Model.ROG_STRIX_B550_F_GAMING_WIFI: // NCT6798D-R + v.Add(new Voltage("Vcore", 0, 2, 2)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU Core", 0)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Temperature #1", 1)); + t.Add(new Temperature("Temperature #2", 2)); + t.Add(new Temperature("Temperature #3", 3)); + t.Add(new Temperature("Temperature #4", 4)); + t.Add(new Temperature("Temperature #5", 5)); + t.Add(new Temperature("Temperature #6", 6)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; } - } - foreach (Sensor sensor in _controls) - { - sensor.Value = _readControl(sensor.Index); - } + break; + case Manufacturer.MSI: + switch (model) + { + case Model.B360M_PRO_VDH: // NCT6797D + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); + //v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("CPU I/O", 6)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("CPU SA", 10)); + //v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("NB/SoC", 12)); + v.Add(new Voltage("DIMM", 13, 1, 1)); + //v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("Motherboard", 2)); + t.Add(new Temperature("Temperature #1", 5)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("System Fan #1", 2)); + f.Add(new Fan("System Fan #2", 3)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("System Fan #1", 2)); + c.Add(new Ctrl("System Fan #2", 3)); - _postUpdate(); + break; + + case Model.B450A_PRO: // NCT6797D + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); + //v.Add(new Voltage("Voltage #6", 5, false)); + //v.Add(new Voltage("CPU I/O", 6)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("CPU SA", 10)); + //v.Add(new Voltage("Voltage #12", 11, false)); + v.Add(new Voltage("NB/SoC", 12)); + v.Add(new Voltage("DIMM", 13, 1, 1)); + //v.Add(new Voltage("Voltage #15", 14, false)); + //t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("CPU", 1)); + t.Add(new Temperature("System", 2)); + t.Add(new Temperature("VRM MOS", 3)); + t.Add(new Temperature("PCH", 5)); + t.Add(new Temperature("SMBus 0", 8)); + f.Add(new Fan("Pump Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("System Fan #1", 2)); + f.Add(new Fan("System Fan #2", 3)); + f.Add(new Fan("System Fan #3", 4)); + f.Add(new Fan("System Fan #4", 5)); + c.Add(new Ctrl("Pump Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("System Fan #1", 2)); + c.Add(new Ctrl("System Fan #2", 3)); + c.Add(new Ctrl("System Fan #3", 4)); + c.Add(new Ctrl("System Fan #4", 5)); + + break; + + case Model.Z270_PC_MATE: // NCT6795D + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+5V", 1, 4, 1)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+12V", 4, 11, 1)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("CPU I/O", 6)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("CPU SA", 10)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("PCH", 12)); + v.Add(new Voltage("DIMM", 13, 1, 1)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("Motherboard", 2)); + f.Add(new Fan("Pump Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("System Fan #1", 2)); + f.Add(new Fan("System Fan #2", 3)); + f.Add(new Fan("System Fan #3", 4)); + f.Add(new Fan("System Fan #4", 5)); + c.Add(new Ctrl("Pump Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("System Fan #1", 2)); + c.Add(new Ctrl("System Fan #2", 3)); + c.Add(new Ctrl("System Fan #3", 4)); + c.Add(new Ctrl("System Fan #4", 5)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Temperature #1", 1)); + t.Add(new Temperature("Temperature #2", 2)); + t.Add(new Temperature("Temperature #3", 3)); + t.Add(new Temperature("Temperature #4", 4)); + t.Add(new Temperature("Temperature #5", 5)); + t.Add(new Temperature("Temperature #6", 6)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; + } + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("VTT", 9)); + v.Add(new Voltage("Voltage #11", 10, true)); + v.Add(new Voltage("Voltage #12", 11, true)); + v.Add(new Voltage("Voltage #13", 12, true)); + v.Add(new Voltage("Voltage #14", 13, true)); + v.Add(new Voltage("Voltage #15", 14, true)); + t.Add(new Temperature("CPU Core", 0)); + t.Add(new Temperature("Temperature #1", 1)); + t.Add(new Temperature("Temperature #2", 2)); + t.Add(new Temperature("Temperature #3", 3)); + t.Add(new Temperature("Temperature #4", 4)); + t.Add(new Temperature("Temperature #5", 5)); + t.Add(new Temperature("Temperature #6", 6)); + + for (int i = 0; i < superIO.Fans.Length; i++) + f.Add(new Fan("Fan #" + (i + 1), i)); + + for (int i = 0; i < superIO.Controls.Length; i++) + c.Add(new Ctrl("Fan #" + (i + 1), i)); + + break; } + } - public override void Close() + private static void GetWinbondConfigurationEhf(Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + { + switch (manufacturer) { - foreach (Sensor sensor in _controls) - { - // restore all controls back to default - _superIO.SetControl(sensor.Index, null); - } + case Manufacturer.ASRock: + switch (model) + { + case Model.AOD790GX_128M: // W83627EHF + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 4, 10, 10)); + v.Add(new Voltage("+5V", 5, 20, 10)); + v.Add(new Voltage("+12V", 6, 28, 5)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 2)); + f.Add(new Fan("CPU Fan", 0)); + f.Add(new Fan("Chassis Fan", 1)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); - base.Close(); + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("Voltage #10", 9, true)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("System Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Auxiliary Fan", 2)); + f.Add(new Fan("CPU Fan #2", 3)); + f.Add(new Fan("Auxiliary Fan #2", 4)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + + break; + } + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + v.Add(new Voltage("Voltage #10", 9, true)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("System Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Auxiliary Fan", 2)); + f.Add(new Fan("CPU Fan #2", 3)); + f.Add(new Fan("Auxiliary Fan #2", 4)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + + break; } + } - private delegate float? ReadValueDelegate(int index); - - private delegate void UpdateDelegate(); - - private class Voltage + private static void GetWinbondConfigurationHg(Manufacturer manufacturer, Model model, IList v, IList t, IList f, IList c) + { + switch (manufacturer) { - public readonly bool Hidden; - public readonly int Index; - public readonly string Name; - public readonly float Rf; - public readonly float Ri; - public readonly float Vf; + case Manufacturer.ASRock: + switch (model) + { + case Model._880GMH_USB3: // W83627DHG-P + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+5V", 5, 15, 7.5f)); + v.Add(new Voltage("+12V", 6, 56, 10)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 2)); + f.Add(new Fan("Chassis Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Power Fan", 2)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); - public Voltage(string name, int index, bool hidden = false) : this(name, index, 0, 1, 0, hidden) - { } + break; - public Voltage(string name, int index, float ri, float rf, float vf = 0, bool hidden = false) + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("System Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Auxiliary Fan", 2)); + f.Add(new Fan("CPU Fan #2", 3)); + f.Add(new Fan("Auxiliary Fan #2", 4)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + + break; + } + + break; + case Manufacturer.ASUS: + switch (model) + { + case Model.P6T: // W83667HG + case Model.P6X58D_E: // W83667HG + case Model.RAMPAGE_II_GENE: // W83667HG + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+12V", 1, 11.5f, 1.91f)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+5V", 4, 15, 7.5f)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 2)); + f.Add(new Fan("Chassis Fan #1", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("Chassis Fan #2", 3)); + f.Add(new Fan("Chassis Fan #3", 4)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + + break; + + case Model.RAMPAGE_EXTREME: // W83667HG + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("+12V", 1, 12, 2)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("+5V", 4, 15, 7.5f)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Motherboard", 2)); + f.Add(new Fan("Chassis Fan #1", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Power Fan", 2)); + f.Add(new Fan("Chassis Fan #2", 3)); + f.Add(new Fan("Chassis Fan #3", 4)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("System Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Auxiliary Fan", 2)); + f.Add(new Fan("CPU Fan #2", 3)); + f.Add(new Fan("Auxiliary Fan #2", 4)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + + break; + } + + break; + + default: + v.Add(new Voltage("Vcore", 0)); + v.Add(new Voltage("Voltage #2", 1, true)); + v.Add(new Voltage("AVCC", 2, 34, 34)); + v.Add(new Voltage("+3.3V", 3, 34, 34)); + v.Add(new Voltage("Voltage #5", 4, true)); + v.Add(new Voltage("Voltage #6", 5, true)); + v.Add(new Voltage("Voltage #7", 6, true)); + v.Add(new Voltage("3VSB", 7, 34, 34)); + v.Add(new Voltage("VBat", 8, 34, 34)); + t.Add(new Temperature("CPU", 0)); + t.Add(new Temperature("Auxiliary", 1)); + t.Add(new Temperature("System", 2)); + f.Add(new Fan("System Fan", 0)); + f.Add(new Fan("CPU Fan", 1)); + f.Add(new Fan("Auxiliary Fan", 2)); + f.Add(new Fan("CPU Fan #2", 3)); + f.Add(new Fan("Auxiliary Fan #2", 4)); + c.Add(new Ctrl("System Fan", 0)); + c.Add(new Ctrl("CPU Fan", 1)); + c.Add(new Ctrl("Auxiliary Fan", 2)); + + break; + } + } + + public override string GetReport() + { + return _superIO.GetReport(); + } + + public override void Update() + { + _superIO.Update(); + + foreach (Sensor sensor in _voltages) + { + float? value = _readVoltage(sensor.Index); + if (value.HasValue) { - Name = name; - Index = index; - Ri = ri; - Rf = rf; - Vf = vf; - Hidden = hidden; + sensor.Value = value + ((value - sensor.Parameters[2].Value) * sensor.Parameters[0].Value / sensor.Parameters[1].Value); + ActivateSensor(sensor); } } - private class Temperature + foreach (Sensor sensor in _temperatures) { - public readonly int Index; - public readonly string Name; - - public Temperature(string name, int index) + float? value = _readTemperature(sensor.Index); + if (value.HasValue) { - Name = name; - Index = index; + sensor.Value = value + sensor.Parameters[0].Value; + ActivateSensor(sensor); } } - private class Fan + foreach (Sensor sensor in _fans) { - public readonly int Index; - public readonly string Name; - - public Fan(string name, int index) + float? value = _readFan(sensor.Index); + if (value.HasValue) { - Name = name; - Index = index; + sensor.Value = value; + ActivateSensor(sensor); } } - private class Ctrl + foreach (Sensor sensor in _controls) { - public readonly int Index; - public readonly string Name; + sensor.Value = _readControl(sensor.Index); + } - public Ctrl(string name, int index) - { - Name = name; - Index = index; - } + _postUpdate(); + } + + public override void Close() + { + foreach (Sensor sensor in _controls) + { + // restore all controls back to default + _superIO.SetControl(sensor.Index, null); + } + + base.Close(); + } + + private delegate float? ReadValueDelegate(int index); + + private delegate void UpdateDelegate(); + + private class Voltage + { + public readonly bool Hidden; + public readonly int Index; + public readonly string Name; + public readonly float Rf; + public readonly float Ri; + public readonly float Vf; + + public Voltage(string name, int index, bool hidden = false) : this(name, index, 0, 1, 0, hidden) + { } + + public Voltage(string name, int index, float ri, float rf, float vf = 0, bool hidden = false) + { + Name = name; + Index = index; + Ri = ri; + Rf = rf; + Vf = vf; + Hidden = hidden; + } + } + + private class Temperature + { + public readonly int Index; + public readonly string Name; + + public Temperature(string name, int index) + { + Name = name; + Index = index; + } + } + + private class Fan + { + public readonly int Index; + public readonly string Name; + + public Fan(string name, int index) + { + Name = name; + Index = index; + } + } + + private class Ctrl + { + public readonly int Index; + public readonly string Name; + + public Ctrl(string name, int index) + { + Name = name; + Index = index; } } } diff --git a/LibreHardwareMonitorLib/Hardware/Network/Network.cs b/LibreHardwareMonitorLib/Hardware/Network/Network.cs index b174747..88a9228 100644 --- a/LibreHardwareMonitorLib/Hardware/Network/Network.cs +++ b/LibreHardwareMonitorLib/Hardware/Network/Network.cs @@ -7,107 +7,106 @@ using System; using System.Diagnostics; using System.Net.NetworkInformation; -namespace LibreHardwareMonitor.Hardware.Network +namespace LibreHardwareMonitor.Hardware.Network; + +internal sealed class Network : Hardware { - internal sealed class Network : Hardware + private readonly Sensor _dataDownloaded; + private readonly Sensor _dataUploaded; + private readonly Sensor _downloadSpeed; + private readonly Sensor _networkUtilization; + private readonly Sensor _uploadSpeed; + private long _bytesDownloaded; + private long _bytesUploaded; + private long _lastTick; + + public Network(NetworkInterface networkInterface, ISettings settings) + : base(networkInterface.Name, new Identifier("nic", networkInterface.Id), settings) { - private readonly Sensor _dataDownloaded; - private readonly Sensor _dataUploaded; - private readonly Sensor _downloadSpeed; - private readonly Sensor _networkUtilization; - private readonly Sensor _uploadSpeed; - private long _bytesDownloaded; - private long _bytesUploaded; - private long _lastTick; + NetworkInterface = networkInterface; + _dataUploaded = new Sensor("Data Uploaded", 2, SensorType.Data, this, settings); + ActivateSensor(_dataUploaded); + _dataDownloaded = new Sensor("Data Downloaded", 3, SensorType.Data, this, settings); + ActivateSensor(_dataDownloaded); + _uploadSpeed = new Sensor("Upload Speed", 7, SensorType.Throughput, this, settings); + ActivateSensor(_uploadSpeed); + _downloadSpeed = new Sensor("Download Speed", 8, SensorType.Throughput, this, settings); + ActivateSensor(_downloadSpeed); + _networkUtilization = new Sensor("Network Utilization", 1, SensorType.Load, this, settings); + ActivateSensor(_networkUtilization); + _bytesUploaded = NetworkInterface.GetIPStatistics().BytesSent; + _bytesDownloaded = NetworkInterface.GetIPStatistics().BytesReceived; + _lastTick = Stopwatch.GetTimestamp(); + } - public Network(NetworkInterface networkInterface, ISettings settings) - : base(networkInterface.Name, new Identifier("nic", networkInterface.Id), settings) + public override HardwareType HardwareType + { + get { return HardwareType.Network; } + } + + internal NetworkInterface NetworkInterface { get; private set; } + + public override void Update() + { + try { - NetworkInterface = networkInterface; - _dataUploaded = new Sensor("Data Uploaded", 2, SensorType.Data, this, settings); - ActivateSensor(_dataUploaded); - _dataDownloaded = new Sensor("Data Downloaded", 3, SensorType.Data, this, settings); - ActivateSensor(_dataDownloaded); - _uploadSpeed = new Sensor("Upload Speed", 7, SensorType.Throughput, this, settings); - ActivateSensor(_uploadSpeed); - _downloadSpeed = new Sensor("Download Speed", 8, SensorType.Throughput, this, settings); - ActivateSensor(_downloadSpeed); - _networkUtilization = new Sensor("Network Utilization", 1, SensorType.Load, this, settings); - ActivateSensor(_networkUtilization); - _bytesUploaded = NetworkInterface.GetIPStatistics().BytesSent; - _bytesDownloaded = NetworkInterface.GetIPStatistics().BytesReceived; - _lastTick = Stopwatch.GetTimestamp(); - } + if (NetworkInterface == null) + return; - public override HardwareType HardwareType - { - get { return HardwareType.Network; } - } + long newTick = Stopwatch.GetTimestamp(); + double dt = new TimeSpan(newTick - _lastTick).TotalSeconds; - internal NetworkInterface NetworkInterface { get; private set; } + IPv4InterfaceStatistics interfaceStats = NetworkInterface.GetIPv4Statistics(); - public override void Update() - { - try + // Report out the number of GB (2^30 Bytes) that this interface has up/downloaded. Note + // that these values can reset back at zero (eg: after waking from sleep). + _dataUploaded.Value = (float)(interfaceStats.BytesSent / (double)0x40000000); + _dataDownloaded.Value = (float)(interfaceStats.BytesReceived / (double)0x40000000); + + // Detect a reset in interface stats if the new total is less than what was previously + // seen. While setting the previous values to zero doesn't encapsulate the value the + // instant before the reset, it is the best approximation we have. + if (interfaceStats.BytesSent < _bytesUploaded || interfaceStats.BytesReceived < _bytesDownloaded) { - if (NetworkInterface == null) - return; - - long newTick = Stopwatch.GetTimestamp(); - double dt = new TimeSpan(newTick - _lastTick).TotalSeconds; - - IPv4InterfaceStatistics interfaceStats = NetworkInterface.GetIPv4Statistics(); - - // Report out the number of GB (2^30 Bytes) that this interface has up/downloaded. Note - // that these values can reset back at zero (eg: after waking from sleep). - _dataUploaded.Value = (float)(interfaceStats.BytesSent / (double)0x40000000); - _dataDownloaded.Value = (float)(interfaceStats.BytesReceived / (double)0x40000000); - - // Detect a reset in interface stats if the new total is less than what was previously - // seen. While setting the previous values to zero doesn't encapsulate the value the - // instant before the reset, it is the best approximation we have. - if (interfaceStats.BytesSent < _bytesUploaded || interfaceStats.BytesReceived < _bytesDownloaded) - { - _bytesUploaded = 0; - _bytesDownloaded = 0; - } - - long dBytesUploaded = interfaceStats.BytesSent - _bytesUploaded; - long dBytesDownloaded = interfaceStats.BytesReceived - _bytesDownloaded; - - // Upload and download speeds are reported as the number of bytes transfered over the - // time difference since the last report. In this way, the values represent the average - // number of bytes up/downloaded in a second. - _uploadSpeed.Value = (float)(dBytesUploaded / dt); - _downloadSpeed.Value = (float)(dBytesDownloaded / dt); - - // Network speed is in bits per second, so when calculating the load on the NIC we first - // grab the total number of bits up/downloaded - long dbits = (dBytesUploaded + dBytesDownloaded) * 8; - - // Converts the ratio of total bits transferred over time over theoretical max bits - // transfer rate into a percentage load - double load = (dbits / dt / NetworkInterface.Speed) * 100; - - // Finally clamp the value between 0% and 100% to avoid reporting nonsensical numbers - _networkUtilization.Value = (float)Math.Min(Math.Max(load, 0), 100); - - // Store the recorded values and time, so they can be used in the next update - _bytesUploaded = interfaceStats.BytesSent; - _bytesDownloaded = interfaceStats.BytesReceived; - _lastTick = newTick; + _bytesUploaded = 0; + _bytesDownloaded = 0; } - catch (NetworkInformationException networkInformationException) when (unchecked(networkInformationException.HResult == (int)0x80004005)) + + long dBytesUploaded = interfaceStats.BytesSent - _bytesUploaded; + long dBytesDownloaded = interfaceStats.BytesReceived - _bytesDownloaded; + + // Upload and download speeds are reported as the number of bytes transfered over the + // time difference since the last report. In this way, the values represent the average + // number of bytes up/downloaded in a second. + _uploadSpeed.Value = (float)(dBytesUploaded / dt); + _downloadSpeed.Value = (float)(dBytesDownloaded / dt); + + // Network speed is in bits per second, so when calculating the load on the NIC we first + // grab the total number of bits up/downloaded + long dbits = (dBytesUploaded + dBytesDownloaded) * 8; + + // Converts the ratio of total bits transferred over time over theoretical max bits + // transfer rate into a percentage load + double load = (dbits / dt / NetworkInterface.Speed) * 100; + + // Finally clamp the value between 0% and 100% to avoid reporting nonsensical numbers + _networkUtilization.Value = (float)Math.Min(Math.Max(load, 0), 100); + + // Store the recorded values and time, so they can be used in the next update + _bytesUploaded = interfaceStats.BytesSent; + _bytesDownloaded = interfaceStats.BytesReceived; + _lastTick = newTick; + } + catch (NetworkInformationException networkInformationException) when (unchecked(networkInformationException.HResult == (int)0x80004005)) + { + foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces()) { - foreach (NetworkInterface networkInterface in NetworkInterface.GetAllNetworkInterfaces()) + if (networkInterface.Id.Equals(NetworkInterface?.Id)) { - if (networkInterface.Id.Equals(NetworkInterface?.Id)) - { - NetworkInterface = networkInterface; - break; - } + NetworkInterface = networkInterface; + break; } } } } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Network/NetworkGroup.cs b/LibreHardwareMonitorLib/Hardware/Network/NetworkGroup.cs index 8a9302f..1f03bed 100644 --- a/LibreHardwareMonitorLib/Hardware/Network/NetworkGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Network/NetworkGroup.cs @@ -9,142 +9,141 @@ using System.Linq; using System.Net.NetworkInformation; using System.Text; -namespace LibreHardwareMonitor.Hardware.Network +namespace LibreHardwareMonitor.Hardware.Network; + +internal class NetworkGroup : IGroup, IHardwareChanged { - internal class NetworkGroup : IGroup, IHardwareChanged + public event HardwareEventHandler HardwareAdded; + public event HardwareEventHandler HardwareRemoved; + + private readonly Dictionary _networks = new(); + private readonly object _scanLock = new(); + private readonly ISettings _settings; + private readonly List _hardware = new(); + + public NetworkGroup(ISettings settings) { - public event HardwareEventHandler HardwareAdded; - public event HardwareEventHandler HardwareRemoved; + _settings = settings; + UpdateNetworkInterfaces(settings); - private readonly Dictionary _networks = new(); - private readonly object _scanLock = new(); - private readonly ISettings _settings; - private readonly List _hardware = new(); + NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged; + NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAddressChanged; + } - public NetworkGroup(ISettings settings) + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + var report = new StringBuilder(); + + foreach (Network network in _hardware) { - _settings = settings; - UpdateNetworkInterfaces(settings); + report.AppendLine(network.NetworkInterface.Description); + report.AppendLine(network.NetworkInterface.OperationalStatus.ToString()); + report.AppendLine(); - NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged; - NetworkChange.NetworkAvailabilityChanged += NetworkChange_NetworkAddressChanged; - } - - public IReadOnlyList Hardware => _hardware; - - public string GetReport() - { - var report = new StringBuilder(); - - foreach (Network network in _hardware) + foreach (ISensor sensor in network.Sensors) { - report.AppendLine(network.NetworkInterface.Description); - report.AppendLine(network.NetworkInterface.OperationalStatus.ToString()); + report.AppendLine(sensor.Name); + report.AppendLine(sensor.Value.ToString()); report.AppendLine(); - - foreach (ISensor sensor in network.Sensors) - { - report.AppendLine(sensor.Name); - report.AppendLine(sensor.Value.ToString()); - report.AppendLine(); - } } - - return report.ToString(); } - public void Close() - { - NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged; - NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAddressChanged; + return report.ToString(); + } - foreach (Network network in _hardware) + public void Close() + { + NetworkChange.NetworkAddressChanged -= NetworkChange_NetworkAddressChanged; + NetworkChange.NetworkAvailabilityChanged -= NetworkChange_NetworkAddressChanged; + + foreach (Network network in _hardware) + network.Close(); + } + + private void UpdateNetworkInterfaces(ISettings settings) + { + // When multiple events fire concurrently, we don't want threads interfering + // with others as they manipulate non-thread safe state. + lock (_scanLock) + { + IOrderedEnumerable networkInterfaces = GetNetworkInterfaces(); + if (networkInterfaces == null) + return; + + var foundNetworkInterfaces = networkInterfaces.ToDictionary(x => x.Id, x => x); + + // Remove network interfaces that no longer exist. + List removeKeys = new(); + foreach (KeyValuePair networkInterfacePair in _networks) + { + if (foundNetworkInterfaces.ContainsKey(networkInterfacePair.Key)) + continue; + + removeKeys.Add(networkInterfacePair.Key); + } + + foreach (string key in removeKeys) + { + Network network = _networks[key]; network.Close(); - } + _networks.Remove(key); - private void UpdateNetworkInterfaces(ISettings settings) - { - // When multiple events fire concurrently, we don't want threads interfering - // with others as they manipulate non-thread safe state. - lock (_scanLock) - { - IOrderedEnumerable networkInterfaces = GetNetworkInterfaces(); - if (networkInterfaces == null) - return; - - var foundNetworkInterfaces = networkInterfaces.ToDictionary(x => x.Id, x => x); - - // Remove network interfaces that no longer exist. - List removeKeys = new(); - foreach (KeyValuePair networkInterfacePair in _networks) - { - if (foundNetworkInterfaces.ContainsKey(networkInterfacePair.Key)) - continue; - - removeKeys.Add(networkInterfacePair.Key); - } - - foreach (string key in removeKeys) - { - Network network = _networks[key]; - network.Close(); - _networks.Remove(key); - - _hardware.Remove(network); - HardwareRemoved?.Invoke(network); - } - - // Add new network interfaces. - foreach (KeyValuePair networkInterfacePair in foundNetworkInterfaces) - { - if (!_networks.ContainsKey(networkInterfacePair.Key)) - { - _networks.Add(networkInterfacePair.Key, new Network(networkInterfacePair.Value, settings)); - _hardware.Add(_networks[networkInterfacePair.Key]); - HardwareAdded?.Invoke(_networks[networkInterfacePair.Key]); - } - } - } - } - - private static IOrderedEnumerable GetNetworkInterfaces() - { - int retry = 0; - - while (retry++ < 5) - { - try - { - return NetworkInterface.GetAllNetworkInterfaces() - .Where(DesiredNetworkType) - .OrderBy(x => x.Name); - } - catch (NetworkInformationException) - { - // Disabling IPv4 while running can cause a NetworkInformationException: The pipe is being closed. - // This can be retried. - } + _hardware.Remove(network); + HardwareRemoved?.Invoke(network); } - return null; - } - - private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e) - { - UpdateNetworkInterfaces(_settings); - } - - private static bool DesiredNetworkType(NetworkInterface nic) - { - switch (nic.NetworkInterfaceType) + // Add new network interfaces. + foreach (KeyValuePair networkInterfacePair in foundNetworkInterfaces) { - case NetworkInterfaceType.Loopback: - case NetworkInterfaceType.Tunnel: - case NetworkInterfaceType.Unknown: - return false; - default: - return true; + if (!_networks.ContainsKey(networkInterfacePair.Key)) + { + _networks.Add(networkInterfacePair.Key, new Network(networkInterfacePair.Value, settings)); + _hardware.Add(_networks[networkInterfacePair.Key]); + HardwareAdded?.Invoke(_networks[networkInterfacePair.Key]); + } } } } + + private static IOrderedEnumerable GetNetworkInterfaces() + { + int retry = 0; + + while (retry++ < 5) + { + try + { + return NetworkInterface.GetAllNetworkInterfaces() + .Where(DesiredNetworkType) + .OrderBy(x => x.Name); + } + catch (NetworkInformationException) + { + // Disabling IPv4 while running can cause a NetworkInformationException: The pipe is being closed. + // This can be retried. + } + } + + return null; + } + + private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e) + { + UpdateNetworkInterfaces(_settings); + } + + private static bool DesiredNetworkType(NetworkInterface nic) + { + switch (nic.NetworkInterfaceType) + { + case NetworkInterfaceType.Loopback: + case NetworkInterfaceType.Tunnel: + case NetworkInterfaceType.Unknown: + return false; + default: + return true; + } + } } diff --git a/LibreHardwareMonitorLib/Hardware/OpCode.cs b/LibreHardwareMonitorLib/Hardware/OpCode.cs index 51659e2..432a9e4 100644 --- a/LibreHardwareMonitorLib/Hardware/OpCode.cs +++ b/LibreHardwareMonitorLib/Hardware/OpCode.cs @@ -8,296 +8,295 @@ using System; using System.Reflection; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal static class OpCode { - internal static class OpCode + public static CpuidDelegate CpuId; + public static RdtscDelegate Rdtsc; + + private static IntPtr _codeBuffer; + private static ulong _size; + + // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, + // unsigned int* eax, unsigned int* ebx, unsigned int* ecx, + // unsigned int* edx) + // { + // int info[4]; + // __cpuidex(info, index, ecxValue); + // *eax = info[0]; + // *ebx = info[1]; + // *ecx = info[2]; + // *edx = info[3]; + // } + + private static readonly byte[] CpuId32 = { - public static CpuidDelegate CpuId; - public static RdtscDelegate Rdtsc; + 0x55, // push ebp + 0x8B, + 0xEC, // mov ebp, esp + 0x83, + 0xEC, + 0x10, // sub esp, 10h + 0x8B, + 0x45, + 0x08, // mov eax, dword ptr [ebp+8] + 0x8B, + 0x4D, + 0x0C, // mov ecx, dword ptr [ebp+0Ch] + 0x53, // push ebx + 0x0F, + 0xA2, // cpuid + 0x56, // push esi + 0x8D, + 0x75, + 0xF0, // lea esi, [info] + 0x89, + 0x06, // mov dword ptr [esi],eax + 0x8B, + 0x45, + 0x10, // mov eax, dword ptr [eax] + 0x89, + 0x5E, + 0x04, // mov dword ptr [esi+4], ebx + 0x89, + 0x4E, + 0x08, // mov dword ptr [esi+8], ecx + 0x89, + 0x56, + 0x0C, // mov dword ptr [esi+0Ch], edx + 0x8B, + 0x4D, + 0xF0, // mov ecx, dword ptr [info] + 0x89, + 0x08, // mov dword ptr [eax], ecx + 0x8B, + 0x45, + 0x14, // mov eax, dword ptr [ebx] + 0x8B, + 0x4D, + 0xF4, // mov ecx, dword ptr [ebp-0Ch] + 0x89, + 0x08, // mov dword ptr [eax], ecx + 0x8B, + 0x45, + 0x18, // mov eax, dword ptr [ecx] + 0x8B, + 0x4D, + 0xF8, // mov ecx, dword ptr [ebp-8] + 0x89, + 0x08, // mov dword ptr [eax], ecx + 0x8B, + 0x45, + 0x1C, // mov eax, dword ptr [edx] + 0x8B, + 0x4D, + 0xFC, // mov ecx, dword ptr [ebp-4] + 0x5E, // pop esi + 0x89, + 0x08, // mov dword ptr [eax], ecx + 0x5B, // pop ebx + 0xC9, // leave + 0xC2, + 0x18, + 0x00 // ret 18h + }; - private static IntPtr _codeBuffer; - private static ulong _size; + private static readonly byte[] CpuId64Linux = + { + 0x49, + 0x89, + 0xD2, // mov r10, rdx + 0x49, + 0x89, + 0xCB, // mov r11, rcx + 0x53, // push rbx + 0x89, + 0xF8, // mov eax, edi + 0x89, + 0xF1, // mov ecx, esi + 0x0F, + 0xA2, // cpuid + 0x41, + 0x89, + 0x02, // mov dword ptr [r10], eax + 0x41, + 0x89, + 0x1B, // mov dword ptr [r11], ebx + 0x41, + 0x89, + 0x08, // mov dword ptr [r8], ecx + 0x41, + 0x89, + 0x11, // mov dword ptr [r9], edx + 0x5B, // pop rbx + 0xC3 // ret + }; - // void __stdcall cpuidex(unsigned int index, unsigned int ecxValue, - // unsigned int* eax, unsigned int* ebx, unsigned int* ecx, - // unsigned int* edx) - // { - // int info[4]; - // __cpuidex(info, index, ecxValue); - // *eax = info[0]; - // *ebx = info[1]; - // *ecx = info[2]; - // *edx = info[3]; - // } + private static readonly byte[] CpuId64Windows = + { + 0x48, + 0x89, + 0x5C, + 0x24, + 0x08, // mov qword ptr [rsp+8], rbx + 0x8B, + 0xC1, // mov eax, ecx + 0x8B, + 0xCA, // mov ecx, edx + 0x0F, + 0xA2, // cpuid + 0x41, + 0x89, + 0x00, // mov dword ptr [r8], eax + 0x48, + 0x8B, + 0x44, + 0x24, + 0x28, // mov rax, qword ptr [rsp+28h] + 0x41, + 0x89, + 0x19, // mov dword ptr [r9], ebx + 0x48, + 0x8B, + 0x5C, + 0x24, + 0x08, // mov rbx, qword ptr [rsp+8] + 0x89, + 0x08, // mov dword ptr [rax], ecx + 0x48, + 0x8B, + 0x44, + 0x24, + 0x30, // mov rax, qword ptr [rsp+30h] + 0x89, + 0x10, // mov dword ptr [rax], edx + 0xC3 // ret + }; - private static readonly byte[] CpuId32 = + // unsigned __int64 __stdcall rdtsc() { + // return __rdtsc(); + // } + + private static readonly byte[] Rdtsc32 = + { + 0x0F, + 0x31, // rdtsc + 0xC3 // ret + }; + + private static readonly byte[] Rdtsc64 = + { + 0x0F, + 0x31, // rdtsc + 0x48, + 0xC1, + 0xE2, + 0x20, // shl rdx, 20h + 0x48, + 0x0B, + 0xC2, // or rax, rdx + 0xC3 // ret + }; + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + public delegate bool CpuidDelegate(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx); + + [UnmanagedFunctionPointer(CallingConvention.StdCall)] + public delegate ulong RdtscDelegate(); + + public static void Open() + { + byte[] rdTscCode; + byte[] cpuidCode; + if (IntPtr.Size == 4) { - 0x55, // push ebp - 0x8B, - 0xEC, // mov ebp, esp - 0x83, - 0xEC, - 0x10, // sub esp, 10h - 0x8B, - 0x45, - 0x08, // mov eax, dword ptr [ebp+8] - 0x8B, - 0x4D, - 0x0C, // mov ecx, dword ptr [ebp+0Ch] - 0x53, // push ebx - 0x0F, - 0xA2, // cpuid - 0x56, // push esi - 0x8D, - 0x75, - 0xF0, // lea esi, [info] - 0x89, - 0x06, // mov dword ptr [esi],eax - 0x8B, - 0x45, - 0x10, // mov eax, dword ptr [eax] - 0x89, - 0x5E, - 0x04, // mov dword ptr [esi+4], ebx - 0x89, - 0x4E, - 0x08, // mov dword ptr [esi+8], ecx - 0x89, - 0x56, - 0x0C, // mov dword ptr [esi+0Ch], edx - 0x8B, - 0x4D, - 0xF0, // mov ecx, dword ptr [info] - 0x89, - 0x08, // mov dword ptr [eax], ecx - 0x8B, - 0x45, - 0x14, // mov eax, dword ptr [ebx] - 0x8B, - 0x4D, - 0xF4, // mov ecx, dword ptr [ebp-0Ch] - 0x89, - 0x08, // mov dword ptr [eax], ecx - 0x8B, - 0x45, - 0x18, // mov eax, dword ptr [ecx] - 0x8B, - 0x4D, - 0xF8, // mov ecx, dword ptr [ebp-8] - 0x89, - 0x08, // mov dword ptr [eax], ecx - 0x8B, - 0x45, - 0x1C, // mov eax, dword ptr [edx] - 0x8B, - 0x4D, - 0xFC, // mov ecx, dword ptr [ebp-4] - 0x5E, // pop esi - 0x89, - 0x08, // mov dword ptr [eax], ecx - 0x5B, // pop ebx - 0xC9, // leave - 0xC2, - 0x18, - 0x00 // ret 18h - }; - - private static readonly byte[] CpuId64Linux = + rdTscCode = Rdtsc32; + cpuidCode = CpuId32; + } + else { - 0x49, - 0x89, - 0xD2, // mov r10, rdx - 0x49, - 0x89, - 0xCB, // mov r11, rcx - 0x53, // push rbx - 0x89, - 0xF8, // mov eax, edi - 0x89, - 0xF1, // mov ecx, esi - 0x0F, - 0xA2, // cpuid - 0x41, - 0x89, - 0x02, // mov dword ptr [r10], eax - 0x41, - 0x89, - 0x1B, // mov dword ptr [r11], ebx - 0x41, - 0x89, - 0x08, // mov dword ptr [r8], ecx - 0x41, - 0x89, - 0x11, // mov dword ptr [r9], edx - 0x5B, // pop rbx - 0xC3 // ret - }; + rdTscCode = Rdtsc64; - private static readonly byte[] CpuId64Windows = + cpuidCode = Software.OperatingSystem.IsUnix ? CpuId64Linux : CpuId64Windows; + } + + _size = (ulong)(rdTscCode.Length + cpuidCode.Length); + + if (Software.OperatingSystem.IsUnix) { - 0x48, - 0x89, - 0x5C, - 0x24, - 0x08, // mov qword ptr [rsp+8], rbx - 0x8B, - 0xC1, // mov eax, ecx - 0x8B, - 0xCA, // mov ecx, edx - 0x0F, - 0xA2, // cpuid - 0x41, - 0x89, - 0x00, // mov dword ptr [r8], eax - 0x48, - 0x8B, - 0x44, - 0x24, - 0x28, // mov rax, qword ptr [rsp+28h] - 0x41, - 0x89, - 0x19, // mov dword ptr [r9], ebx - 0x48, - 0x8B, - 0x5C, - 0x24, - 0x08, // mov rbx, qword ptr [rsp+8] - 0x89, - 0x08, // mov dword ptr [rax], ecx - 0x48, - 0x8B, - 0x44, - 0x24, - 0x30, // mov rax, qword ptr [rsp+30h] - 0x89, - 0x10, // mov dword ptr [rax], edx - 0xC3 // ret - }; - - // unsigned __int64 __stdcall rdtsc() { - // return __rdtsc(); - // } - - private static readonly byte[] Rdtsc32 = - { - 0x0F, - 0x31, // rdtsc - 0xC3 // ret - }; - - private static readonly byte[] Rdtsc64 = - { - 0x0F, - 0x31, // rdtsc - 0x48, - 0xC1, - 0xE2, - 0x20, // shl rdx, 20h - 0x48, - 0x0B, - 0xC2, // or rax, rdx - 0xC3 // ret - }; - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate bool CpuidDelegate(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx); - - [UnmanagedFunctionPointer(CallingConvention.StdCall)] - public delegate ulong RdtscDelegate(); - - public static void Open() - { - byte[] rdTscCode; - byte[] cpuidCode; - if (IntPtr.Size == 4) - { - rdTscCode = Rdtsc32; - cpuidCode = CpuId32; - } - else - { - rdTscCode = Rdtsc64; - - cpuidCode = Software.OperatingSystem.IsUnix ? CpuId64Linux : CpuId64Windows; - } - - _size = (ulong)(rdTscCode.Length + cpuidCode.Length); - - if (Software.OperatingSystem.IsUnix) - { #if NETFRAMEWORK - Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756"); + Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756"); #else Assembly assembly = Assembly.Load("Mono.Posix.NETStandard, Version=1.0.0.0, Culture=neutral"); #endif - Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall"); - MethodInfo mmap = sysCall.GetMethod("mmap"); + Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall"); + MethodInfo mmap = sysCall.GetMethod("mmap"); - Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts"); - object mmapProtsParam = Enum.ToObject(mmapProts, - (int)mmapProts.GetField("PROT_READ").GetValue(null) | - (int)mmapProts.GetField("PROT_WRITE").GetValue(null) | - (int)mmapProts.GetField("PROT_EXEC").GetValue(null)); + Type mmapProts = assembly.GetType("Mono.Unix.Native.MmapProts"); + object mmapProtsParam = Enum.ToObject(mmapProts, + (int)mmapProts.GetField("PROT_READ").GetValue(null) | + (int)mmapProts.GetField("PROT_WRITE").GetValue(null) | + (int)mmapProts.GetField("PROT_EXEC").GetValue(null)); - Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags"); - object mmapFlagsParam = Enum.ToObject(mmapFlags, - (int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) | - (int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null)); + Type mmapFlags = assembly.GetType("Mono.Unix.Native.MmapFlags"); + object mmapFlagsParam = Enum.ToObject(mmapFlags, + (int)mmapFlags.GetField("MAP_ANONYMOUS").GetValue(null) | + (int)mmapFlags.GetField("MAP_PRIVATE").GetValue(null)); - if (mmap != null) - _codeBuffer = (IntPtr)mmap.Invoke(null, new[] { IntPtr.Zero, _size, mmapProtsParam, mmapFlagsParam, -1, 0 }); - } - else - { - _codeBuffer = Interop.Kernel32.VirtualAlloc(IntPtr.Zero, - (UIntPtr)_size, - Interop.Kernel32.MEM.MEM_COMMIT | Interop.Kernel32.MEM.MEM_RESERVE, - Interop.Kernel32.PAGE.PAGE_EXECUTE_READWRITE); - } - - Marshal.Copy(rdTscCode, 0, _codeBuffer, rdTscCode.Length); - Rdtsc = Marshal.GetDelegateForFunctionPointer(_codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate; - IntPtr cpuidAddress = (IntPtr)((long)_codeBuffer + rdTscCode.Length); - Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length); - CpuId = Marshal.GetDelegateForFunctionPointer(cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate; + if (mmap != null) + _codeBuffer = (IntPtr)mmap.Invoke(null, new[] { IntPtr.Zero, _size, mmapProtsParam, mmapFlagsParam, -1, 0 }); + } + else + { + _codeBuffer = Interop.Kernel32.VirtualAlloc(IntPtr.Zero, + (UIntPtr)_size, + Interop.Kernel32.MEM.MEM_COMMIT | Interop.Kernel32.MEM.MEM_RESERVE, + Interop.Kernel32.PAGE.PAGE_EXECUTE_READWRITE); } - public static void Close() - { - Rdtsc = null; - CpuId = null; + Marshal.Copy(rdTscCode, 0, _codeBuffer, rdTscCode.Length); + Rdtsc = Marshal.GetDelegateForFunctionPointer(_codeBuffer, typeof(RdtscDelegate)) as RdtscDelegate; + IntPtr cpuidAddress = (IntPtr)((long)_codeBuffer + rdTscCode.Length); + Marshal.Copy(cpuidCode, 0, cpuidAddress, cpuidCode.Length); + CpuId = Marshal.GetDelegateForFunctionPointer(cpuidAddress, typeof(CpuidDelegate)) as CpuidDelegate; + } - if (Software.OperatingSystem.IsUnix) - { + public static void Close() + { + Rdtsc = null; + CpuId = null; + + if (Software.OperatingSystem.IsUnix) + { #if NETFRAMEWORK - Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756"); + Assembly assembly = Assembly.Load("Mono.Posix, Version=2.0.0.0, Culture=neutral, " + "PublicKeyToken=0738eb9f132ed756"); #else Assembly assembly = Assembly.Load("Mono.Posix.NETStandard, Version=1.0.0.0, Culture=neutral"); #endif - Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall"); - MethodInfo method = sysCall.GetMethod("munmap"); - method?.Invoke(null, new object[] { _codeBuffer, _size }); - } - else - { - Interop.Kernel32.VirtualFree(_codeBuffer, UIntPtr.Zero, Interop.Kernel32.MEM.MEM_RELEASE); - } + Type sysCall = assembly.GetType("Mono.Unix.Native.Syscall"); + MethodInfo method = sysCall.GetMethod("munmap"); + method?.Invoke(null, new object[] { _codeBuffer, _size }); } - - public static bool CpuIdTx(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx, GroupAffinity affinity) + else { - GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); - if (previousAffinity == GroupAffinity.Undefined) - { - eax = ebx = ecx = edx = 0; - return false; - } - - CpuId(index, ecxValue, out eax, out ebx, out ecx, out edx); - ThreadAffinity.Set(previousAffinity); - return true; + Interop.Kernel32.VirtualFree(_codeBuffer, UIntPtr.Zero, Interop.Kernel32.MEM.MEM_RELEASE); } } -} + + public static bool CpuIdTx(uint index, uint ecxValue, out uint eax, out uint ebx, out uint ecx, out uint edx, GroupAffinity affinity) + { + GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); + if (previousAffinity == GroupAffinity.Undefined) + { + eax = ebx = ecx = edx = 0; + return false; + } + + CpuId(index, ecxValue, out eax, out ebx, out ecx, out edx); + ThreadAffinity.Set(previousAffinity); + return true; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Parameter.cs b/LibreHardwareMonitorLib/Hardware/Parameter.cs index 89ee623..5014ab9 100644 --- a/LibreHardwareMonitorLib/Hardware/Parameter.cs +++ b/LibreHardwareMonitorLib/Hardware/Parameter.cs @@ -7,84 +7,83 @@ using System; using System.Globalization; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal class Parameter : IParameter { - internal class Parameter : IParameter + private readonly ISettings _settings; + private readonly ParameterDescription _description; + private bool _isDefault; + private float _value; + + public Parameter(ParameterDescription description, ISensor sensor, ISettings settings) { - private readonly ISettings _settings; - private readonly ParameterDescription _description; - private bool _isDefault; - private float _value; - - public Parameter(ParameterDescription description, ISensor sensor, ISettings settings) + Sensor = sensor; + _description = description; + _settings = settings; + _isDefault = !settings.Contains(Identifier.ToString()); + _value = description.DefaultValue; + if (!_isDefault && !float.TryParse(settings.GetValue(Identifier.ToString(), "0"), NumberStyles.Float, CultureInfo.InvariantCulture, out _value)) { - Sensor = sensor; - _description = description; - _settings = settings; - _isDefault = !settings.Contains(Identifier.ToString()); _value = description.DefaultValue; - if (!_isDefault && !float.TryParse(settings.GetValue(Identifier.ToString(), "0"), NumberStyles.Float, CultureInfo.InvariantCulture, out _value)) - { - _value = description.DefaultValue; - } } - - public float DefaultValue - { - get { return _description.DefaultValue; } - } - - public string Description - { - get { return _description.Description; } - } - - public Identifier Identifier - { - get { return new Identifier(Sensor.Identifier, "parameter", Name.Replace(" ", string.Empty).ToLowerInvariant()); } - } - - public bool IsDefault - { - get { return _isDefault; } - set - { - _isDefault = value; - if (value) - { - _value = _description.DefaultValue; - _settings.Remove(Identifier.ToString()); - } - } - } - - public string Name - { - get { return _description.Name; } - } - - public ISensor Sensor { get; } - - public float Value - { - get { return _value; } - set - { - _isDefault = false; - _value = value; - _settings.SetValue(Identifier.ToString(), value.ToString(CultureInfo.InvariantCulture)); - } - } - - public void Accept(IVisitor visitor) - { - if (visitor == null) - throw new ArgumentNullException(nameof(visitor)); - - visitor.VisitParameter(this); - } - - public void Traverse(IVisitor visitor) - { } } -} + + public float DefaultValue + { + get { return _description.DefaultValue; } + } + + public string Description + { + get { return _description.Description; } + } + + public Identifier Identifier + { + get { return new Identifier(Sensor.Identifier, "parameter", Name.Replace(" ", string.Empty).ToLowerInvariant()); } + } + + public bool IsDefault + { + get { return _isDefault; } + set + { + _isDefault = value; + if (value) + { + _value = _description.DefaultValue; + _settings.Remove(Identifier.ToString()); + } + } + } + + public string Name + { + get { return _description.Name; } + } + + public ISensor Sensor { get; } + + public float Value + { + get { return _value; } + set + { + _isDefault = false; + _value = value; + _settings.SetValue(Identifier.ToString(), value.ToString(CultureInfo.InvariantCulture)); + } + } + + public void Accept(IVisitor visitor) + { + if (visitor == null) + throw new ArgumentNullException(nameof(visitor)); + + visitor.VisitParameter(this); + } + + public void Traverse(IVisitor visitor) + { } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/ParameterDescription.cs b/LibreHardwareMonitorLib/Hardware/ParameterDescription.cs index 61fe6c5..359dbfc 100644 --- a/LibreHardwareMonitorLib/Hardware/ParameterDescription.cs +++ b/LibreHardwareMonitorLib/Hardware/ParameterDescription.cs @@ -4,39 +4,38 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Composite class containing information about the selected . +/// +public struct ParameterDescription { /// - /// Composite class containing information about the selected . + /// Creates a new instance and assigns values. /// - public struct ParameterDescription + /// Name of the selected component. + /// Description of the selected component. + /// Default value of the selected component. + public ParameterDescription(string name, string description, float defaultValue) { - /// - /// Creates a new instance and assigns values. - /// - /// Name of the selected component. - /// Description of the selected component. - /// Default value of the selected component. - public ParameterDescription(string name, string description, float defaultValue) - { - Name = name; - Description = description; - DefaultValue = defaultValue; - } - - /// - /// Gets a name of the parent . - /// - public string Name { get; } - - /// - /// Gets a description of the parent . - /// - public string Description { get; } - - /// - /// Gets a default value of the parent . - /// - public float DefaultValue { get; } + Name = name; + Description = description; + DefaultValue = defaultValue; } -} + + /// + /// Gets a name of the parent . + /// + public string Name { get; } + + /// + /// Gets a description of the parent . + /// + public string Description { get; } + + /// + /// Gets a default value of the parent . + /// + public float DefaultValue { get; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsu.cs b/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsu.cs index 05e77fe..7c3f2dd 100644 --- a/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsu.cs +++ b/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsu.cs @@ -11,248 +11,248 @@ using System.Globalization; using System.Text; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Psu.Corsair +namespace LibreHardwareMonitor.Hardware.Psu.Corsair; + +internal class SensorIndices { - internal class SensorIndices + private readonly Dictionary _lastIndices = new(); + + public int NextIndex(SensorType type) { - private readonly Dictionary _lastIndices = new(); - - public int NextIndex(SensorType type) + if (!_lastIndices.ContainsKey(type)) { - if (!_lastIndices.ContainsKey(type)) - { - _lastIndices.Add(type, 0); - return 0; - } - - int res = _lastIndices[type] + 1; - _lastIndices[type] = res; - return res; + _lastIndices.Add(type, 0); + return 0; } + + int res = _lastIndices[type] + 1; + _lastIndices[type] = res; + return res; + } +} + +// might need refactoring into two classes if AXi series API differs significantly +internal sealed class CorsairPsu : Hardware +{ + private readonly List _compositeSensors = new(); + private readonly HidDevice _device; + private readonly List _sensors = new(); + + public CorsairPsu(HidDevice device, ISettings settings, int index) + : base("Corsair PSU", new Identifier("psu", "corsair", index.ToString()), settings) + { + _device = device; + using HidStream stream = device.Open(); + + UsbApi.Init(stream); + UsbApi.FirmwareInfo fwInfo = UsbApi.FwInfo(stream); + Name = $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(fwInfo.Vendor.ToLowerInvariant())} {fwInfo.Product}"; + + AddSensors(UsbApi.GetOptionalCommands(stream), UsbApi.GetCriticals(stream), settings); } - // might need refactoring into two classes if AXi series API differs significantly - internal sealed class CorsairPsu : Hardware + public override HardwareType HardwareType => HardwareType.Psu; + + public override IDictionary Properties { - private readonly List _compositeSensors = new(); - private readonly HidDevice _device; - private readonly List _sensors = new(); - - public CorsairPsu(HidDevice device, ISettings settings, int index) - : base("Corsair PSU", new Identifier("psu", "corsair", index.ToString()), settings) + get { - _device = device; - using HidStream stream = device.Open(); + SortedDictionary properties = new(); - UsbApi.Init(stream); - UsbApi.FirmwareInfo fwInfo = UsbApi.FwInfo(stream); - Name = $"{CultureInfo.InvariantCulture.TextInfo.ToTitleCase(fwInfo.Vendor.ToLowerInvariant())} {fwInfo.Product}"; - - AddSensors(UsbApi.GetOptionalCommands(stream), UsbApi.GetCriticals(stream), settings); - } - - public override HardwareType HardwareType => HardwareType.Psu; - - public override IDictionary Properties - { - get - { - SortedDictionary properties = new(); - - using HidStream stream = _device.Open(); - - float? mode = UsbApi.GetValue(stream, UsbApi.Command.OCPMODE, 0); - if (mode.HasValue) - properties.Add("Over-current protection", mode > 1.0 ? "multi-rail" : "single-rail"); - - return properties; - } - } - - public override void Update() - { using HidStream stream = _device.Open(); - _sensors.ForEach(s => s.Update(stream)); - } - private void AddSensors(UsbApi.OptionalCommands optionalCommands, UsbApi.Criticals criticals, ISettings settings) - { - SensorIndices indices = new(); - _sensors.Add(new PsuSensorWithLimits("VRM", - indices, - SensorType.Temperature, - this, - settings, - UsbApi.Command.TEMP0, - null, - criticals.TempMax[0])); + float? mode = UsbApi.GetValue(stream, UsbApi.Command.OCPMODE, 0); + if (mode.HasValue) + properties.Add("Over-current protection", mode > 1.0 ? "multi-rail" : "single-rail"); - _sensors.Add(new PsuSensorWithLimits("Case", - indices, - SensorType.Temperature, - this, - settings, - UsbApi.Command.TEMP1, - null, - criticals.TempMax[1])); - - _sensors.Add(new PsuSensor("Case", indices, SensorType.Fan, this, settings, UsbApi.Command.FAN_RPM)); - - _sensors.Add(new PsuSensor("Input", indices, SensorType.Voltage, this, settings, UsbApi.Command.IN_VOLTS)); - _sensors.Add(new PsuSensorWithLimits("+12V", - indices, - SensorType.Voltage, - this, - settings, - UsbApi.Command.RAIL_VOLTS, - criticals.VoltageMin[(byte)Rail._12V], - criticals.VoltageMax[(byte)Rail._12V])); - - _sensors.Add(new PsuSensorWithLimits("+5V", - indices, - SensorType.Voltage, - this, - settings, - UsbApi.Command.RAIL_VOLTS, - criticals.VoltageMin[(byte)Rail._5V], - criticals.VoltageMax[(byte)Rail._5V], - Rail._5V)); - - _sensors.Add(new PsuSensorWithLimits("+3.3V", - indices, - SensorType.Voltage, - this, - settings, - UsbApi.Command.RAIL_VOLTS, - criticals.VoltageMin[(byte)Rail._3V], - criticals.VoltageMax[(byte)Rail._3V], - Rail._3V)); - - if (optionalCommands.HasFlag(UsbApi.OptionalCommands.InputCurrent)) - { - _sensors.Add(new PsuSensor("Input", indices, SensorType.Current, this, settings, UsbApi.Command.IN_AMPS)); - } - - _sensors.Add(new PsuSensorWithLimits("+12V", - indices, - SensorType.Current, - this, - settings, - UsbApi.Command.RAIL_AMPS, - null, - criticals.CurrentMax[(byte)Rail._12V])); - - _sensors.Add(new PsuSensorWithLimits("+5V", - indices, - SensorType.Current, - this, - settings, - UsbApi.Command.RAIL_AMPS, - null, - criticals.CurrentMax[(byte)Rail._5V], - Rail._5V)); - - _sensors.Add(new PsuSensorWithLimits("+3.3V", - indices, - SensorType.Current, - this, - settings, - UsbApi.Command.RAIL_AMPS, - null, - criticals.CurrentMax[(byte)Rail._3V], - Rail._3V)); - - PsuSensor[] powerRails = - { - new("+12V", indices, SensorType.Power, this, settings, UsbApi.Command.RAIL_WATTS), - new("+5V", indices, SensorType.Power, this, settings, UsbApi.Command.RAIL_WATTS, Rail._5V), - new("+3.3V", indices, SensorType.Power, this, settings, UsbApi.Command.RAIL_WATTS, Rail._3V) - }; - - _sensors.AddRange(powerRails); - _sensors.Add(new PsuSensor("Total watts", indices, SensorType.Power, this, settings, UsbApi.Command.TOTAL_WATTS)); - _compositeSensors.Add(new CompositeSensor("Total Output", - indices.NextIndex(SensorType.Power), - SensorType.Power, - this, - settings, - powerRails, - (acc, sensor) => acc + sensor.Value ?? 0f)); - - ActivateSensor(_compositeSensors[_compositeSensors.Count - 1]); - - _sensors.Add(new PsuSensor("Uptime", indices, SensorType.TimeSpan, this, settings, UsbApi.Command.UPTIME, Rail._12V, true)); - _sensors.Add(new PsuSensor("Total uptime", indices, SensorType.TimeSpan, this, settings, UsbApi.Command.TOTAL_UPTIME, Rail._12V, true)); - } - - private class PsuSensor : Sensor - { - private readonly UsbApi.Command _cmd; - private readonly byte _rail; - - public PsuSensor(string name, SensorIndices indices, SensorType type, CorsairPsu hardware, ISettings settings, UsbApi.Command cmd, Rail rail = Rail._12V, bool noHistory = false) - : base(name, indices.NextIndex(type), false, type, hardware, null, settings, noHistory) - { - _cmd = cmd; - _rail = (byte)rail; - - hardware.ActivateSensor(this); - } - - public void Update(HidStream stream) - { - Value = UsbApi.GetValue(stream, _cmd, _rail); - } - } - - private class PsuSensorWithLimits : PsuSensor, ICriticalSensorLimits - { - public PsuSensorWithLimits - ( - string name, - SensorIndices indices, - SensorType type, - CorsairPsu hardware, - ISettings settings, - UsbApi.Command cmd, - float? lowCritical, - float? highCritical, - Rail rail = Rail._12V) - : base(name, indices, type, hardware, settings, cmd, rail) - { - CriticalLowLimit = lowCritical; - CriticalHighLimit = highCritical; - } - - public float? CriticalHighLimit { get; } - - public float? CriticalLowLimit { get; } - } - - private enum Rail : byte - { - _12V = 0, - _5V = 1, - _3V = 2 + return properties; } } - #region Exception classes - - public class CommunicationProtocolError : ApplicationException + public override void Update() { - public CommunicationProtocolError(HidDevice device, string message) - : base($"Error communicating with the PSU controller at {device.DevicePath}: {message}") - { } + using HidStream stream = _device.Open(); + _sensors.ForEach(s => s.Update(stream)); } - #endregion - - #region PSU USB communication protocol implementation - - internal static class UsbApi + private void AddSensors(UsbApi.OptionalCommands optionalCommands, UsbApi.Criticals criticals, ISettings settings) { - /* some values are SMBus LINEAR11 data which need a conversion */ + SensorIndices indices = new(); + _sensors.Add(new PsuSensorWithLimits("VRM", + indices, + SensorType.Temperature, + this, + settings, + UsbApi.Command.TEMP0, + null, + criticals.TempMax[0])); + + _sensors.Add(new PsuSensorWithLimits("Case", + indices, + SensorType.Temperature, + this, + settings, + UsbApi.Command.TEMP1, + null, + criticals.TempMax[1])); + + _sensors.Add(new PsuSensor("Case", indices, SensorType.Fan, this, settings, UsbApi.Command.FAN_RPM)); + + _sensors.Add(new PsuSensor("Input", indices, SensorType.Voltage, this, settings, UsbApi.Command.IN_VOLTS)); + _sensors.Add(new PsuSensorWithLimits("+12V", + indices, + SensorType.Voltage, + this, + settings, + UsbApi.Command.RAIL_VOLTS, + criticals.VoltageMin[(byte)Rail._12V], + criticals.VoltageMax[(byte)Rail._12V])); + + _sensors.Add(new PsuSensorWithLimits("+5V", + indices, + SensorType.Voltage, + this, + settings, + UsbApi.Command.RAIL_VOLTS, + criticals.VoltageMin[(byte)Rail._5V], + criticals.VoltageMax[(byte)Rail._5V], + Rail._5V)); + + _sensors.Add(new PsuSensorWithLimits("+3.3V", + indices, + SensorType.Voltage, + this, + settings, + UsbApi.Command.RAIL_VOLTS, + criticals.VoltageMin[(byte)Rail._3V], + criticals.VoltageMax[(byte)Rail._3V], + Rail._3V)); + + if (optionalCommands.HasFlag(UsbApi.OptionalCommands.InputCurrent)) + { + _sensors.Add(new PsuSensor("Input", indices, SensorType.Current, this, settings, UsbApi.Command.IN_AMPS)); + } + + _sensors.Add(new PsuSensorWithLimits("+12V", + indices, + SensorType.Current, + this, + settings, + UsbApi.Command.RAIL_AMPS, + null, + criticals.CurrentMax[(byte)Rail._12V])); + + _sensors.Add(new PsuSensorWithLimits("+5V", + indices, + SensorType.Current, + this, + settings, + UsbApi.Command.RAIL_AMPS, + null, + criticals.CurrentMax[(byte)Rail._5V], + Rail._5V)); + + _sensors.Add(new PsuSensorWithLimits("+3.3V", + indices, + SensorType.Current, + this, + settings, + UsbApi.Command.RAIL_AMPS, + null, + criticals.CurrentMax[(byte)Rail._3V], + Rail._3V)); + + PsuSensor[] powerRails = + { + new("+12V", indices, SensorType.Power, this, settings, UsbApi.Command.RAIL_WATTS), + new("+5V", indices, SensorType.Power, this, settings, UsbApi.Command.RAIL_WATTS, Rail._5V), + new("+3.3V", indices, SensorType.Power, this, settings, UsbApi.Command.RAIL_WATTS, Rail._3V) + }; + + _sensors.AddRange(powerRails); + _sensors.Add(new PsuSensor("Total watts", indices, SensorType.Power, this, settings, UsbApi.Command.TOTAL_WATTS)); + _compositeSensors.Add(new CompositeSensor("Total Output", + indices.NextIndex(SensorType.Power), + SensorType.Power, + this, + settings, + powerRails, + (acc, sensor) => acc + sensor.Value ?? 0f)); + + ActivateSensor(_compositeSensors[_compositeSensors.Count - 1]); + + _sensors.Add(new PsuSensor("Uptime", indices, SensorType.TimeSpan, this, settings, UsbApi.Command.UPTIME, Rail._12V, true)); + _sensors.Add(new PsuSensor("Total uptime", indices, SensorType.TimeSpan, this, settings, UsbApi.Command.TOTAL_UPTIME, Rail._12V, true)); + } + + private class PsuSensor : Sensor + { + private readonly UsbApi.Command _cmd; + private readonly byte _rail; + + public PsuSensor(string name, SensorIndices indices, SensorType type, CorsairPsu hardware, ISettings settings, UsbApi.Command cmd, Rail rail = Rail._12V, bool noHistory = false) + : base(name, indices.NextIndex(type), false, type, hardware, null, settings, noHistory) + { + _cmd = cmd; + _rail = (byte)rail; + + hardware.ActivateSensor(this); + } + + public void Update(HidStream stream) + { + Value = UsbApi.GetValue(stream, _cmd, _rail); + } + } + + private class PsuSensorWithLimits : PsuSensor, ICriticalSensorLimits + { + public PsuSensorWithLimits + ( + string name, + SensorIndices indices, + SensorType type, + CorsairPsu hardware, + ISettings settings, + UsbApi.Command cmd, + float? lowCritical, + float? highCritical, + Rail rail = Rail._12V) + : base(name, indices, type, hardware, settings, cmd, rail) + { + CriticalLowLimit = lowCritical; + CriticalHighLimit = highCritical; + } + + public float? CriticalHighLimit { get; } + + public float? CriticalLowLimit { get; } + } + + private enum Rail : byte + { + _12V = 0, + _5V = 1, + _3V = 2 + } +} + +#region Exception classes + +public class CommunicationProtocolError : ApplicationException +{ + public CommunicationProtocolError(HidDevice device, string message) + : base($"Error communicating with the PSU controller at {device.DevicePath}: {message}") + { } +} + +#endregion + +#region PSU USB communication protocol implementation + +internal static class UsbApi +{ + /* some values are SMBus LINEAR11 data which need a conversion */ #if false static int Linear11ToInt(ushort val, int scale) { @@ -263,227 +263,226 @@ namespace LibreHardwareMonitor.Hardware.Psu.Corsair return (exp >= 0) ? (result << exp) : (result >> -exp); } #endif - static float Linear11ToFloat32(ushort val) - { - int exp = (short)val >> 11; - int mant = ((short)(val & 0x7ff) << 5) >> 5; - return mant * (float)Math.Pow(2, exp); - } - - static bool SendCommand(HidStream stream, byte length, Command cmd, byte arg, out byte[] replyData) - { - /* - * Corsair protocol for PSUs - * - * message size = 64 bytes (request and response, little endian) - * request: - * [length][command][param0][param1][paramX]... - * reply: - * [echo of length][echo of command][data0][data1][dataX]... - * - * - commands are byte sized opcodes - * - length is the sum of all bytes of the commands/params - * - the micro-controller of most of these PSUs support concatenation in the request and reply, - * but it is better to not rely on this (it is also hard to parse) - * - the driver uses raw events to be accessible from userspace (though this is not really - * supported, it is just there for convenience, may be removed in the future) - * - a reply always start with the length and command in the same order the request used it - * - length of the reply data is specific to the command used - * - some of the commands work on a rail and can be switched to a specific rail (0 = 12v, - * 1 = 5v, 2 = 3.3v) - * - the format of the init command 0xFE is swapped length/command bytes - * - parameter bytes amount and values are specific to the command (rail setting is the only - * for now that uses non-zero values) - * - there are much more commands, especially for configuring the device, but they are not - * supported because a wrong command/length can lockup the micro-controller - * - the driver supports debugfs for values not fitting into the hwmon class - * - not every device class (HXi, RMi or AXi) supports all commands - * - it is a pure sensors reading driver (will not support configuring) - */ - - const int cmdBufferSize = 64; - const int replySize = 16; - - byte[] cmdBuffer = new byte[cmdBufferSize + 1]; - cmdBuffer[0] = 0; // report id - cmdBuffer[1] = length; - cmdBuffer[2] = (byte)cmd; - cmdBuffer[3] = arg; - - stream.Write(cmdBuffer); - byte[] reply = stream.Read(); - replyData = new byte[replySize]; - Array.Copy(reply, 3, replyData, 0, replySize); - - return reply[1] == cmdBuffer[1] && reply[2] == cmdBuffer[2]; - } - - public static void Init(HidStream stream) - { - /* - * PSU_CMD_INIT uses swapped length/command and expects 2 parameter bytes, this command - * actually generates a reply, but we don't need it - */ - SendCommand(stream, (byte)Command.INIT, (Command)3, 0, out _); - } - - public struct FirmwareInfo - { - public string Vendor; - public string Product; - } - - public static FirmwareInfo FwInfo(HidStream stream) - { - if (!SendCommand(stream, 3, Command.VEND_STR, 0, out byte[] vendorArr)) - throw new CommunicationProtocolError(stream.Device, "Can't read vendor string"); - - if (!SendCommand(stream, 3, Command.PROD_STR, 0, out byte[] productArr)) - throw new CommunicationProtocolError(stream.Device, "Can't read product"); - - string ArrayToString(byte[] ar) - { - int i = 0; - while (ar[i] != 0) - i++; - - byte[] trimmed = new byte[i]; - for (int j = 0; j < i; j++) - trimmed[j] = ar[j]; - - return Encoding.ASCII.GetString(trimmed); - } - - return new FirmwareInfo { Vendor = ArrayToString(vendorArr), Product = ArrayToString(productArr) }; - } - - static bool Request(HidStream stream, Command cmd, byte rail, out byte[] data) - { - //mutex_lock(&priv->lock) ; - switch (cmd) - { - case Command.RAIL_VOLTS_HCRIT: - case Command.RAIL_VOLTS_LCRIT: - case Command.RAIL_AMPS_HCRIT: - case Command.RAIL_VOLTS: - case Command.RAIL_AMPS: - case Command.RAIL_WATTS: - if (!SendCommand(stream, 2, Command.SELECT_RAIL, rail, out _)) - { - data = null; - return false; - } - - break; - } - - return SendCommand(stream, 3, cmd, 0, out data); - - // mutex_unlock(&priv->lock) ; - // return ret; - } - - public static float? GetValue(HidStream stream, Command cmd, byte rail) - { - if (!Request(stream, cmd, rail, out byte[] data)) - { - return null; - } - - /* - * the biggest value here comes from the uptime command and to exceed MAXINT total uptime - * needs to be about 68 years, the rest are u16 values and the biggest value coming out of - * the LINEAR11 conversion are the watts values which are about 1200 for the strongest psu - * supported (HX1200i) - */ - int tmp = BitConverter.ToInt32(data, 0); // ((int)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]; - return cmd switch - { - Command.RAIL_VOLTS_HCRIT or Command.RAIL_VOLTS_LCRIT or Command.RAIL_AMPS_HCRIT or Command.TEMP_HCRIT or Command.IN_VOLTS or Command.IN_AMPS or Command.RAIL_VOLTS or Command.RAIL_AMPS - or Command.TEMP0 or Command.TEMP1 or Command.FAN_RPM or Command.RAIL_WATTS or Command.TOTAL_WATTS => Linear11ToFloat32((ushort)tmp), // Linear11ToInt((ushort)tmp, 1000000); - Command.TOTAL_UPTIME or Command.UPTIME or Command.OCPMODE => tmp, - _ => null - }; - } - - public struct Criticals - { - public float?[] TempMax; - - public float?[] VoltageMin; - public float?[] VoltageMax; - - public float?[] CurrentMax; - } - - public static Criticals GetCriticals(HidStream stream) - { - Criticals res = new(); - const byte tempCount = 2; - res.TempMax = new float?[tempCount]; - - for (byte rail = 0; rail < tempCount; rail++) - { - res.TempMax[rail] = GetValue(stream, Command.TEMP_HCRIT, rail); - } - - const byte railCount = 3; /* 3v + 5v + 12v */ - res.VoltageMin = new float?[railCount]; - res.VoltageMax = new float?[railCount]; - res.CurrentMax = new float?[railCount]; - - for (byte rail = 0; rail < railCount; rail++) - { - res.VoltageMax[rail] = GetValue(stream, Command.RAIL_VOLTS_HCRIT, rail); - res.VoltageMin[rail] = GetValue(stream, Command.RAIL_VOLTS_LCRIT, rail); - res.CurrentMax[rail] = GetValue(stream, Command.RAIL_AMPS_HCRIT, rail); - } - - return res; - } - - [Flags] - public enum OptionalCommands - { - None = 0x0, - InputCurrent = 0x1 - } - - public static OptionalCommands GetOptionalCommands(HidStream stream) - { - OptionalCommands res = OptionalCommands.None; - if (GetValue(stream, Command.IN_AMPS, 0).HasValue) - { - res |= OptionalCommands.InputCurrent; - } - - return res; - } - - public enum Command : byte - { - SELECT_RAIL = 0x00, /* expects length 2 */ - RAIL_VOLTS_HCRIT = 0x40, /* the rest of the commands expect length 3 */ - RAIL_VOLTS_LCRIT = 0x44, - RAIL_AMPS_HCRIT = 0x46, - TEMP_HCRIT = 0x4F, - IN_VOLTS = 0x88, - IN_AMPS = 0x89, - RAIL_VOLTS = 0x8B, - RAIL_AMPS = 0x8C, - TEMP0 = 0x8D, - TEMP1 = 0x8E, - FAN_RPM = 0x90, - RAIL_WATTS = 0x96, - VEND_STR = 0x99, - PROD_STR = 0x9A, - TOTAL_UPTIME = 0xD1, - UPTIME = 0xD2, - OCPMODE = 0xD8, - TOTAL_WATTS = 0xEE, - INIT = 0xFE - } + static float Linear11ToFloat32(ushort val) + { + int exp = (short)val >> 11; + int mant = ((short)(val & 0x7ff) << 5) >> 5; + return mant * (float)Math.Pow(2, exp); } - #endregion + static bool SendCommand(HidStream stream, byte length, Command cmd, byte arg, out byte[] replyData) + { + /* + * Corsair protocol for PSUs + * + * message size = 64 bytes (request and response, little endian) + * request: + * [length][command][param0][param1][paramX]... + * reply: + * [echo of length][echo of command][data0][data1][dataX]... + * + * - commands are byte sized opcodes + * - length is the sum of all bytes of the commands/params + * - the micro-controller of most of these PSUs support concatenation in the request and reply, + * but it is better to not rely on this (it is also hard to parse) + * - the driver uses raw events to be accessible from userspace (though this is not really + * supported, it is just there for convenience, may be removed in the future) + * - a reply always start with the length and command in the same order the request used it + * - length of the reply data is specific to the command used + * - some of the commands work on a rail and can be switched to a specific rail (0 = 12v, + * 1 = 5v, 2 = 3.3v) + * - the format of the init command 0xFE is swapped length/command bytes + * - parameter bytes amount and values are specific to the command (rail setting is the only + * for now that uses non-zero values) + * - there are much more commands, especially for configuring the device, but they are not + * supported because a wrong command/length can lockup the micro-controller + * - the driver supports debugfs for values not fitting into the hwmon class + * - not every device class (HXi, RMi or AXi) supports all commands + * - it is a pure sensors reading driver (will not support configuring) + */ + + const int cmdBufferSize = 64; + const int replySize = 16; + + byte[] cmdBuffer = new byte[cmdBufferSize + 1]; + cmdBuffer[0] = 0; // report id + cmdBuffer[1] = length; + cmdBuffer[2] = (byte)cmd; + cmdBuffer[3] = arg; + + stream.Write(cmdBuffer); + byte[] reply = stream.Read(); + replyData = new byte[replySize]; + Array.Copy(reply, 3, replyData, 0, replySize); + + return reply[1] == cmdBuffer[1] && reply[2] == cmdBuffer[2]; + } + + public static void Init(HidStream stream) + { + /* + * PSU_CMD_INIT uses swapped length/command and expects 2 parameter bytes, this command + * actually generates a reply, but we don't need it + */ + SendCommand(stream, (byte)Command.INIT, (Command)3, 0, out _); + } + + public struct FirmwareInfo + { + public string Vendor; + public string Product; + } + + public static FirmwareInfo FwInfo(HidStream stream) + { + if (!SendCommand(stream, 3, Command.VEND_STR, 0, out byte[] vendorArr)) + throw new CommunicationProtocolError(stream.Device, "Can't read vendor string"); + + if (!SendCommand(stream, 3, Command.PROD_STR, 0, out byte[] productArr)) + throw new CommunicationProtocolError(stream.Device, "Can't read product"); + + string ArrayToString(byte[] ar) + { + int i = 0; + while (ar[i] != 0) + i++; + + byte[] trimmed = new byte[i]; + for (int j = 0; j < i; j++) + trimmed[j] = ar[j]; + + return Encoding.ASCII.GetString(trimmed); + } + + return new FirmwareInfo { Vendor = ArrayToString(vendorArr), Product = ArrayToString(productArr) }; + } + + static bool Request(HidStream stream, Command cmd, byte rail, out byte[] data) + { + //mutex_lock(&priv->lock) ; + switch (cmd) + { + case Command.RAIL_VOLTS_HCRIT: + case Command.RAIL_VOLTS_LCRIT: + case Command.RAIL_AMPS_HCRIT: + case Command.RAIL_VOLTS: + case Command.RAIL_AMPS: + case Command.RAIL_WATTS: + if (!SendCommand(stream, 2, Command.SELECT_RAIL, rail, out _)) + { + data = null; + return false; + } + + break; + } + + return SendCommand(stream, 3, cmd, 0, out data); + + // mutex_unlock(&priv->lock) ; + // return ret; + } + + public static float? GetValue(HidStream stream, Command cmd, byte rail) + { + if (!Request(stream, cmd, rail, out byte[] data)) + { + return null; + } + + /* + * the biggest value here comes from the uptime command and to exceed MAXINT total uptime + * needs to be about 68 years, the rest are u16 values and the biggest value coming out of + * the LINEAR11 conversion are the watts values which are about 1200 for the strongest psu + * supported (HX1200i) + */ + int tmp = BitConverter.ToInt32(data, 0); // ((int)data[3] << 24) + (data[2] << 16) + (data[1] << 8) + data[0]; + return cmd switch + { + Command.RAIL_VOLTS_HCRIT or Command.RAIL_VOLTS_LCRIT or Command.RAIL_AMPS_HCRIT or Command.TEMP_HCRIT or Command.IN_VOLTS or Command.IN_AMPS or Command.RAIL_VOLTS or Command.RAIL_AMPS + or Command.TEMP0 or Command.TEMP1 or Command.FAN_RPM or Command.RAIL_WATTS or Command.TOTAL_WATTS => Linear11ToFloat32((ushort)tmp), // Linear11ToInt((ushort)tmp, 1000000); + Command.TOTAL_UPTIME or Command.UPTIME or Command.OCPMODE => tmp, + _ => null + }; + } + + public struct Criticals + { + public float?[] TempMax; + + public float?[] VoltageMin; + public float?[] VoltageMax; + + public float?[] CurrentMax; + } + + public static Criticals GetCriticals(HidStream stream) + { + Criticals res = new(); + const byte tempCount = 2; + res.TempMax = new float?[tempCount]; + + for (byte rail = 0; rail < tempCount; rail++) + { + res.TempMax[rail] = GetValue(stream, Command.TEMP_HCRIT, rail); + } + + const byte railCount = 3; /* 3v + 5v + 12v */ + res.VoltageMin = new float?[railCount]; + res.VoltageMax = new float?[railCount]; + res.CurrentMax = new float?[railCount]; + + for (byte rail = 0; rail < railCount; rail++) + { + res.VoltageMax[rail] = GetValue(stream, Command.RAIL_VOLTS_HCRIT, rail); + res.VoltageMin[rail] = GetValue(stream, Command.RAIL_VOLTS_LCRIT, rail); + res.CurrentMax[rail] = GetValue(stream, Command.RAIL_AMPS_HCRIT, rail); + } + + return res; + } + + [Flags] + public enum OptionalCommands + { + None = 0x0, + InputCurrent = 0x1 + } + + public static OptionalCommands GetOptionalCommands(HidStream stream) + { + OptionalCommands res = OptionalCommands.None; + if (GetValue(stream, Command.IN_AMPS, 0).HasValue) + { + res |= OptionalCommands.InputCurrent; + } + + return res; + } + + public enum Command : byte + { + SELECT_RAIL = 0x00, /* expects length 2 */ + RAIL_VOLTS_HCRIT = 0x40, /* the rest of the commands expect length 3 */ + RAIL_VOLTS_LCRIT = 0x44, + RAIL_AMPS_HCRIT = 0x46, + TEMP_HCRIT = 0x4F, + IN_VOLTS = 0x88, + IN_AMPS = 0x89, + RAIL_VOLTS = 0x8B, + RAIL_AMPS = 0x8C, + TEMP0 = 0x8D, + TEMP1 = 0x8E, + FAN_RPM = 0x90, + RAIL_WATTS = 0x96, + VEND_STR = 0x99, + PROD_STR = 0x9A, + TOTAL_UPTIME = 0xD1, + UPTIME = 0xD2, + OCPMODE = 0xD8, + TOTAL_WATTS = 0xEE, + INIT = 0xFE + } } + +#endregion diff --git a/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsuGroup.cs b/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsuGroup.cs index 3b6103e..e039f8b 100644 --- a/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsuGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Psu/Corsair/CorsairPsuGroup.cs @@ -9,63 +9,62 @@ using System.Linq; using System.Text; using HidSharp; -namespace LibreHardwareMonitor.Hardware.Psu.Corsair +namespace LibreHardwareMonitor.Hardware.Psu.Corsair; + +public class CorsairPsuGroup : IGroup { - public class CorsairPsuGroup : IGroup + private static readonly int[] _productIds = { - private static readonly int[] _productIds = + 0x1c03, // HX550i + 0x1c04, // HX650i + 0x1c05, // HX750i + 0x1c06, // HX850i + 0x1c07, // HX1000i + 0x1c08, // HX1200i + 0x1c09, // RM550i + 0x1c0a, // RM650i + 0x1c0b, // RM750i + 0x1c0c, // RM850i + 0x1c0d // RM1000i + // 0x1c11, // AX1600i + }; + + private static readonly ushort _vendorId = 0x1b1c; + private readonly List _hardware; + private readonly StringBuilder _report; + + public CorsairPsuGroup(ISettings settings) + { + _report = new StringBuilder(); + _report.AppendLine("Corsair HXi/RMi series PSU Hardware"); + _report.AppendLine(); + + _hardware = new List(); + foreach (HidDevice dev in DeviceList.Local.GetHidDevices(_vendorId)) { - 0x1c03, // HX550i - 0x1c04, // HX650i - 0x1c05, // HX750i - 0x1c06, // HX850i - 0x1c07, // HX1000i - 0x1c08, // HX1200i - 0x1c09, // RM550i - 0x1c0a, // RM650i - 0x1c0b, // RM750i - 0x1c0c, // RM850i - 0x1c0d // RM1000i - // 0x1c11, // AX1600i - }; - - private static readonly ushort _vendorId = 0x1b1c; - private readonly List _hardware; - private readonly StringBuilder _report; - - public CorsairPsuGroup(ISettings settings) - { - _report = new StringBuilder(); - _report.AppendLine("Corsair HXi/RMi series PSU Hardware"); - _report.AppendLine(); - - _hardware = new List(); - foreach (HidDevice dev in DeviceList.Local.GetHidDevices(_vendorId)) + if (_productIds.Contains(dev.ProductID)) { - if (_productIds.Contains(dev.ProductID)) - { - var device = new CorsairPsu(dev, settings, _hardware.Count); - _hardware.Add(device); - _report.AppendLine($"Device name: {device.Name}"); - _report.AppendLine(); - } + var device = new CorsairPsu(dev, settings, _hardware.Count); + _hardware.Add(device); + _report.AppendLine($"Device name: {device.Name}"); + _report.AppendLine(); } } - - public IReadOnlyList Hardware => _hardware; - - public void Close() - { - foreach (IHardware iHardware in _hardware) - { - if (iHardware is Hardware hardware) - hardware.Close(); - } - } - - public string GetReport() - { - return _report.ToString(); - } + } + + public IReadOnlyList Hardware => _hardware; + + public void Close() + { + foreach (IHardware iHardware in _hardware) + { + if (iHardware is Hardware hardware) + hardware.Close(); + } + } + + public string GetReport() + { + return _report.ToString(); } } diff --git a/LibreHardwareMonitorLib/Hardware/Ring0.cs b/LibreHardwareMonitorLib/Hardware/Ring0.cs index 75f11eb..91ba0f6 100644 --- a/LibreHardwareMonitorLib/Hardware/Ring0.cs +++ b/LibreHardwareMonitorLib/Hardware/Ring0.cs @@ -14,166 +14,166 @@ using System.Security.Principal; using System.Text; using System.Threading; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal static class Ring0 { - internal static class Ring0 + private static KernelDriver _driver; + private static Mutex _ecMutex; + private static string _filePath; + private static Mutex _isaBusMutex; + private static Mutex _pciBusMutex; + + private static readonly StringBuilder _report = new(); + + public static bool IsOpen => _driver != null; + + public static void Open() { - private static KernelDriver _driver; - private static Mutex _ecMutex; - private static string _filePath; - private static Mutex _isaBusMutex; - private static Mutex _pciBusMutex; + // no implementation for unix systems + if (Software.OperatingSystem.IsUnix) + return; - private static readonly StringBuilder _report = new(); + if (_driver != null) + return; - public static bool IsOpen => _driver != null; + // clear the current report + _report.Length = 0; - public static void Open() + _driver = new KernelDriver(GetServiceName(), "WinRing0_1_2_0"); + _driver.Open(); + + if (!_driver.IsOpen) { - // no implementation for unix systems - if (Software.OperatingSystem.IsUnix) - return; - - if (_driver != null) - return; - - // clear the current report - _report.Length = 0; - - _driver = new KernelDriver(GetServiceName(), "WinRing0_1_2_0"); - _driver.Open(); - - if (!_driver.IsOpen) + // driver is not loaded, try to install and open + _filePath = GetFilePath(); + if (_filePath != null && ExtractDriver(_filePath)) { - // driver is not loaded, try to install and open - _filePath = GetFilePath(); - if (_filePath != null && ExtractDriver(_filePath)) + if (_driver.Install(_filePath, out string installError)) { - if (_driver.Install(_filePath, out string installError)) + _driver.Open(); + + if (!_driver.IsOpen) + _report.AppendLine("Status: Opening driver failed after install"); + } + else + { + // install failed, try to delete and reinstall + _driver.Delete(); + + // wait a short moment to give the OS a chance to remove the driver + Thread.Sleep(2000); + + if (_driver.Install(_filePath, out string secondError)) { _driver.Open(); if (!_driver.IsOpen) - _report.AppendLine("Status: Opening driver failed after install"); + _report.AppendLine("Status: Opening driver failed after reinstall"); } else { - // install failed, try to delete and reinstall - _driver.Delete(); - - // wait a short moment to give the OS a chance to remove the driver - Thread.Sleep(2000); - - if (_driver.Install(_filePath, out string secondError)) - { - _driver.Open(); - - if (!_driver.IsOpen) - _report.AppendLine("Status: Opening driver failed after reinstall"); - } - else - { - _report.Append("Status: Installing driver \"").Append(_filePath).Append("\" failed").AppendLine(File.Exists(_filePath) ? " and file exists" : string.Empty); - _report.Append("First Exception: ").AppendLine(installError); - _report.Append("Second Exception: ").AppendLine(secondError); - } - } - - if (!_driver.IsOpen) - { - _driver.Delete(); - DeleteDriver(); + _report.Append("Status: Installing driver \"").Append(_filePath).Append("\" failed").AppendLine(File.Exists(_filePath) ? " and file exists" : string.Empty); + _report.Append("First Exception: ").AppendLine(installError); + _report.Append("Second Exception: ").AppendLine(secondError); } } - else + + if (!_driver.IsOpen) { - _report.AppendLine("Status: Extracting driver failed"); + _driver.Delete(); + DeleteDriver(); } } - - if (!_driver.IsOpen) - _driver = null; - - const string isaMutexName = "Global\\Access_ISABUS.HTP.Method"; - if (!TryCreateOrOpenExistingMutex(isaMutexName, out _isaBusMutex)) + else { - // Mutex could not be created or opened. - } - - const string pciMutexName = "Global\\Access_PCI"; - if (!TryCreateOrOpenExistingMutex(pciMutexName, out _pciBusMutex)) - { - // Mutex could not be created or opened. - } - - const string ecMutexName = "Global\\Access_EC"; - if (!TryCreateOrOpenExistingMutex(ecMutexName, out _ecMutex)) - { - // Mutex could not be created or opened. + _report.AppendLine("Status: Extracting driver failed"); } } - private static bool ExtractDriver(string filePath) + if (!_driver.IsOpen) + _driver = null; + + const string isaMutexName = "Global\\Access_ISABUS.HTP.Method"; + if (!TryCreateOrOpenExistingMutex(isaMutexName, out _isaBusMutex)) { - string resourceName = $"{nameof(LibreHardwareMonitor)}.Resources.{(Software.OperatingSystem.Is64Bit ? "WinRing0x64.sys" : "WinRing0.sys")}"; - Assembly assembly = typeof(Ring0).Assembly; + // Mutex could not be created or opened. + } - string[] names = assembly.GetManifestResourceNames(); - byte[] buffer = null; + const string pciMutexName = "Global\\Access_PCI"; + if (!TryCreateOrOpenExistingMutex(pciMutexName, out _pciBusMutex)) + { + // Mutex could not be created or opened. + } - for (int i = 0; i < names.Length; i++) + const string ecMutexName = "Global\\Access_EC"; + if (!TryCreateOrOpenExistingMutex(ecMutexName, out _ecMutex)) + { + // Mutex could not be created or opened. + } + } + + private static bool ExtractDriver(string filePath) + { + string resourceName = $"{nameof(LibreHardwareMonitor)}.Resources.{(Software.OperatingSystem.Is64Bit ? "WinRing0x64.sys" : "WinRing0.sys")}"; + Assembly assembly = typeof(Ring0).Assembly; + + string[] names = assembly.GetManifestResourceNames(); + byte[] buffer = null; + + for (int i = 0; i < names.Length; i++) + { + if (names[i].Replace('\\', '.') == resourceName) { - if (names[i].Replace('\\', '.') == resourceName) - { - using Stream stream = assembly.GetManifestResourceStream(names[i]); + using Stream stream = assembly.GetManifestResourceStream(names[i]); - if (stream != null) - { - buffer = new byte[stream.Length]; - stream.Read(buffer, 0, buffer.Length); - } + if (stream != null) + { + buffer = new byte[stream.Length]; + stream.Read(buffer, 0, buffer.Length); } } + } - if (buffer == null) - return false; + if (buffer == null) + return false; - try - { - using FileStream target = new(filePath, FileMode.Create); + try + { + using FileStream target = new(filePath, FileMode.Create); - target.Write(buffer, 0, buffer.Length); - target.Flush(); - } - catch (IOException) - { - // for example there is not enough space on the disk - return false; - } - - // make sure the file is actually written to the file system - var stopwatch = new Stopwatch(); - stopwatch.Start(); - - while (stopwatch.ElapsedMilliseconds < 2000) - { - try - { - if (File.Exists(filePath) && new FileInfo(filePath).Length == buffer.Length) - return true; - } - catch - { } - - Thread.Sleep(1); - } - - // file still has not the right size, something is wrong + target.Write(buffer, 0, buffer.Length); + target.Flush(); + } + catch (IOException) + { + // for example there is not enough space on the disk return false; } - private static bool TryCreateOrOpenExistingMutex(string name, out Mutex mutex) + // make sure the file is actually written to the file system + var stopwatch = new Stopwatch(); + stopwatch.Start(); + + while (stopwatch.ElapsedMilliseconds < 2000) { + try + { + if (File.Exists(filePath) && new FileInfo(filePath).Length == buffer.Length) + return true; + } + catch + { } + + Thread.Sleep(1); + } + + // file still has not the right size, something is wrong + return false; + } + + private static bool TryCreateOrOpenExistingMutex(string name, out Mutex mutex) + { #if NETFRAMEWORK MutexSecurity mutexSecurity = new(); SecurityIdentifier identity = new(WellKnownSidType.WorldSid, null); @@ -197,410 +197,409 @@ namespace LibreHardwareMonitor.Hardware return false; } #else + try + { + mutex = new Mutex(false, name); + return true; + } + catch (UnauthorizedAccessException) + { try { - mutex = new Mutex(false, name); + mutex = Mutex.OpenExisting(name); return true; } - catch (UnauthorizedAccessException) - { - try - { - mutex = Mutex.OpenExisting(name); - return true; - } - catch { } + catch { } - mutex = null; - } - return false; + mutex = null; + } + return false; #endif - } + } - private static void DeleteDriver() + private static void DeleteDriver() + { + try { - try - { - // Try to delete the driver file - if (_filePath != null && File.Exists(_filePath)) - File.Delete(_filePath); + // Try to delete the driver file + if (_filePath != null && File.Exists(_filePath)) + File.Delete(_filePath); - _filePath = null; - } - catch + _filePath = null; + } + catch + { + // Mutex could not be created or opened + } + } + + private static string GetServiceName() + { + string name; + + try + { + ProcessModule processModule = Process.GetCurrentProcess().MainModule; + if (!string.IsNullOrEmpty(processModule?.FileName)) { - // Mutex could not be created or opened + name = Path.GetFileNameWithoutExtension(processModule.FileName); + if (!string.IsNullOrEmpty(name)) + return GetName(name); } } - - private static string GetServiceName() + catch { - string name; + // Continue with the other options. + } - try - { - ProcessModule processModule = Process.GetCurrentProcess().MainModule; - if (!string.IsNullOrEmpty(processModule?.FileName)) - { - name = Path.GetFileNameWithoutExtension(processModule.FileName); - if (!string.IsNullOrEmpty(name)) - return GetName(name); - } - } - catch - { - // Continue with the other options. - } - - name = GetNameFromAssembly(Assembly.GetExecutingAssembly()); - if (!string.IsNullOrEmpty(name)) - return GetName(name); - - name = GetNameFromAssembly(typeof(Ring0).Assembly); - if (!string.IsNullOrEmpty(name)) - return GetName(name); - - name = nameof(LibreHardwareMonitor); + name = GetNameFromAssembly(Assembly.GetExecutingAssembly()); + if (!string.IsNullOrEmpty(name)) return GetName(name); - static string GetNameFromAssembly(Assembly assembly) - { - return assembly?.GetName().Name; - } + name = GetNameFromAssembly(typeof(Ring0).Assembly); + if (!string.IsNullOrEmpty(name)) + return GetName(name); - static string GetName(string name) - { - return $"R0{name}".Replace(" ", string.Empty).Replace(".", "_"); - } + name = nameof(LibreHardwareMonitor); + return GetName(name); + + static string GetNameFromAssembly(Assembly assembly) + { + return assembly?.GetName().Name; } - private static string GetFilePath() + static string GetName(string name) { - string filePath; + return $"R0{name}".Replace(" ", string.Empty).Replace(".", "_"); + } + } + private static string GetFilePath() + { + string filePath; + + try + { + ProcessModule processModule = Process.GetCurrentProcess().MainModule; + if (!string.IsNullOrEmpty(processModule?.FileName)) + { + filePath = Path.ChangeExtension(processModule.FileName, ".sys"); + if (TryCreate(filePath)) + return filePath; + } + } + catch + { + // Continue with the other options. + } + + filePath = GetPathFromAssembly(Assembly.GetExecutingAssembly()); + if (!string.IsNullOrEmpty(filePath) && TryCreate(filePath)) + return filePath; + + filePath = GetPathFromAssembly(typeof(Ring0).Assembly); + if (!string.IsNullOrEmpty(filePath) && TryCreate(filePath)) + return filePath; + + try + { + filePath = Path.GetTempFileName(); + if (!string.IsNullOrEmpty(filePath)) + { + filePath = Path.ChangeExtension(filePath, ".sys"); + if (TryCreate(filePath)) + return filePath; + } + } + catch + { + return null; + } + + return null; + + static string GetPathFromAssembly(Assembly assembly) + { try { - ProcessModule processModule = Process.GetCurrentProcess().MainModule; - if (!string.IsNullOrEmpty(processModule?.FileName)) - { - filePath = Path.ChangeExtension(processModule.FileName, ".sys"); - if (TryCreate(filePath)) - return filePath; - } - } - catch - { - // Continue with the other options. - } - - filePath = GetPathFromAssembly(Assembly.GetExecutingAssembly()); - if (!string.IsNullOrEmpty(filePath) && TryCreate(filePath)) - return filePath; - - filePath = GetPathFromAssembly(typeof(Ring0).Assembly); - if (!string.IsNullOrEmpty(filePath) && TryCreate(filePath)) - return filePath; - - try - { - filePath = Path.GetTempFileName(); - if (!string.IsNullOrEmpty(filePath)) - { - filePath = Path.ChangeExtension(filePath, ".sys"); - if (TryCreate(filePath)) - return filePath; - } + string location = assembly?.Location; + return !string.IsNullOrEmpty(location) ? Path.ChangeExtension(location, ".sys") : null; } catch { return null; } - - return null; - - static string GetPathFromAssembly(Assembly assembly) - { - try - { - string location = assembly?.Location; - return !string.IsNullOrEmpty(location) ? Path.ChangeExtension(location, ".sys") : null; - } - catch - { - return null; - } - } - - static bool TryCreate(string path) - { - try - { - using (File.Create(path)) - return true; - } - catch - { - return false; - } - } } - public static void Close() + static bool TryCreate(string path) { - if (_driver != null) - { - uint refCount = 0; - _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_GET_REFCOUNT, null, ref refCount); - _driver.Close(); - - if (refCount <= 1) - _driver.Delete(); - - _driver = null; - } - - if (_isaBusMutex != null) - { - _isaBusMutex.Close(); - _isaBusMutex = null; - } - - if (_pciBusMutex != null) - { - _pciBusMutex.Close(); - _pciBusMutex = null; - } - - if (_ecMutex != null) - { - _ecMutex.Close(); - _ecMutex = null; - } - - // try to delete temporary driver file again if failed during open - DeleteDriver(); - } - - public static string GetReport() - { - if (_report.Length > 0) - { - StringBuilder r = new(); - r.AppendLine("Ring0"); - r.AppendLine(); - r.Append(_report); - r.AppendLine(); - return r.ToString(); - } - - return null; - } - - public static bool WaitIsaBusMutex(int millisecondsTimeout) - { - if (_isaBusMutex == null) - return true; - try { - return _isaBusMutex.WaitOne(millisecondsTimeout, false); + using (File.Create(path)) + return true; } - catch (AbandonedMutexException) - { - return true; - } - catch (InvalidOperationException) + catch { return false; } } - - public static void ReleaseIsaBusMutex() - { - _isaBusMutex?.ReleaseMutex(); - } - - public static bool WaitPciBusMutex(int millisecondsTimeout) - { - if (_pciBusMutex == null) - return true; - - try - { - return _pciBusMutex.WaitOne(millisecondsTimeout, false); - } - catch (AbandonedMutexException) - { - return true; - } - catch (InvalidOperationException) - { - return false; - } - } - - public static void ReleasePciBusMutex() - { - _pciBusMutex?.ReleaseMutex(); - } - - public static bool WaitEcMutex(int millisecondsTimeout) - { - if (_ecMutex == null) - return true; - - try - { - return _ecMutex.WaitOne(millisecondsTimeout, false); - } - catch (AbandonedMutexException) - { - return true; - } - catch (InvalidOperationException) - { - return false; - } - } - - public static void ReleaseEcMutex() - { - _ecMutex?.ReleaseMutex(); - } - - public static bool ReadMsr(uint index, out uint eax, out uint edx) - { - if (_driver == null) - { - eax = 0; - edx = 0; - return false; - } - - ulong buffer = 0; - bool result = _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_MSR, index, ref buffer); - edx = (uint)((buffer >> 32) & 0xFFFFFFFF); - eax = (uint)(buffer & 0xFFFFFFFF); - return result; - } - - public static bool ReadMsr(uint index, out uint eax, out uint edx, GroupAffinity affinity) - { - GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); - bool result = ReadMsr(index, out eax, out edx); - ThreadAffinity.Set(previousAffinity); - return result; - } - - public static bool WriteMsr(uint index, uint eax, uint edx) - { - if (_driver == null) - return false; - - WriteMsrInput input = new() { Register = index, Value = ((ulong)edx << 32) | eax }; - return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_WRITE_MSR, input); - } - - public static byte ReadIoPort(uint port) - { - if (_driver == null) - return 0; - - uint value = 0; - _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value); - return (byte)(value & 0xFF); - } - - public static void WriteIoPort(uint port, byte value) - { - if (_driver == null) - return; - - WriteIoPortInput input = new() { PortNumber = port, Value = value }; - _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_WRITE_IO_PORT_BYTE, input); - } - - public static uint GetPciAddress(byte bus, byte device, byte function) - { - return (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7)); - } - - public static bool ReadPciConfig(uint pciAddress, uint regAddress, out uint value) - { - if (_driver == null || (regAddress & 3) != 0) - { - value = 0; - return false; - } - - ReadPciConfigInput input = new() { PciAddress = pciAddress, RegAddress = regAddress }; - - value = 0; - return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_PCI_CONFIG, input, ref value); - } - - public static bool WritePciConfig(uint pciAddress, uint regAddress, uint value) - { - if (_driver == null || (regAddress & 3) != 0) - return false; - - WritePciConfigInput input = new() { PciAddress = pciAddress, RegAddress = regAddress, Value = value }; - return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_WRITE_PCI_CONFIG, input); - } - - public static bool ReadMemory(ulong address, ref T buffer) - { - if (_driver == null) - return false; - - ReadMemoryInput input = new() { Address = address, UnitSize = 1, Count = (uint)Marshal.SizeOf(buffer) }; - return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_MEMORY, input, ref buffer); - } - - public static bool ReadMemory(ulong address, ref T[] buffer) - { - if (_driver == null) - return false; - - ReadMemoryInput input = new() { Address = address, UnitSize = (uint)Marshal.SizeOf(typeof(T)), Count = (uint)buffer.Length }; - return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_MEMORY, input, ref buffer); - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - private struct WriteMsrInput - { - public uint Register; - public ulong Value; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - private struct WriteIoPortInput - { - public uint PortNumber; - public byte Value; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - private struct ReadPciConfigInput - { - public uint PciAddress; - public uint RegAddress; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - private struct WritePciConfigInput - { - public uint PciAddress; - public uint RegAddress; - public uint Value; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - private struct ReadMemoryInput - { - public ulong Address; - public uint UnitSize; - public uint Count; - } + } + + public static void Close() + { + if (_driver != null) + { + uint refCount = 0; + _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_GET_REFCOUNT, null, ref refCount); + _driver.Close(); + + if (refCount <= 1) + _driver.Delete(); + + _driver = null; + } + + if (_isaBusMutex != null) + { + _isaBusMutex.Close(); + _isaBusMutex = null; + } + + if (_pciBusMutex != null) + { + _pciBusMutex.Close(); + _pciBusMutex = null; + } + + if (_ecMutex != null) + { + _ecMutex.Close(); + _ecMutex = null; + } + + // try to delete temporary driver file again if failed during open + DeleteDriver(); + } + + public static string GetReport() + { + if (_report.Length > 0) + { + StringBuilder r = new(); + r.AppendLine("Ring0"); + r.AppendLine(); + r.Append(_report); + r.AppendLine(); + return r.ToString(); + } + + return null; + } + + public static bool WaitIsaBusMutex(int millisecondsTimeout) + { + if (_isaBusMutex == null) + return true; + + try + { + return _isaBusMutex.WaitOne(millisecondsTimeout, false); + } + catch (AbandonedMutexException) + { + return true; + } + catch (InvalidOperationException) + { + return false; + } + } + + public static void ReleaseIsaBusMutex() + { + _isaBusMutex?.ReleaseMutex(); + } + + public static bool WaitPciBusMutex(int millisecondsTimeout) + { + if (_pciBusMutex == null) + return true; + + try + { + return _pciBusMutex.WaitOne(millisecondsTimeout, false); + } + catch (AbandonedMutexException) + { + return true; + } + catch (InvalidOperationException) + { + return false; + } + } + + public static void ReleasePciBusMutex() + { + _pciBusMutex?.ReleaseMutex(); + } + + public static bool WaitEcMutex(int millisecondsTimeout) + { + if (_ecMutex == null) + return true; + + try + { + return _ecMutex.WaitOne(millisecondsTimeout, false); + } + catch (AbandonedMutexException) + { + return true; + } + catch (InvalidOperationException) + { + return false; + } + } + + public static void ReleaseEcMutex() + { + _ecMutex?.ReleaseMutex(); + } + + public static bool ReadMsr(uint index, out uint eax, out uint edx) + { + if (_driver == null) + { + eax = 0; + edx = 0; + return false; + } + + ulong buffer = 0; + bool result = _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_MSR, index, ref buffer); + edx = (uint)((buffer >> 32) & 0xFFFFFFFF); + eax = (uint)(buffer & 0xFFFFFFFF); + return result; + } + + public static bool ReadMsr(uint index, out uint eax, out uint edx, GroupAffinity affinity) + { + GroupAffinity previousAffinity = ThreadAffinity.Set(affinity); + bool result = ReadMsr(index, out eax, out edx); + ThreadAffinity.Set(previousAffinity); + return result; + } + + public static bool WriteMsr(uint index, uint eax, uint edx) + { + if (_driver == null) + return false; + + WriteMsrInput input = new() { Register = index, Value = ((ulong)edx << 32) | eax }; + return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_WRITE_MSR, input); + } + + public static byte ReadIoPort(uint port) + { + if (_driver == null) + return 0; + + uint value = 0; + _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_IO_PORT_BYTE, port, ref value); + return (byte)(value & 0xFF); + } + + public static void WriteIoPort(uint port, byte value) + { + if (_driver == null) + return; + + WriteIoPortInput input = new() { PortNumber = port, Value = value }; + _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_WRITE_IO_PORT_BYTE, input); + } + + public static uint GetPciAddress(byte bus, byte device, byte function) + { + return (uint)(((bus & 0xFF) << 8) | ((device & 0x1F) << 3) | (function & 7)); + } + + public static bool ReadPciConfig(uint pciAddress, uint regAddress, out uint value) + { + if (_driver == null || (regAddress & 3) != 0) + { + value = 0; + return false; + } + + ReadPciConfigInput input = new() { PciAddress = pciAddress, RegAddress = regAddress }; + + value = 0; + return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_PCI_CONFIG, input, ref value); + } + + public static bool WritePciConfig(uint pciAddress, uint regAddress, uint value) + { + if (_driver == null || (regAddress & 3) != 0) + return false; + + WritePciConfigInput input = new() { PciAddress = pciAddress, RegAddress = regAddress, Value = value }; + return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_WRITE_PCI_CONFIG, input); + } + + public static bool ReadMemory(ulong address, ref T buffer) + { + if (_driver == null) + return false; + + ReadMemoryInput input = new() { Address = address, UnitSize = 1, Count = (uint)Marshal.SizeOf(buffer) }; + return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_MEMORY, input, ref buffer); + } + + public static bool ReadMemory(ulong address, ref T[] buffer) + { + if (_driver == null) + return false; + + ReadMemoryInput input = new() { Address = address, UnitSize = (uint)Marshal.SizeOf(typeof(T)), Count = (uint)buffer.Length }; + return _driver.DeviceIOControl(Interop.Ring0.IOCTL_OLS_READ_MEMORY, input, ref buffer); + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct WriteMsrInput + { + public uint Register; + public ulong Value; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct WriteIoPortInput + { + public uint PortNumber; + public byte Value; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct ReadPciConfigInput + { + public uint PciAddress; + public uint RegAddress; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct WritePciConfigInput + { + public uint PciAddress; + public uint RegAddress; + public uint Value; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + private struct ReadMemoryInput + { + public ulong Address; + public uint UnitSize; + public uint Count; } } diff --git a/LibreHardwareMonitorLib/Hardware/RyzenSMU.cs b/LibreHardwareMonitorLib/Hardware/RyzenSMU.cs index 8956d66..de7a6ac 100644 --- a/LibreHardwareMonitorLib/Hardware/RyzenSMU.cs +++ b/LibreHardwareMonitorLib/Hardware/RyzenSMU.cs @@ -8,701 +8,700 @@ using System.Threading; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal class RyzenSMU { - internal class RyzenSMU + private const byte SMU_PCI_ADDR_REG = 0xC4; + private const byte SMU_PCI_DATA_REG = 0xC8; + private const uint SMU_REQ_MAX_ARGS = 6; + private const uint SMU_RETRIES_MAX = 8096; + + private readonly CpuCodeName _cpuCodeName; + private readonly Mutex _mutex = new(); + private readonly bool _supportedCPU; + + private readonly Dictionary> _supportedPmTableVersions = new() { - private const byte SMU_PCI_ADDR_REG = 0xC4; - private const byte SMU_PCI_DATA_REG = 0xC8; - private const uint SMU_REQ_MAX_ARGS = 6; - private const uint SMU_RETRIES_MAX = 8096; - - private readonly CpuCodeName _cpuCodeName; - private readonly Mutex _mutex = new(); - private readonly bool _supportedCPU; - - private readonly Dictionary> _supportedPmTableVersions = new() { + // Zen Raven Ridge APU. + 0x001E0004, new Dictionary { - // Zen Raven Ridge APU. - 0x001E0004, new Dictionary - { - { 7, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, - { 11, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, - //{ 61, new SmuSensorType { Name = "Core", Type = SensorType.Voltage } }, - //{ 62, new SmuSensorType { Name = "Core", Type = SensorType.Current, Scale = 1} }, - //{ 63, new SmuSensorType { Name = "Core", Type = SensorType.Power, Scale = 1 } }, - //{ 65, new SmuSensorType { Name = "SoC", Type = SensorType.Voltage } }, - { 66, new SmuSensorType { Name = "SoC", Type = SensorType.Current, Scale = 1 } }, - { 67, new SmuSensorType { Name = "SoC", Type = SensorType.Power, Scale = 1 } }, - //{ 96, new SmuSensorType { Name = "Core #1", Type = SensorType.Power } }, - //{ 97, new SmuSensorType { Name = "Core #2", Type = SensorType.Power } }, - //{ 98, new SmuSensorType { Name = "Core #3", Type = SensorType.Power } }, - //{ 99, new SmuSensorType { Name = "Core #4", Type = SensorType.Power } }, - { 108, new SmuSensorType { Name = "Core #1", Type = SensorType.Temperature, Scale = 1 } }, - { 109, new SmuSensorType { Name = "Core #2", Type = SensorType.Temperature, Scale = 1 } }, - { 110, new SmuSensorType { Name = "Core #3", Type = SensorType.Temperature, Scale = 1 } }, - { 111, new SmuSensorType { Name = "Core #4", Type = SensorType.Temperature, Scale = 1 } }, - { 150, new SmuSensorType { Name = "GFX", Type = SensorType.Voltage, Scale = 1 } }, - { 151, new SmuSensorType { Name = "GFX", Type = SensorType.Temperature, Scale = 1 } }, - { 154, new SmuSensorType { Name = "GFX", Type = SensorType.Clock, Scale = 1 } }, - { 156, new SmuSensorType { Name = "GFX", Type = SensorType.Load, Scale = 1 } }, - { 166, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, - { 177, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, - { 178, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, - { 342, new SmuSensorType { Name = "Displays", Type = SensorType.Factor, Scale = 1 } } - } - }, - { - // Zen 2. - 0x00240903, new Dictionary - { - { 15, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, - { 21, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, - { 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, - { 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, - { 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, - { 115, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } } - //{ 66, new SmuSensorType { Name = "Bus Speed", Type = SensorType.Clock, Scale = 1 } }, - //{ 188, new SmuSensorType { Name = "Core #1", Type = SensorType.Clock, Scale = 1000 } }, - //{ 189, new SmuSensorType { Name = "Core #2", Type = SensorType.Clock, Scale = 1000 } }, - //{ 190, new SmuSensorType { Name = "Core #3", Type = SensorType.Clock, Scale = 1000 } }, - //{ 191, new SmuSensorType { Name = "Core #4", Type = SensorType.Clock, Scale = 1000 } }, - //{ 192, new SmuSensorType { Name = "Core #5", Type = SensorType.Clock, Scale = 1000 } }, - //{ 193, new SmuSensorType { Name = "Core #6", Type = SensorType.Clock, Scale = 1000 } }, - } - }, - { - // Zen 3. - 0x00380805, new Dictionary - { - { 3, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, - // TODO: requires some post-processing - // see: https://gitlab.com/leogx9r/ryzen_smu/-/blob/master/userspace/monitor_cpu.c#L577 - // { 9, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, - { 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, - { 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, - { 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, - { 127, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } }, - { 268, new SmuSensorType { Name = "Core #1 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 269, new SmuSensorType { Name = "Core #2 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 270, new SmuSensorType { Name = "Core #3 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 271, new SmuSensorType { Name = "Core #4 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 272, new SmuSensorType { Name = "Core #5 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 273, new SmuSensorType { Name = "Core #6 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 274, new SmuSensorType { Name = "Core #7 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 275, new SmuSensorType { Name = "Core #8 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 276, new SmuSensorType { Name = "Core #9 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 277, new SmuSensorType { Name = "Core #10 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 278, new SmuSensorType { Name = "Core #11 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 279, new SmuSensorType { Name = "Core #12 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 280, new SmuSensorType { Name = "Core #13 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 281, new SmuSensorType { Name = "Core #14 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 282, new SmuSensorType { Name = "Core #15 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, - { 283, new SmuSensorType { Name = "Core #16 (Effective)", Type = SensorType.Clock, Scale = 1000 } } - } + { 7, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, + { 11, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, + //{ 61, new SmuSensorType { Name = "Core", Type = SensorType.Voltage } }, + //{ 62, new SmuSensorType { Name = "Core", Type = SensorType.Current, Scale = 1} }, + //{ 63, new SmuSensorType { Name = "Core", Type = SensorType.Power, Scale = 1 } }, + //{ 65, new SmuSensorType { Name = "SoC", Type = SensorType.Voltage } }, + { 66, new SmuSensorType { Name = "SoC", Type = SensorType.Current, Scale = 1 } }, + { 67, new SmuSensorType { Name = "SoC", Type = SensorType.Power, Scale = 1 } }, + //{ 96, new SmuSensorType { Name = "Core #1", Type = SensorType.Power } }, + //{ 97, new SmuSensorType { Name = "Core #2", Type = SensorType.Power } }, + //{ 98, new SmuSensorType { Name = "Core #3", Type = SensorType.Power } }, + //{ 99, new SmuSensorType { Name = "Core #4", Type = SensorType.Power } }, + { 108, new SmuSensorType { Name = "Core #1", Type = SensorType.Temperature, Scale = 1 } }, + { 109, new SmuSensorType { Name = "Core #2", Type = SensorType.Temperature, Scale = 1 } }, + { 110, new SmuSensorType { Name = "Core #3", Type = SensorType.Temperature, Scale = 1 } }, + { 111, new SmuSensorType { Name = "Core #4", Type = SensorType.Temperature, Scale = 1 } }, + { 150, new SmuSensorType { Name = "GFX", Type = SensorType.Voltage, Scale = 1 } }, + { 151, new SmuSensorType { Name = "GFX", Type = SensorType.Temperature, Scale = 1 } }, + { 154, new SmuSensorType { Name = "GFX", Type = SensorType.Clock, Scale = 1 } }, + { 156, new SmuSensorType { Name = "GFX", Type = SensorType.Load, Scale = 1 } }, + { 166, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, + { 177, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, + { 178, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, + { 342, new SmuSensorType { Name = "Displays", Type = SensorType.Factor, Scale = 1 } } } - }; - - private uint _argsAddr; - private uint _cmdAddr; - private uint _dramBaseAddr; - private uint _pmTableSize; - private uint _pmTableSizeAlt; - private uint _pmTableVersion; - private uint _rspAddr; - - public RyzenSMU(uint family, uint model, uint packageType) + }, { - _cpuCodeName = GetCpuCodeName(family, model, packageType); - - _supportedCPU = Environment.Is64BitOperatingSystem == Environment.Is64BitProcess && SetAddresses(_cpuCodeName); - - if (_supportedCPU) + // Zen 2. + 0x00240903, new Dictionary { - InpOut.Open(); - - SetupPmTableAddrAndSize(); + { 15, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, + { 21, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, + { 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, + { 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, + { 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, + { 115, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } } + //{ 66, new SmuSensorType { Name = "Bus Speed", Type = SensorType.Clock, Scale = 1 } }, + //{ 188, new SmuSensorType { Name = "Core #1", Type = SensorType.Clock, Scale = 1000 } }, + //{ 189, new SmuSensorType { Name = "Core #2", Type = SensorType.Clock, Scale = 1000 } }, + //{ 190, new SmuSensorType { Name = "Core #3", Type = SensorType.Clock, Scale = 1000 } }, + //{ 191, new SmuSensorType { Name = "Core #4", Type = SensorType.Clock, Scale = 1000 } }, + //{ 192, new SmuSensorType { Name = "Core #5", Type = SensorType.Clock, Scale = 1000 } }, + //{ 193, new SmuSensorType { Name = "Core #6", Type = SensorType.Clock, Scale = 1000 } }, + } + }, + { + // Zen 3. + 0x00380805, new Dictionary + { + { 3, new SmuSensorType { Name = "TDC", Type = SensorType.Current, Scale = 1 } }, + // TODO: requires some post-processing + // see: https://gitlab.com/leogx9r/ryzen_smu/-/blob/master/userspace/monitor_cpu.c#L577 + // { 9, new SmuSensorType { Name = "EDC", Type = SensorType.Current, Scale = 1 } }, + { 48, new SmuSensorType { Name = "Fabric", Type = SensorType.Clock, Scale = 1 } }, + { 50, new SmuSensorType { Name = "Uncore", Type = SensorType.Clock, Scale = 1 } }, + { 51, new SmuSensorType { Name = "Memory", Type = SensorType.Clock, Scale = 1 } }, + { 127, new SmuSensorType { Name = "SoC", Type = SensorType.Temperature, Scale = 1 } }, + { 268, new SmuSensorType { Name = "Core #1 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 269, new SmuSensorType { Name = "Core #2 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 270, new SmuSensorType { Name = "Core #3 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 271, new SmuSensorType { Name = "Core #4 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 272, new SmuSensorType { Name = "Core #5 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 273, new SmuSensorType { Name = "Core #6 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 274, new SmuSensorType { Name = "Core #7 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 275, new SmuSensorType { Name = "Core #8 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 276, new SmuSensorType { Name = "Core #9 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 277, new SmuSensorType { Name = "Core #10 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 278, new SmuSensorType { Name = "Core #11 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 279, new SmuSensorType { Name = "Core #12 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 280, new SmuSensorType { Name = "Core #13 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 281, new SmuSensorType { Name = "Core #14 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 282, new SmuSensorType { Name = "Core #15 (Effective)", Type = SensorType.Clock, Scale = 1000 } }, + { 283, new SmuSensorType { Name = "Core #16 (Effective)", Type = SensorType.Clock, Scale = 1000 } } } } + }; - private static CpuCodeName GetCpuCodeName(uint family, uint model, uint packageType) + private uint _argsAddr; + private uint _cmdAddr; + private uint _dramBaseAddr; + private uint _pmTableSize; + private uint _pmTableSizeAlt; + private uint _pmTableVersion; + private uint _rspAddr; + + public RyzenSMU(uint family, uint model, uint packageType) + { + _cpuCodeName = GetCpuCodeName(family, model, packageType); + + _supportedCPU = Environment.Is64BitOperatingSystem == Environment.Is64BitProcess && SetAddresses(_cpuCodeName); + + if (_supportedCPU) { - if (family == 0x17) - { - return model switch - { - 0x01 => packageType == 7 ? CpuCodeName.Threadripper : CpuCodeName.SummitRidge, - 0x08 => packageType == 7 ? CpuCodeName.Colfax : CpuCodeName.PinnacleRidge, - 0x11 => CpuCodeName.RavenRidge, - 0x18 => packageType == 2 ? CpuCodeName.RavenRidge2 : CpuCodeName.Picasso, - 0x20 => CpuCodeName.Dali, - 0x31 => CpuCodeName.CastlePeak, - 0x60 => CpuCodeName.Renoir, - 0x71 => CpuCodeName.Matisse, - 0x90 => CpuCodeName.Vangogh, - _ => CpuCodeName.Undefined - }; - } + InpOut.Open(); - if (family == 0x19) - { - return model switch - { - 0x00 => CpuCodeName.Milan, - 0x20 or 0x21 => CpuCodeName.Vermeer, - 0x40 => CpuCodeName.Rembrandt, - 0x50 => CpuCodeName.Cezanne, - _ => CpuCodeName.Undefined - }; - } - - return CpuCodeName.Undefined; - } - - public string GetReport() - { - StringBuilder r = new(); - - r.AppendLine("Ryzen SMU"); - r.AppendLine(); - r.AppendLine($" PM table version: 0x{_pmTableVersion:X8}"); - r.AppendLine($" PM table supported: {_supportedCPU}"); - r.AppendLine($" PM table layout defined: {IsPmTableLayoutDefined()}"); - - if (_supportedCPU) - { - r.AppendLine($" PM table size: 0x{_pmTableSize:X3}"); - r.AppendLine($" PM table start address: 0x{_dramBaseAddr:X8}"); - r.AppendLine(); - r.AppendLine(" PM table dump:"); - r.AppendLine(" Idx Offset Value"); - r.AppendLine(" ------------------------"); - - float[] pm_values = GetPmTable(); - for (int i = 0; i < pm_values.Length; i++) - { - r.AppendLine($" {i,4} 0x{i * 4:X3} {pm_values[i]}"); - } - } - - return r.ToString(); - } - - private bool SetAddresses(CpuCodeName codeName) - { - switch (codeName) - { - case CpuCodeName.CastlePeak: - case CpuCodeName.Matisse: - case CpuCodeName.Vermeer: - _cmdAddr = 0x3B10524; - _rspAddr = 0x3B10570; - _argsAddr = 0x3B10A40; - return true; - - case CpuCodeName.Colfax: - case CpuCodeName.SummitRidge: - case CpuCodeName.Threadripper: - case CpuCodeName.PinnacleRidge: - _cmdAddr = 0x3B1051C; - _rspAddr = 0x3B10568; - _argsAddr = 0x3B10590; - return true; - - case CpuCodeName.Renoir: - case CpuCodeName.Picasso: - case CpuCodeName.RavenRidge: - case CpuCodeName.RavenRidge2: - case CpuCodeName.Dali: - _cmdAddr = 0x3B10A20; - _rspAddr = 0x3B10A80; - _argsAddr = 0x3B10A88; - return true; - - default: - return false; - } - } - - public uint GetSmuVersion() - { - uint[] args = { 1 }; - - if (SendCommand(0x02, ref args)) - return args[0]; - - return 0; - } - - public Dictionary GetPmTableStructure() - { - if (!IsPmTableLayoutDefined()) - return new Dictionary(); - - return _supportedPmTableVersions[_pmTableVersion]; - } - - public bool IsPmTableLayoutDefined() - { - return _supportedPmTableVersions.ContainsKey(_pmTableVersion); - } - - public float[] GetPmTable() - { - if (!_supportedCPU || !TransferTableToDram()) - return new float[] { 0 }; - - float[] table = ReadDramToArray(); - - // Fix for Zen+ empty values on first call. - if (table.Length == 0 || table[0] == 0) - { - Thread.Sleep(10); - TransferTableToDram(); - table = ReadDramToArray(); - } - - return table; - } - - private float[] ReadDramToArray() - { - float[] table = new float[_pmTableSize / 4]; - - byte[] bytes = InpOut.ReadMemory(new IntPtr(_dramBaseAddr), _pmTableSize); - if (bytes != null) - Buffer.BlockCopy(bytes, 0, table, 0, bytes.Length); - - return table; - } - - private bool SetupPmTableAddrAndSize() - { - if (_pmTableSize == 0) - SetupPmTableSize(); - - if (_dramBaseAddr == 0) - SetupDramBaseAddr(); - - return _dramBaseAddr != 0 && _pmTableSize != 0; - } - - private void SetupPmTableSize() - { - if (!GetPmTableVersion(ref _pmTableVersion)) - return; - - switch (_cpuCodeName) - { - case CpuCodeName.Matisse: - switch (_pmTableVersion) - { - case 0x240902: - _pmTableSize = 0x514; - break; - case 0x240903: - _pmTableSize = 0x518; - break; - case 0x240802: - _pmTableSize = 0x7E0; - break; - case 0x240803: - _pmTableSize = 0x7E4; - break; - default: - return; - } - break; - - case CpuCodeName.Vermeer: - switch (_pmTableVersion) - { - case 0x2D0903: - _pmTableSize = 0x594; - break; - case 0x380904: - _pmTableSize = 0x5A4; - break; - case 0x380905: - _pmTableSize = 0x5D0; - break; - case 0x2D0803: - _pmTableSize = 0x894; - break; - case 0x380804: - _pmTableSize = 0x8A4; - break; - case 0x380805: - _pmTableSize = 0x8F0; - break; - default: - return; - } - break; - - case CpuCodeName.Renoir: - switch (_pmTableVersion) - { - case 0x370000: - _pmTableSize = 0x794; - break; - case 0x370001: - _pmTableSize = 0x884; - break; - case 0x370002: - case 0x370003: - _pmTableSize = 0x88C; - break; - case 0x370004: - _pmTableSize = 0x8AC; - break; - case 0x370005: - _pmTableSize = 0x8C8; - break; - default: - return; - } - break; - - case CpuCodeName.Cezanne: - switch (_pmTableVersion) - { - case 0x400005: - _pmTableSize = 0x944; - break; - - default: - return; - } - break; - - case CpuCodeName.Picasso: - case CpuCodeName.RavenRidge: - case CpuCodeName.RavenRidge2: - _pmTableSizeAlt = 0xA4; - _pmTableSize = 0x608 + _pmTableSizeAlt; - break; - - default: - return; - } - } - - private bool GetPmTableVersion(ref uint version) - { - uint[] args = { 0 }; - uint fn; - - switch (_cpuCodeName) - { - case CpuCodeName.RavenRidge: - case CpuCodeName.Picasso: - fn = 0x0c; - break; - case CpuCodeName.Matisse: - case CpuCodeName.Vermeer: - fn = 0x08; - break; - case CpuCodeName.Renoir: - fn = 0x06; - break; - default: - return false; - } - - bool ret = SendCommand(fn, ref args); - version = args[0]; - - return ret; - } - - private void SetupAddrClass1(uint[] fn) - { - uint[] args = { 1, 1 }; - - bool command = SendCommand(fn[0], ref args); - if (!command) - return; - - _dramBaseAddr = args[0] | (args[1] << 32); - } - - private void SetupAddrClass2(uint[] fn) - { - uint[] args = { 0, 0, 0, 0, 0, 0 }; - - bool command = SendCommand(fn[0], ref args); - if (!command) - return; - - args = new uint[] { 0 }; - command = SendCommand(fn[1], ref args); - if (!command) - return; - - _dramBaseAddr = args[0]; - } - - private void SetupAddrClass3(uint[] fn) - { - uint[] parts = { 0, 0 }; - - // == Part 1 == - uint[] args = { 3 }; - bool command = SendCommand(fn[0], ref args); - if (!command) - return; - - args = new uint[] { 3 }; - command = SendCommand(fn[2], ref args); - if (!command) - return; - - // 1st Base. - parts[0] = args[0]; - // == Part 1 End == - - // == Part 2 == - args = new uint[] { 3 }; - command = SendCommand(fn[1], ref args); - if (!command) - return; - - args = new uint[] { 5 }; - command = SendCommand(fn[0], ref args); - if (!command) - return; - - args = new uint[] { 5 }; - command = SendCommand(fn[2], ref args); - if (!command) - return; - - // 2nd base. - parts[1] = args[0]; - // == Part 2 End == - - _dramBaseAddr = parts[0] & 0xFFFFFFFF; - } - - private void SetupDramBaseAddr() - { - uint[] fn = { 0, 0, 0 }; - - switch (_cpuCodeName) - { - case CpuCodeName.Vermeer: - case CpuCodeName.Matisse: - case CpuCodeName.CastlePeak: - fn[0] = 0x06; - SetupAddrClass1(fn); - return; - - case CpuCodeName.Renoir: - fn[0] = 0x66; - SetupAddrClass1(fn); - return; - - case CpuCodeName.Colfax: - case CpuCodeName.PinnacleRidge: - fn[0] = 0x0b; - fn[1] = 0x0c; - SetupAddrClass2(fn); - return; - - case CpuCodeName.Dali: - case CpuCodeName.Picasso: - case CpuCodeName.RavenRidge: - case CpuCodeName.RavenRidge2: - fn[0] = 0x0a; - fn[1] = 0x3d; - fn[2] = 0x0b; - SetupAddrClass3(fn); - return; - - default: - return; - } - } - - public bool TransferTableToDram() - { - uint[] args = { 0 }; - uint fn; - - switch (_cpuCodeName) - { - case CpuCodeName.Matisse: - case CpuCodeName.Vermeer: - fn = 0x05; - break; - - case CpuCodeName.Renoir: - args[0] = 3; - fn = 0x65; - break; - - case CpuCodeName.Picasso: - case CpuCodeName.RavenRidge: - case CpuCodeName.RavenRidge2: - args[0] = 3; - fn = 0x3d; - break; - - default: - return false; - } - - return SendCommand(fn, ref args); - } - - private bool SendCommand(uint msg, ref uint[] args) - { - uint[] cmdArgs = new uint[SMU_REQ_MAX_ARGS]; - int argsLength = Math.Min(args.Length, cmdArgs.Length); - - for (int i = 0; i < argsLength; ++i) - cmdArgs[i] = args[i]; - - uint tmp = 0; - if (_mutex.WaitOne(5000)) - { - // Step 1: Wait until the RSP register is non-zero. - - tmp = 0; - uint retries = SMU_RETRIES_MAX; - do - { - if (!ReadReg(_rspAddr, ref tmp)) - { - _mutex.ReleaseMutex(); - return false; - } - } - while (tmp == 0 && 0 != retries--); - - // Step 1.b: A command is still being processed meaning a new command cannot be issued. - - if (retries == 0 && tmp == 0) - { - _mutex.ReleaseMutex(); - return false; - } - - // Step 2: Write zero (0) to the RSP register - WriteReg(_rspAddr, 0); - - // Step 3: Write the argument(s) into the argument register(s) - for (int i = 0; i < cmdArgs.Length; ++i) - WriteReg(_argsAddr + (uint)(i * 4), cmdArgs[i]); - - // Step 4: Write the message Id into the Message ID register - WriteReg(_cmdAddr, msg); - - // Step 5: Wait until the Response register is non-zero. - tmp = 0; - retries = SMU_RETRIES_MAX; - do - { - if (!ReadReg(_rspAddr, ref tmp)) - { - _mutex.ReleaseMutex(); - return false; - } - } - while (tmp == 0 && retries-- != 0); - - if (retries == 0 && tmp != (uint)Status.OK) - { - _mutex.ReleaseMutex(); - return false; - } - - // Step 6: If the Response register contains OK, then SMU has finished processing the message. - - args = new uint[SMU_REQ_MAX_ARGS]; - for (byte i = 0; i < SMU_REQ_MAX_ARGS; i++) - { - if (!ReadReg(_argsAddr + (uint)(i * 4), ref args[i])) - { - _mutex.ReleaseMutex(); - return false; - } - } - - ReadReg(_rspAddr, ref tmp); - _mutex.ReleaseMutex(); - } - - return tmp == (uint)Status.OK; - } - - private static void WriteReg(uint addr, uint data) - { - if (Ring0.WaitPciBusMutex(10)) - { - if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr)) - { - Ring0.WritePciConfig(0x00, SMU_PCI_DATA_REG, data); - } - - Ring0.ReleasePciBusMutex(); - } - } - - private static bool ReadReg(uint addr, ref uint data) - { - bool read = false; - - if (Ring0.WaitPciBusMutex(10)) - { - if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr)) - { - read = Ring0.ReadPciConfig(0x00, SMU_PCI_DATA_REG, out data); - } - - Ring0.ReleasePciBusMutex(); - } - - return read; - } - - public struct SmuSensorType - { - public string Name; - public SensorType Type; - public float Scale; - } - - private enum Status : uint - { - OK = 0x01, - Failed = 0xFF, - UnknownCmd = 0xFE, - CmdRejectedPrereq = 0xFD, - CmdRejectedBusy = 0xFC - } - - private enum CpuCodeName - { - Undefined, - Colfax, - Renoir, - Picasso, - Matisse, - Threadripper, - CastlePeak, - RavenRidge, - RavenRidge2, - SummitRidge, - PinnacleRidge, - Rembrandt, - Vermeer, - Vangogh, - Cezanne, - Milan, - Dali + SetupPmTableAddrAndSize(); } } + + private static CpuCodeName GetCpuCodeName(uint family, uint model, uint packageType) + { + if (family == 0x17) + { + return model switch + { + 0x01 => packageType == 7 ? CpuCodeName.Threadripper : CpuCodeName.SummitRidge, + 0x08 => packageType == 7 ? CpuCodeName.Colfax : CpuCodeName.PinnacleRidge, + 0x11 => CpuCodeName.RavenRidge, + 0x18 => packageType == 2 ? CpuCodeName.RavenRidge2 : CpuCodeName.Picasso, + 0x20 => CpuCodeName.Dali, + 0x31 => CpuCodeName.CastlePeak, + 0x60 => CpuCodeName.Renoir, + 0x71 => CpuCodeName.Matisse, + 0x90 => CpuCodeName.Vangogh, + _ => CpuCodeName.Undefined + }; + } + + if (family == 0x19) + { + return model switch + { + 0x00 => CpuCodeName.Milan, + 0x20 or 0x21 => CpuCodeName.Vermeer, + 0x40 => CpuCodeName.Rembrandt, + 0x50 => CpuCodeName.Cezanne, + _ => CpuCodeName.Undefined + }; + } + + return CpuCodeName.Undefined; + } + + public string GetReport() + { + StringBuilder r = new(); + + r.AppendLine("Ryzen SMU"); + r.AppendLine(); + r.AppendLine($" PM table version: 0x{_pmTableVersion:X8}"); + r.AppendLine($" PM table supported: {_supportedCPU}"); + r.AppendLine($" PM table layout defined: {IsPmTableLayoutDefined()}"); + + if (_supportedCPU) + { + r.AppendLine($" PM table size: 0x{_pmTableSize:X3}"); + r.AppendLine($" PM table start address: 0x{_dramBaseAddr:X8}"); + r.AppendLine(); + r.AppendLine(" PM table dump:"); + r.AppendLine(" Idx Offset Value"); + r.AppendLine(" ------------------------"); + + float[] pm_values = GetPmTable(); + for (int i = 0; i < pm_values.Length; i++) + { + r.AppendLine($" {i,4} 0x{i * 4:X3} {pm_values[i]}"); + } + } + + return r.ToString(); + } + + private bool SetAddresses(CpuCodeName codeName) + { + switch (codeName) + { + case CpuCodeName.CastlePeak: + case CpuCodeName.Matisse: + case CpuCodeName.Vermeer: + _cmdAddr = 0x3B10524; + _rspAddr = 0x3B10570; + _argsAddr = 0x3B10A40; + return true; + + case CpuCodeName.Colfax: + case CpuCodeName.SummitRidge: + case CpuCodeName.Threadripper: + case CpuCodeName.PinnacleRidge: + _cmdAddr = 0x3B1051C; + _rspAddr = 0x3B10568; + _argsAddr = 0x3B10590; + return true; + + case CpuCodeName.Renoir: + case CpuCodeName.Picasso: + case CpuCodeName.RavenRidge: + case CpuCodeName.RavenRidge2: + case CpuCodeName.Dali: + _cmdAddr = 0x3B10A20; + _rspAddr = 0x3B10A80; + _argsAddr = 0x3B10A88; + return true; + + default: + return false; + } + } + + public uint GetSmuVersion() + { + uint[] args = { 1 }; + + if (SendCommand(0x02, ref args)) + return args[0]; + + return 0; + } + + public Dictionary GetPmTableStructure() + { + if (!IsPmTableLayoutDefined()) + return new Dictionary(); + + return _supportedPmTableVersions[_pmTableVersion]; + } + + public bool IsPmTableLayoutDefined() + { + return _supportedPmTableVersions.ContainsKey(_pmTableVersion); + } + + public float[] GetPmTable() + { + if (!_supportedCPU || !TransferTableToDram()) + return new float[] { 0 }; + + float[] table = ReadDramToArray(); + + // Fix for Zen+ empty values on first call. + if (table.Length == 0 || table[0] == 0) + { + Thread.Sleep(10); + TransferTableToDram(); + table = ReadDramToArray(); + } + + return table; + } + + private float[] ReadDramToArray() + { + float[] table = new float[_pmTableSize / 4]; + + byte[] bytes = InpOut.ReadMemory(new IntPtr(_dramBaseAddr), _pmTableSize); + if (bytes != null) + Buffer.BlockCopy(bytes, 0, table, 0, bytes.Length); + + return table; + } + + private bool SetupPmTableAddrAndSize() + { + if (_pmTableSize == 0) + SetupPmTableSize(); + + if (_dramBaseAddr == 0) + SetupDramBaseAddr(); + + return _dramBaseAddr != 0 && _pmTableSize != 0; + } + + private void SetupPmTableSize() + { + if (!GetPmTableVersion(ref _pmTableVersion)) + return; + + switch (_cpuCodeName) + { + case CpuCodeName.Matisse: + switch (_pmTableVersion) + { + case 0x240902: + _pmTableSize = 0x514; + break; + case 0x240903: + _pmTableSize = 0x518; + break; + case 0x240802: + _pmTableSize = 0x7E0; + break; + case 0x240803: + _pmTableSize = 0x7E4; + break; + default: + return; + } + break; + + case CpuCodeName.Vermeer: + switch (_pmTableVersion) + { + case 0x2D0903: + _pmTableSize = 0x594; + break; + case 0x380904: + _pmTableSize = 0x5A4; + break; + case 0x380905: + _pmTableSize = 0x5D0; + break; + case 0x2D0803: + _pmTableSize = 0x894; + break; + case 0x380804: + _pmTableSize = 0x8A4; + break; + case 0x380805: + _pmTableSize = 0x8F0; + break; + default: + return; + } + break; + + case CpuCodeName.Renoir: + switch (_pmTableVersion) + { + case 0x370000: + _pmTableSize = 0x794; + break; + case 0x370001: + _pmTableSize = 0x884; + break; + case 0x370002: + case 0x370003: + _pmTableSize = 0x88C; + break; + case 0x370004: + _pmTableSize = 0x8AC; + break; + case 0x370005: + _pmTableSize = 0x8C8; + break; + default: + return; + } + break; + + case CpuCodeName.Cezanne: + switch (_pmTableVersion) + { + case 0x400005: + _pmTableSize = 0x944; + break; + + default: + return; + } + break; + + case CpuCodeName.Picasso: + case CpuCodeName.RavenRidge: + case CpuCodeName.RavenRidge2: + _pmTableSizeAlt = 0xA4; + _pmTableSize = 0x608 + _pmTableSizeAlt; + break; + + default: + return; + } + } + + private bool GetPmTableVersion(ref uint version) + { + uint[] args = { 0 }; + uint fn; + + switch (_cpuCodeName) + { + case CpuCodeName.RavenRidge: + case CpuCodeName.Picasso: + fn = 0x0c; + break; + case CpuCodeName.Matisse: + case CpuCodeName.Vermeer: + fn = 0x08; + break; + case CpuCodeName.Renoir: + fn = 0x06; + break; + default: + return false; + } + + bool ret = SendCommand(fn, ref args); + version = args[0]; + + return ret; + } + + private void SetupAddrClass1(uint[] fn) + { + uint[] args = { 1, 1 }; + + bool command = SendCommand(fn[0], ref args); + if (!command) + return; + + _dramBaseAddr = args[0] | (args[1] << 32); + } + + private void SetupAddrClass2(uint[] fn) + { + uint[] args = { 0, 0, 0, 0, 0, 0 }; + + bool command = SendCommand(fn[0], ref args); + if (!command) + return; + + args = new uint[] { 0 }; + command = SendCommand(fn[1], ref args); + if (!command) + return; + + _dramBaseAddr = args[0]; + } + + private void SetupAddrClass3(uint[] fn) + { + uint[] parts = { 0, 0 }; + + // == Part 1 == + uint[] args = { 3 }; + bool command = SendCommand(fn[0], ref args); + if (!command) + return; + + args = new uint[] { 3 }; + command = SendCommand(fn[2], ref args); + if (!command) + return; + + // 1st Base. + parts[0] = args[0]; + // == Part 1 End == + + // == Part 2 == + args = new uint[] { 3 }; + command = SendCommand(fn[1], ref args); + if (!command) + return; + + args = new uint[] { 5 }; + command = SendCommand(fn[0], ref args); + if (!command) + return; + + args = new uint[] { 5 }; + command = SendCommand(fn[2], ref args); + if (!command) + return; + + // 2nd base. + parts[1] = args[0]; + // == Part 2 End == + + _dramBaseAddr = parts[0] & 0xFFFFFFFF; + } + + private void SetupDramBaseAddr() + { + uint[] fn = { 0, 0, 0 }; + + switch (_cpuCodeName) + { + case CpuCodeName.Vermeer: + case CpuCodeName.Matisse: + case CpuCodeName.CastlePeak: + fn[0] = 0x06; + SetupAddrClass1(fn); + return; + + case CpuCodeName.Renoir: + fn[0] = 0x66; + SetupAddrClass1(fn); + return; + + case CpuCodeName.Colfax: + case CpuCodeName.PinnacleRidge: + fn[0] = 0x0b; + fn[1] = 0x0c; + SetupAddrClass2(fn); + return; + + case CpuCodeName.Dali: + case CpuCodeName.Picasso: + case CpuCodeName.RavenRidge: + case CpuCodeName.RavenRidge2: + fn[0] = 0x0a; + fn[1] = 0x3d; + fn[2] = 0x0b; + SetupAddrClass3(fn); + return; + + default: + return; + } + } + + public bool TransferTableToDram() + { + uint[] args = { 0 }; + uint fn; + + switch (_cpuCodeName) + { + case CpuCodeName.Matisse: + case CpuCodeName.Vermeer: + fn = 0x05; + break; + + case CpuCodeName.Renoir: + args[0] = 3; + fn = 0x65; + break; + + case CpuCodeName.Picasso: + case CpuCodeName.RavenRidge: + case CpuCodeName.RavenRidge2: + args[0] = 3; + fn = 0x3d; + break; + + default: + return false; + } + + return SendCommand(fn, ref args); + } + + private bool SendCommand(uint msg, ref uint[] args) + { + uint[] cmdArgs = new uint[SMU_REQ_MAX_ARGS]; + int argsLength = Math.Min(args.Length, cmdArgs.Length); + + for (int i = 0; i < argsLength; ++i) + cmdArgs[i] = args[i]; + + uint tmp = 0; + if (_mutex.WaitOne(5000)) + { + // Step 1: Wait until the RSP register is non-zero. + + tmp = 0; + uint retries = SMU_RETRIES_MAX; + do + { + if (!ReadReg(_rspAddr, ref tmp)) + { + _mutex.ReleaseMutex(); + return false; + } + } + while (tmp == 0 && 0 != retries--); + + // Step 1.b: A command is still being processed meaning a new command cannot be issued. + + if (retries == 0 && tmp == 0) + { + _mutex.ReleaseMutex(); + return false; + } + + // Step 2: Write zero (0) to the RSP register + WriteReg(_rspAddr, 0); + + // Step 3: Write the argument(s) into the argument register(s) + for (int i = 0; i < cmdArgs.Length; ++i) + WriteReg(_argsAddr + (uint)(i * 4), cmdArgs[i]); + + // Step 4: Write the message Id into the Message ID register + WriteReg(_cmdAddr, msg); + + // Step 5: Wait until the Response register is non-zero. + tmp = 0; + retries = SMU_RETRIES_MAX; + do + { + if (!ReadReg(_rspAddr, ref tmp)) + { + _mutex.ReleaseMutex(); + return false; + } + } + while (tmp == 0 && retries-- != 0); + + if (retries == 0 && tmp != (uint)Status.OK) + { + _mutex.ReleaseMutex(); + return false; + } + + // Step 6: If the Response register contains OK, then SMU has finished processing the message. + + args = new uint[SMU_REQ_MAX_ARGS]; + for (byte i = 0; i < SMU_REQ_MAX_ARGS; i++) + { + if (!ReadReg(_argsAddr + (uint)(i * 4), ref args[i])) + { + _mutex.ReleaseMutex(); + return false; + } + } + + ReadReg(_rspAddr, ref tmp); + _mutex.ReleaseMutex(); + } + + return tmp == (uint)Status.OK; + } + + private static void WriteReg(uint addr, uint data) + { + if (Ring0.WaitPciBusMutex(10)) + { + if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr)) + { + Ring0.WritePciConfig(0x00, SMU_PCI_DATA_REG, data); + } + + Ring0.ReleasePciBusMutex(); + } + } + + private static bool ReadReg(uint addr, ref uint data) + { + bool read = false; + + if (Ring0.WaitPciBusMutex(10)) + { + if (Ring0.WritePciConfig(0x00, SMU_PCI_ADDR_REG, addr)) + { + read = Ring0.ReadPciConfig(0x00, SMU_PCI_DATA_REG, out data); + } + + Ring0.ReleasePciBusMutex(); + } + + return read; + } + + public struct SmuSensorType + { + public string Name; + public SensorType Type; + public float Scale; + } + + private enum Status : uint + { + OK = 0x01, + Failed = 0xFF, + UnknownCmd = 0xFE, + CmdRejectedPrereq = 0xFD, + CmdRejectedBusy = 0xFC + } + + private enum CpuCodeName + { + Undefined, + Colfax, + Renoir, + Picasso, + Matisse, + Threadripper, + CastlePeak, + RavenRidge, + RavenRidge2, + SummitRidge, + PinnacleRidge, + Rembrandt, + Vermeer, + Vangogh, + Cezanne, + Milan, + Dali + } } diff --git a/LibreHardwareMonitorLib/Hardware/SMBios.cs b/LibreHardwareMonitorLib/Hardware/SMBios.cs index 149dd60..9c4258f 100644 --- a/LibreHardwareMonitorLib/Hardware/SMBios.cs +++ b/LibreHardwareMonitorLib/Hardware/SMBios.cs @@ -14,1501 +14,1500 @@ using LibreHardwareMonitor.Interop; // ReSharper disable IdentifierTypo // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// System enclosure security status based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.3. +/// +public enum SystemEnclosureSecurityStatus { + Other = 1, + Unknown, + None, + ExternalInterfaceLockedOut, + ExternalInterfaceEnabled +} + +/// +/// System enclosure state based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.2. +/// +public enum SystemEnclosureState +{ + Other = 1, + Unknown, + Safe, + Warning, + Critical, + NonRecoverable +} + +/// +/// System enclosure type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.1. +/// +public enum SystemEnclosureType +{ + Other = 1, + Unknown, + Desktop, + LowProfileDesktop, + PizzaBox, + MiniTower, + Tower, + Portable, + Laptop, + Notebook, + HandHeld, + DockingStation, + AllInOne, + SubNotebook, + SpaceSaving, + LunchBox, + MainServerChassis, + ExpansionChassis, + SubChassis, + BusExpansionChassis, + PeripheralChassis, + RaidChassis, + RackMountChassis, + SealedCasePc, + MultiSystemChassis, + CompactPci, + AdvancedTca, + Blade, + BladeEnclosure, + Tablet, + Convertible, + Detachable, + IoTGateway, + EmbeddedPc, + MiniPc, + StickPc +} + +/// +/// Processor family based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.2. +/// +public enum ProcessorFamily +{ + Other = 1, + Intel8086 = 3, + Intel80286 = 4, + Intel386, + Intel486, + Intel8087, + Intel80287, + Intel80387, + Intel80487, + IntelPentium, + IntelPentiumPro, + IntelPentiumII, + IntelPentiumMMX, + IntelCeleron, + IntelPentiumIIXeon, + IntelPentiumIII, + M1, + M2, + IntelCeleronM, + IntelPentium4HT, + AmdDuron = 24, + AmdK5, + AmdK6, + AmdK62, + AmdK63, + AmdAthlon, + Amd2900, + AmdK62Plus, + PowerPc, + PowerPc601, + PowerPc603, + PowerPc603Plus, + PowerPc604, + PowerPc620, + PowerPcx704, + PowerPc750, + IntelCoreDuo, + IntelCoreDuoMobile, + IntelCoreSoloMobile, + IntelAtom, + IntelCoreM, + IntelCoreM3, + IntelCoreM5, + IntelCoreM7, + Alpha, + Alpha21064, + Alpha21066, + Alpha21164, + Alpha21164Pc, + Alpha21164a, + Alpha21264, + Alpha21364, + AmdTurionIIUltraDualCoreMobileM, + AmdTurionDualCoreMobileM, + AmdAthlonIIDualCoreM, + AmdOpteron6100Series, + AmdOpteron4100Series, + AmdOpteron6200Series, + AmdOpteron4200Series, + AmdFxSeries, + Mips, + MipsR4000, + MipsR4200, + MipsR4400, + MipsR4600, + MipsR10000, + AmdCSeries, + AmdESeries, + AmdASeries, + AmdGSeries, + AmdZSeries, + AmdRSeries, + AmdOpteron4300Series, + AmdOpteron6300Series, + AmdOpteron3300Series, + AmdFireProSeries, + Sparc, + SuperSparc, + MicroSparcII, + MicroSparcIIep, + UltraSparc, + UltraSparcII, + UltraSparcIIi, + UltraSparcIII, + UltraSparcIIIi, + Motorola68040 = 96, + Motorola68xxx, + Motorola68000, + Motorola68010, + Motorola68020, + Motorola68030, + AmdAthlonX4QuadCore, + AmdOpteronX1000Series, + AmdOpteronX2000Series, + AmdOpteronASeries, + AmdOpteronX3000Series, + AmdZen, + Hobbit = 112, + CrusoeTm5000 = 120, + CrusoeTm3000, + EfficeonTm8000, + Weitek = 128, + IntelItanium = 130, + AmdAthlon64, + AmdOpteron, + AmdSempron, + AmdTurio64Mobile, + AmdOpteronDualCore, + AmdAthlon64X2DualCore, + AmdTurion64X2Mobile, + AmdOpteronQuadCore, + AmdOpteronThirdGen, + AmdPhenomFXQuadCore, + AmdPhenomX4QuadCore, + AmdPhenomX2DualCore, + AmdAthlonX2DualCore, + PaRisc, + PaRisc8500, + PaRisc8000, + PaRisc7300LC, + PaRisc7200, + PaRisc7100LC, + PaRisc7100, + V30 = 160, + IntelXeon3200QuadCoreSeries, + IntelXeon3000DualCoreSeries, + IntelXeon5300QuadCoreSeries, + IntelXeon5100DualCoreSeries, + IntelXeon5000DualCoreSeries, + IntelXeonLVDualCore, + IntelXeonULVDualCore, + IntelXeon7100Series, + IntelXeon5400Series, + IntelXeonQuadCore, + IntelXeon5200DualCoreSeries, + IntelXeon7200DualCoreSeries, + IntelXeon7300QuadCoreSeries, + IntelXeon7400QuadCoreSeries, + IntelXeon7400MultiCoreSeries, + IntelPentiumIIIXeon, + IntelPentiumIIISpeedStep, + IntelPentium4, + IntelXeon, + As400, + IntelXeonMP, + AmdAthlonXP, + AmdAthlonMP, + IntelItanium2, + IntelPentiumM, + IntelCeleronD, + IntelPentiumD, + IntelPentiumExtreme, + IntelCoreSolo, + IntelCore2Duo = 191, + IntelCore2Solo, + IntelCore2Extreme, + IntelCore2Quad, + IntelCore2ExtremeMobile, + IntelCore2DuoMobile, + IntelCore2SoloMobile, + IntelCoreI7, + IntelCeleronDualCore, + Ibm390, + PowerPcG4, + PowerPcG5, + Esa390G6, + ZArchitecture, + IntelCoreI5, + IntelCoreI3, + IntelCoreI9, + ViaC7M = 210, + ViaC7D, + ViaC7, + ViaEden, + IntelXeonMultiCore, + IntelXeon3xxxDualCoreSeries, + IntelXeon3xxxQuadCoreSeries, + ViaNano, + IntelXeon5xxxDualCoreSeries, + IntelXeon5xxxQuadCoreSeries, + IntelXeon7xxxDualCoreSeries = 221, + IntelXeon7xxxQuadCoreSeries, + IntelXeon7xxxMultiCoreSeries, + IntelXeon3400MultiCoreSeries, + AmdOpteron3000Series = 228, + AmdSempronII, + AmdOpteronQuadCoreEmbedded, + AmdPhenomTripleCore, + AmdTurionUltraDualCoreMobile, + AmdTurionDualCoreMobile, + AmdTurionDualCore, + AmdAthlonDualCore, + AmdSempronSI, + AmdPhenomII, + AmdAthlonII, + AmdOpteronSixCore, + AmdSempronM, + IntelI860 = 250, + IntelI960, + ArmV7 = 256, + ArmV8, + HitachiSh3, + HitachiSh4, + Arm, + StrongArm, + _686, + MediaGX, + MII, + WinChip, + Dsp, + VideoProcessor +} + +/// +/// Processor characteristics based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.9. +/// +[Flags] +public enum ProcessorCharacteristics +{ + None = 0, + _64BitCapable = 1, + MultiCore = 2, + HardwareThread = 4, + ExecuteProtection = 8, + EnhancedVirtualization = 16, + PowerPerformanceControl = 32, + _128BitCapable = 64 +} + +/// +/// Processor type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.1. +/// +public enum ProcessorType +{ + Other = 1, + Unknown, + CentralProcessor, + MathProcessor, + DspProcessor, + VideoProcessor +} + +/// +/// Processor socket based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.5. +/// +public enum ProcessorSocket +{ + Other = 1, + Unknown, + DaughterBoard, + ZifSocket, + PiggyBack, + None, + LifSocket, + Zif423 = 13, + A, + Zif478, + Zif754, + Zif940, + Zif939, + MPga604, + Lga771, + Lga775, + S1, + AM2, + F, + Lga1366, + G34, + AM3, + C32, + Lga1156, + Lga1567, + Pga988A, + Bga1288, + RPga088B, + Bga1023, + Bga1224, + Lga1155, + Lga1356, + Lga2011, + FS1, + FS2, + FM1, + FM2, + Lga20113, + Lga13563, + Lga1150, + Bga1168, + Bga1234, + Bga1364, + AM4, + Lga1151, + Bga1356, + Bga1440, + Bga1515, + Lga36471, + SP3, + SP3R2, + Lga2066, + Bga1510, + Bga1528, + Lga4189 +} + +/// +/// System wake-up type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.2.2. +/// +public enum SystemWakeUp +{ + Reserved, + Other, + Unknown, + ApmTimer, + ModemRing, + LanRemote, + PowerSwitch, + PciPme, + AcPowerRestored +} + +/// +/// Cache associativity based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.8.5. +/// +public enum CacheAssociativity +{ + Other = 1, + Unknown, + DirectMapped, + _2Way, + _4Way, + FullyAssociative, + _8Way, + _16Way, + _12Way, + _24Way, + _32Way, + _48Way, + _64Way, + _20Way +} + +/// +/// Processor cache level. +/// +public enum CacheDesignation +{ + Other, + L1, + L2, + L3 +} + +/// +/// Memory type. +/// +public enum MemoryType +{ + Other = 0x01, + Unknown = 0x02, + DRAM = 0x03, + EDRAM = 0x04, + VRAM = 0x05, + SRAM = 0x06, + RAM = 0x07, + ROM = 0x08, + FLASH = 0x09, + EEPROM = 0x0a, + FEPROM = 0x0b, + EPROM = 0x0c, + CDRAM = 0x0d, + _3DRAM = 0x0e, + SDRAM = 0x0f, + SGRAM = 0x10, + RDRAM = 0x11, + DDR = 0x12, + DDR2 = 0x13, + DDR2_FBDIMM = 0x14, + DDR3 = 0x18, + FBD2 = 0x19, + DDR4 = 0x1a, + LPDDR = 0x1b, + LPDDR2 = 0x1c, + LPDDR3 = 0x1d, + LPDDR4 = 0x1e, + LogicalNonVolatileDevice = 0x1f, + HBM = 0x20, + HBM2 = 0x21, + DDR5 = 0x22, + LPDDR5 = 0x23 +} + +public class InformationBase +{ + private readonly byte[] _data; + private readonly IList _strings; + /// - /// System enclosure security status based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.3. + /// Initializes a new instance of the class. /// - public enum SystemEnclosureSecurityStatus + /// The data. + /// The strings. + protected InformationBase(byte[] data, IList strings) { - Other = 1, - Unknown, - None, - ExternalInterfaceLockedOut, - ExternalInterfaceEnabled + _data = data; + _strings = strings; } /// - /// System enclosure state based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.2. + /// Gets the byte. /// - public enum SystemEnclosureState + /// The offset. + /// . + protected byte GetByte(int offset) { - Other = 1, - Unknown, - Safe, - Warning, - Critical, - NonRecoverable + if (offset < _data.Length && offset >= 0) + return _data[offset]; + + return 0; } /// - /// System enclosure type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.4.1. + /// Gets the word. /// - public enum SystemEnclosureType + /// The offset. + /// . + protected ushort GetWord(int offset) { - Other = 1, - Unknown, - Desktop, - LowProfileDesktop, - PizzaBox, - MiniTower, - Tower, - Portable, - Laptop, - Notebook, - HandHeld, - DockingStation, - AllInOne, - SubNotebook, - SpaceSaving, - LunchBox, - MainServerChassis, - ExpansionChassis, - SubChassis, - BusExpansionChassis, - PeripheralChassis, - RaidChassis, - RackMountChassis, - SealedCasePc, - MultiSystemChassis, - CompactPci, - AdvancedTca, - Blade, - BladeEnclosure, - Tablet, - Convertible, - Detachable, - IoTGateway, - EmbeddedPc, - MiniPc, - StickPc - } - - /// - /// Processor family based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.2. - /// - public enum ProcessorFamily - { - Other = 1, - Intel8086 = 3, - Intel80286 = 4, - Intel386, - Intel486, - Intel8087, - Intel80287, - Intel80387, - Intel80487, - IntelPentium, - IntelPentiumPro, - IntelPentiumII, - IntelPentiumMMX, - IntelCeleron, - IntelPentiumIIXeon, - IntelPentiumIII, - M1, - M2, - IntelCeleronM, - IntelPentium4HT, - AmdDuron = 24, - AmdK5, - AmdK6, - AmdK62, - AmdK63, - AmdAthlon, - Amd2900, - AmdK62Plus, - PowerPc, - PowerPc601, - PowerPc603, - PowerPc603Plus, - PowerPc604, - PowerPc620, - PowerPcx704, - PowerPc750, - IntelCoreDuo, - IntelCoreDuoMobile, - IntelCoreSoloMobile, - IntelAtom, - IntelCoreM, - IntelCoreM3, - IntelCoreM5, - IntelCoreM7, - Alpha, - Alpha21064, - Alpha21066, - Alpha21164, - Alpha21164Pc, - Alpha21164a, - Alpha21264, - Alpha21364, - AmdTurionIIUltraDualCoreMobileM, - AmdTurionDualCoreMobileM, - AmdAthlonIIDualCoreM, - AmdOpteron6100Series, - AmdOpteron4100Series, - AmdOpteron6200Series, - AmdOpteron4200Series, - AmdFxSeries, - Mips, - MipsR4000, - MipsR4200, - MipsR4400, - MipsR4600, - MipsR10000, - AmdCSeries, - AmdESeries, - AmdASeries, - AmdGSeries, - AmdZSeries, - AmdRSeries, - AmdOpteron4300Series, - AmdOpteron6300Series, - AmdOpteron3300Series, - AmdFireProSeries, - Sparc, - SuperSparc, - MicroSparcII, - MicroSparcIIep, - UltraSparc, - UltraSparcII, - UltraSparcIIi, - UltraSparcIII, - UltraSparcIIIi, - Motorola68040 = 96, - Motorola68xxx, - Motorola68000, - Motorola68010, - Motorola68020, - Motorola68030, - AmdAthlonX4QuadCore, - AmdOpteronX1000Series, - AmdOpteronX2000Series, - AmdOpteronASeries, - AmdOpteronX3000Series, - AmdZen, - Hobbit = 112, - CrusoeTm5000 = 120, - CrusoeTm3000, - EfficeonTm8000, - Weitek = 128, - IntelItanium = 130, - AmdAthlon64, - AmdOpteron, - AmdSempron, - AmdTurio64Mobile, - AmdOpteronDualCore, - AmdAthlon64X2DualCore, - AmdTurion64X2Mobile, - AmdOpteronQuadCore, - AmdOpteronThirdGen, - AmdPhenomFXQuadCore, - AmdPhenomX4QuadCore, - AmdPhenomX2DualCore, - AmdAthlonX2DualCore, - PaRisc, - PaRisc8500, - PaRisc8000, - PaRisc7300LC, - PaRisc7200, - PaRisc7100LC, - PaRisc7100, - V30 = 160, - IntelXeon3200QuadCoreSeries, - IntelXeon3000DualCoreSeries, - IntelXeon5300QuadCoreSeries, - IntelXeon5100DualCoreSeries, - IntelXeon5000DualCoreSeries, - IntelXeonLVDualCore, - IntelXeonULVDualCore, - IntelXeon7100Series, - IntelXeon5400Series, - IntelXeonQuadCore, - IntelXeon5200DualCoreSeries, - IntelXeon7200DualCoreSeries, - IntelXeon7300QuadCoreSeries, - IntelXeon7400QuadCoreSeries, - IntelXeon7400MultiCoreSeries, - IntelPentiumIIIXeon, - IntelPentiumIIISpeedStep, - IntelPentium4, - IntelXeon, - As400, - IntelXeonMP, - AmdAthlonXP, - AmdAthlonMP, - IntelItanium2, - IntelPentiumM, - IntelCeleronD, - IntelPentiumD, - IntelPentiumExtreme, - IntelCoreSolo, - IntelCore2Duo = 191, - IntelCore2Solo, - IntelCore2Extreme, - IntelCore2Quad, - IntelCore2ExtremeMobile, - IntelCore2DuoMobile, - IntelCore2SoloMobile, - IntelCoreI7, - IntelCeleronDualCore, - Ibm390, - PowerPcG4, - PowerPcG5, - Esa390G6, - ZArchitecture, - IntelCoreI5, - IntelCoreI3, - IntelCoreI9, - ViaC7M = 210, - ViaC7D, - ViaC7, - ViaEden, - IntelXeonMultiCore, - IntelXeon3xxxDualCoreSeries, - IntelXeon3xxxQuadCoreSeries, - ViaNano, - IntelXeon5xxxDualCoreSeries, - IntelXeon5xxxQuadCoreSeries, - IntelXeon7xxxDualCoreSeries = 221, - IntelXeon7xxxQuadCoreSeries, - IntelXeon7xxxMultiCoreSeries, - IntelXeon3400MultiCoreSeries, - AmdOpteron3000Series = 228, - AmdSempronII, - AmdOpteronQuadCoreEmbedded, - AmdPhenomTripleCore, - AmdTurionUltraDualCoreMobile, - AmdTurionDualCoreMobile, - AmdTurionDualCore, - AmdAthlonDualCore, - AmdSempronSI, - AmdPhenomII, - AmdAthlonII, - AmdOpteronSixCore, - AmdSempronM, - IntelI860 = 250, - IntelI960, - ArmV7 = 256, - ArmV8, - HitachiSh3, - HitachiSh4, - Arm, - StrongArm, - _686, - MediaGX, - MII, - WinChip, - Dsp, - VideoProcessor - } - - /// - /// Processor characteristics based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.9. - /// - [Flags] - public enum ProcessorCharacteristics - { - None = 0, - _64BitCapable = 1, - MultiCore = 2, - HardwareThread = 4, - ExecuteProtection = 8, - EnhancedVirtualization = 16, - PowerPerformanceControl = 32, - _128BitCapable = 64 - } - - /// - /// Processor type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.1. - /// - public enum ProcessorType - { - Other = 1, - Unknown, - CentralProcessor, - MathProcessor, - DspProcessor, - VideoProcessor - } - - /// - /// Processor socket based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.5.5. - /// - public enum ProcessorSocket - { - Other = 1, - Unknown, - DaughterBoard, - ZifSocket, - PiggyBack, - None, - LifSocket, - Zif423 = 13, - A, - Zif478, - Zif754, - Zif940, - Zif939, - MPga604, - Lga771, - Lga775, - S1, - AM2, - F, - Lga1366, - G34, - AM3, - C32, - Lga1156, - Lga1567, - Pga988A, - Bga1288, - RPga088B, - Bga1023, - Bga1224, - Lga1155, - Lga1356, - Lga2011, - FS1, - FS2, - FM1, - FM2, - Lga20113, - Lga13563, - Lga1150, - Bga1168, - Bga1234, - Bga1364, - AM4, - Lga1151, - Bga1356, - Bga1440, - Bga1515, - Lga36471, - SP3, - SP3R2, - Lga2066, - Bga1510, - Bga1528, - Lga4189 - } - - /// - /// System wake-up type based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.2.2. - /// - public enum SystemWakeUp - { - Reserved, - Other, - Unknown, - ApmTimer, - ModemRing, - LanRemote, - PowerSwitch, - PciPme, - AcPowerRestored - } - - /// - /// Cache associativity based on DMTF SMBIOS Reference Specification v.3.3.0, Chapter 7.8.5. - /// - public enum CacheAssociativity - { - Other = 1, - Unknown, - DirectMapped, - _2Way, - _4Way, - FullyAssociative, - _8Way, - _16Way, - _12Way, - _24Way, - _32Way, - _48Way, - _64Way, - _20Way - } - - /// - /// Processor cache level. - /// - public enum CacheDesignation - { - Other, - L1, - L2, - L3 - } - - /// - /// Memory type. - /// - public enum MemoryType - { - Other = 0x01, - Unknown = 0x02, - DRAM = 0x03, - EDRAM = 0x04, - VRAM = 0x05, - SRAM = 0x06, - RAM = 0x07, - ROM = 0x08, - FLASH = 0x09, - EEPROM = 0x0a, - FEPROM = 0x0b, - EPROM = 0x0c, - CDRAM = 0x0d, - _3DRAM = 0x0e, - SDRAM = 0x0f, - SGRAM = 0x10, - RDRAM = 0x11, - DDR = 0x12, - DDR2 = 0x13, - DDR2_FBDIMM = 0x14, - DDR3 = 0x18, - FBD2 = 0x19, - DDR4 = 0x1a, - LPDDR = 0x1b, - LPDDR2 = 0x1c, - LPDDR3 = 0x1d, - LPDDR4 = 0x1e, - LogicalNonVolatileDevice = 0x1f, - HBM = 0x20, - HBM2 = 0x21, - DDR5 = 0x22, - LPDDR5 = 0x23 - } - - public class InformationBase - { - private readonly byte[] _data; - private readonly IList _strings; - - /// - /// Initializes a new instance of the class. - /// - /// The data. - /// The strings. - protected InformationBase(byte[] data, IList strings) + if (offset + 1 < _data.Length && offset >= 0) { - _data = data; - _strings = strings; + return BitConverter.ToUInt16(_data, offset); } - /// - /// Gets the byte. - /// - /// The offset. - /// . - protected byte GetByte(int offset) - { - if (offset < _data.Length && offset >= 0) - return _data[offset]; + return 0; + } - return 0; + /// + /// Gets the dword. + /// + /// The offset. + /// . + protected uint GetDword(int offset) + { + if (offset + 3 < _data.Length && offset >= 0) + { + return BitConverter.ToUInt32(_data, offset); } - /// - /// Gets the word. - /// - /// The offset. - /// . - protected ushort GetWord(int offset) + return 0; + } + + /// + /// Gets the qword. + /// + /// The offset. + /// . + protected ulong GetQword(int offset) + { + if (offset + 7 < _data.Length && offset >= 0) { - if (offset + 1 < _data.Length && offset >= 0) + return BitConverter.ToUInt64(_data, offset); + } + + return 0; + } + + /// + /// Gets the string. + /// + /// The offset. + /// . + protected string GetString(int offset) + { + if (offset < _data.Length && _data[offset] > 0 && _data[offset] <= _strings.Count) + return _strings[_data[offset] - 1]; + + return string.Empty; + } +} + +/// +/// Motherboard BIOS information obtained from the SMBIOS table. +/// +public class BiosInformation : InformationBase +{ + internal BiosInformation(string vendor, string version, string date = null, ulong? size = null) : base(null, null) + { + Vendor = vendor; + Version = version; + Date = GetDate(date); + Size = size; + } + + internal BiosInformation(byte[] data, IList strings) : base(data, strings) + { + Vendor = GetString(0x04); + Version = GetString(0x05); + Date = GetDate(GetString(0x08)); + Size = GetSize(); + } + + /// + /// Gets the BIOS release date. + /// + public DateTime? Date { get; } + + /// + /// Gets the size of the physical device containing the BIOS. + /// + public ulong? Size { get; } + + /// + /// Gets the string number of the BIOS Vendor’s Name. + /// + public string Vendor { get; } + + /// + /// Gets the string number of the BIOS Version. This value is a free-form string that may contain Core and OEM version information. + /// + public string Version { get; } + + /// + /// Gets the size. + /// + /// . + private ulong? GetSize() + { + int biosRomSize = GetByte(0x09); + ushort extendedBiosRomSize = GetWord(0x18); + + bool isExtendedBiosRomSize = biosRomSize == 0xFF && extendedBiosRomSize != 0; + if (!isExtendedBiosRomSize) + return 65536 * (ulong)(biosRomSize + 1); + + int unit = (extendedBiosRomSize & 0xC000) >> 14; + ulong extendedSize = (ulong)(extendedBiosRomSize & ~0xC000) * 1024 * 1024; + + switch (unit) + { + case 0x00: return extendedSize; // Megabytes + case 0x01: return extendedSize * 1024; // Gigabytes - might overflow in the future + } + + return null; // Other patterns not defined in DMI 3.2.0 + } + + /// + /// Gets the date. + /// + /// The bios date. + /// . + private static DateTime? GetDate(string date) + { + string[] parts = (date ?? string.Empty).Split('/'); + + if (parts.Length == 3 && + int.TryParse(parts[0], out int month) && + int.TryParse(parts[1], out int day) && + int.TryParse(parts[2], out int year)) + { + if (month > 12) { - return BitConverter.ToUInt16(_data, offset); + (month, day) = (day, month); } - return 0; + return new DateTime(year < 100 ? 1900 + year : year, month, day); } - /// - /// Gets the dword. - /// - /// The offset. - /// . - protected uint GetDword(int offset) + return null; + } +} + +/// +/// System information obtained from the SMBIOS table. +/// +public class SystemInformation : InformationBase +{ + internal SystemInformation + ( + string manufacturerName, + string productName, + string version, + string serialNumber, + string family, + SystemWakeUp wakeUp = SystemWakeUp.Unknown) : base(null, null) + { + ManufacturerName = manufacturerName; + ProductName = productName; + Version = version; + SerialNumber = serialNumber; + Family = family; + WakeUp = wakeUp; + } + + internal SystemInformation(byte[] data, IList strings) : base(data, strings) + { + ManufacturerName = GetString(0x04); + ProductName = GetString(0x05); + Version = GetString(0x06); + SerialNumber = GetString(0x07); + Family = GetString(0x1A); + WakeUp = (SystemWakeUp)GetByte(0x18); + } + + /// + /// Gets the family associated with system. + /// + /// This text string identifies the family to which a particular computer belongs. A family refers to a set of computers that are similar but not identical from a hardware or software point of + /// view. Typically, a family is composed of different computer models, which have different configurations and pricing points. Computers in the same family often have similar branding and cosmetic + /// features. + /// + /// + public string Family { get; } + + /// + /// Gets the manufacturer name associated with system. + /// + public string ManufacturerName { get; } + + /// + /// Gets the product name associated with system. + /// + public string ProductName { get; } + + /// + /// Gets the serial number string associated with system. + /// + public string SerialNumber { get; } + + /// + /// Gets the version string associated with system. + /// + public string Version { get; } + + /// + /// Gets + /// + public SystemWakeUp WakeUp { get; } +} + +/// +/// System enclosure obtained from the SMBIOS table. +/// +public class SystemEnclosure : InformationBase +{ + internal SystemEnclosure(byte[] data, IList strings) : base(data, strings) + { + ManufacturerName = GetString(0x04).Trim(); + Version = GetString(0x06).Trim(); + SerialNumber = GetString(0x07).Trim(); + AssetTag = GetString(0x08).Trim(); + RackHeight = GetByte(0x11); + PowerCords = GetByte(0x12); + SKU = GetString(0x15).Trim(); + LockDetected = (GetByte(0x05) & 128) == 128; + Type = (SystemEnclosureType)(GetByte(0x05) & 127); + BootUpState = (SystemEnclosureState)GetByte(0x09); + PowerSupplyState = (SystemEnclosureState)GetByte(0x0A); + ThermalState = (SystemEnclosureState)GetByte(0x0B); + SecurityStatus = (SystemEnclosureSecurityStatus)GetByte(0x0C); + } + + /// + /// Gets the asset tag associated with the enclosure or chassis. + /// + public string AssetTag { get; } + + /// + /// Gets + /// + public SystemEnclosureState BootUpState { get; } + + /// + /// Gets or sets the system enclosure lock. + /// + /// System enclosure lock is present if . Otherwise, either a lock is not present or it is unknown if the enclosure has a lock. + public bool LockDetected { get; set; } + + /// + /// Gets the string describing the chassis or enclosure manufacturer name. + /// + public string ManufacturerName { get; } + + /// + /// Gets the number of power cords associated with the enclosure or chassis. + /// + public byte PowerCords { get; } + + /// + /// Gets the state of the enclosure’s power supply (or supplies) when last booted. + /// + public SystemEnclosureState PowerSupplyState { get; } + + /// + /// Gets the height of the enclosure, in 'U's. A U is a standard unit of measure for the height of a rack or rack-mountable component and is equal to 1.75 inches or 4.445 cm. A value of 0 + /// indicates that the enclosure height is unspecified. + /// + public byte RackHeight { get; } + + /// + /// Gets the physical security status of the enclosure when last booted. + /// + public SystemEnclosureSecurityStatus SecurityStatus { get; set; } + + /// + /// Gets the string describing the chassis or enclosure serial number. + /// + public string SerialNumber { get; } + + /// + /// Gets the string describing the chassis or enclosure SKU number. + /// + public string SKU { get; } + + /// + /// Gets the thermal state of the enclosure when last booted. + /// + public SystemEnclosureState ThermalState { get; } + + /// + /// Gets + /// + public SystemEnclosureType Type { get; } + + /// + /// Gets the number of null-terminated string representing the chassis or enclosure version. + /// + public string Version { get; } +} + +/// +/// Motherboard information obtained from the SMBIOS table. +/// +public class BaseBoardInformation : InformationBase +{ + internal BaseBoardInformation(string manufacturerName, string productName, string version, string serialNumber) : base(null, null) + { + ManufacturerName = manufacturerName; + ProductName = productName; + Version = version; + SerialNumber = serialNumber; + } + + internal BaseBoardInformation(byte[] data, IList strings) : base(data, strings) + { + ManufacturerName = GetString(0x04).Trim(); + ProductName = GetString(0x05).Trim(); + Version = GetString(0x06).Trim(); + SerialNumber = GetString(0x07).Trim(); + } + + /// + /// Gets the value that represents the manufacturer's name. + /// + public string ManufacturerName { get; } + + /// + /// Gets the value that represents the motherboard's name. + /// + public string ProductName { get; } + + /// + /// Gets the value that represents the motherboard's serial number. + /// + public string SerialNumber { get; } + + /// + /// Gets the value that represents the motherboard's revision number. + /// + public string Version { get; } +} + +/// +/// Processor information obtained from the SMBIOS table. +/// +public class ProcessorInformation : InformationBase +{ + internal ProcessorInformation(byte[] data, IList strings) : base(data, strings) + { + SocketDesignation = GetString(0x04).Trim(); + ManufacturerName = GetString(0x07).Trim(); + Version = GetString(0x10).Trim(); + CoreCount = GetByte(0x23) != 255 ? GetByte(0x23) : GetWord(0x2A); + CoreEnabled = GetByte(0x24) != 255 ? GetByte(0x24) : GetWord(0x2C); + ThreadCount = GetByte(0x25) != 255 ? GetByte(0x25) : GetWord(0x2E); + ExternalClock = GetWord(0x12); + MaxSpeed = GetWord(0x14); + CurrentSpeed = GetWord(0x16); + Serial = GetString(0x20).Trim(); + Id = GetQword(0x08); + Handle = GetWord(0x02); + + byte characteristics1 = GetByte(0x26); + byte characteristics2 = GetByte(0x27); + + Characteristics = ProcessorCharacteristics.None; + if (IsBitSet(characteristics1, 2)) + Characteristics |= ProcessorCharacteristics._64BitCapable; + + if (IsBitSet(characteristics1, 3)) + Characteristics |= ProcessorCharacteristics.MultiCore; + + if (IsBitSet(characteristics1, 4)) + Characteristics |= ProcessorCharacteristics.HardwareThread; + + if (IsBitSet(characteristics1, 5)) + Characteristics |= ProcessorCharacteristics.ExecuteProtection; + + if (IsBitSet(characteristics1, 6)) + Characteristics |= ProcessorCharacteristics.EnhancedVirtualization; + + if (IsBitSet(characteristics1, 7)) + Characteristics |= ProcessorCharacteristics.PowerPerformanceControl; + + if (IsBitSet(characteristics2, 0)) + Characteristics |= ProcessorCharacteristics._128BitCapable; + + ProcessorType = (ProcessorType)GetByte(0x05); + Socket = (ProcessorSocket)GetByte(0x19); + + int family = GetByte(0x06); + Family = (ProcessorFamily)(family == 254 ? GetWord(0x28) : family); + + L1CacheHandle = GetWord(0x1A); + L2CacheHandle = GetWord(0x1C); + L3CacheHandle = GetWord(0x1E); + + bool IsBitSet(byte b, int pos) { - if (offset + 3 < _data.Length && offset >= 0) - { - return BitConverter.ToUInt32(_data, offset); - } - - return 0; - } - - /// - /// Gets the qword. - /// - /// The offset. - /// . - protected ulong GetQword(int offset) - { - if (offset + 7 < _data.Length && offset >= 0) - { - return BitConverter.ToUInt64(_data, offset); - } - - return 0; - } - - /// - /// Gets the string. - /// - /// The offset. - /// . - protected string GetString(int offset) - { - if (offset < _data.Length && _data[offset] > 0 && _data[offset] <= _strings.Count) - return _strings[_data[offset] - 1]; - - return string.Empty; + return (b & (1 << pos)) != 0; } } /// - /// Motherboard BIOS information obtained from the SMBIOS table. + /// Gets the characteristics of the processor. /// - public class BiosInformation : InformationBase + public ProcessorCharacteristics Characteristics { get; } + + /// + /// Gets the value that represents the number of cores per processor socket. + /// + public ushort CoreCount { get; } + + /// + /// Gets the value that represents the number of enabled cores per processor socket. + /// + public ushort CoreEnabled { get; } + + /// + /// Gets the value that represents the current processor speed (in MHz). + /// + public ushort CurrentSpeed { get; } + + /// + /// Gets the external Clock Frequency, in MHz. If the value is unknown, the field is set to 0. + /// + public ushort ExternalClock { get; } + + /// + /// Gets + /// + public ProcessorFamily Family { get; } + + /// + /// Gets the handle. + /// + /// The handle. + public ushort Handle { get; } + + /// + /// Gets the identifier. + /// + public ulong Id { get; } + + /// + /// Gets the L1 cache handle. + /// + public ushort L1CacheHandle { get; } + + /// + /// Gets the L2 cache handle. + /// + public ushort L2CacheHandle { get; } + + /// + /// Gets the L3 cache handle. + /// + public ushort L3CacheHandle { get; } + + /// + /// Gets the string number of Processor Manufacturer. + /// + public string ManufacturerName { get; } + + /// + /// Gets the value that represents the maximum processor speed (in MHz) supported by the system for this processor socket. + /// + public ushort MaxSpeed { get; } + + /// + /// Gets + /// + public ProcessorType ProcessorType { get; } + + /// + /// Gets the value that represents the string number for the serial number of this processor. + /// This value is set by the manufacturer and normally not changeable. + /// + public string Serial { get; } + + /// + /// Gets + /// + public ProcessorSocket Socket { get; } + + /// + /// Gets the string number for Reference Designation. + /// + public string SocketDesignation { get; } + + /// + /// Gets the value that represents the number of threads per processor socket. + /// + public ushort ThreadCount { get; } + + /// + /// Gets the value that represents the string number describing the Processor. + /// + public string Version { get; } +} + +/// +/// Cache information obtained from the SMBIOS table. +/// +public class CacheInformation : InformationBase +{ + internal CacheInformation(byte[] data, IList strings) : base(data, strings) { - internal BiosInformation(string vendor, string version, string date = null, ulong? size = null) : base(null, null) + Handle = GetWord(0x02); + Designation = GetCacheDesignation(); + Associativity = (CacheAssociativity)GetByte(0x12); + Size = GetWord(0x09); + } + + /// + /// Gets + /// + public CacheAssociativity Associativity { get; } + + /// + /// Gets + /// + public CacheDesignation Designation { get; } + + /// + /// Gets the handle. + /// + public ushort Handle { get; } + + /// + /// Gets the value that represents the installed cache size. + /// + public ushort Size { get; } + + /// + /// Gets the cache designation. + /// + /// . + private CacheDesignation GetCacheDesignation() + { + string rawCacheType = GetString(0x04); + + if (rawCacheType.Contains("L1")) + return CacheDesignation.L1; + + if (rawCacheType.Contains("L2")) + return CacheDesignation.L2; + + if (rawCacheType.Contains("L3")) + return CacheDesignation.L3; + + return CacheDesignation.Other; + } +} + +/// +/// Memory information obtained from the SMBIOS table. +/// +public class MemoryDevice : InformationBase +{ + internal MemoryDevice(byte[] data, IList strings) : base(data, strings) + { + DeviceLocator = GetString(0x10).Trim(); + BankLocator = GetString(0x11).Trim(); + ManufacturerName = GetString(0x17).Trim(); + SerialNumber = GetString(0x18).Trim(); + PartNumber = GetString(0x1A).Trim(); + Speed = GetWord(0x15); + Size = GetWord(0x0C); + Type = (MemoryType)GetByte(0x12); + + if (GetWord(0x1C) > 0) + Size += GetWord(0x1C); + } + + /// + /// Gets the string number of the string that identifies the physically labeled bank where the memory device is located. + /// + public string BankLocator { get; } + + /// + /// Gets the string number of the string that identifies the physically-labeled socket or board position where the memory device is located. + /// + public string DeviceLocator { get; } + + /// + /// Gets the string number for the manufacturer of this memory device. + /// + public string ManufacturerName { get; } + + /// + /// Gets the string number for the part number of this memory device. + /// + public string PartNumber { get; } + + /// + /// Gets the string number for the serial number of this memory device. + /// + public string SerialNumber { get; } + + /// + /// Gets the size of the memory device. If the value is 0, no memory device is installed in the socket. + /// + public ushort Size { get; } + + /// + /// Gets the value that identifies the maximum capable speed of the device, in mega transfers per second (MT/s). + /// + public ushort Speed { get; } + + /// + /// Gets the type of this memory device. + /// + /// The type. + public MemoryType Type { get; } +} + +/// +/// Reads and processes information encoded in an SMBIOS table. +/// +public class SMBios +{ + private readonly byte[] _raw; + private readonly Version _version; + + /// + /// Initializes a new instance of the class. + /// + public SMBios() + { + if (Software.OperatingSystem.IsUnix) { - Vendor = vendor; - Version = version; - Date = GetDate(date); - Size = size; + _raw = null; + + string boardVendor = ReadSysFs("/sys/class/dmi/id/board_vendor"); + string boardName = ReadSysFs("/sys/class/dmi/id/board_name"); + string boardVersion = ReadSysFs("/sys/class/dmi/id/board_version"); + Board = new BaseBoardInformation(boardVendor, boardName, boardVersion, null); + + string systemVendor = ReadSysFs("/sys/class/dmi/id/sys_vendor"); + string productName = ReadSysFs("/sys/class/dmi/id/product_name"); + string productVersion = ReadSysFs("/sys/class/dmi/id/product_version"); + System = new SystemInformation(systemVendor, productName, productVersion, null, null); + + string biosVendor = ReadSysFs("/sys/class/dmi/id/bios_vendor"); + string biosVersion = ReadSysFs("/sys/class/dmi/id/bios_version"); + string biosDate = ReadSysFs("/sys/class/dmi/id/bios_date"); + Bios = new BiosInformation(biosVendor, biosVersion, biosDate); + + MemoryDevices = Array.Empty(); } - - internal BiosInformation(byte[] data, IList strings) : base(data, strings) + else { - Vendor = GetString(0x04); - Version = GetString(0x05); - Date = GetDate(GetString(0x08)); - Size = GetSize(); - } + List memoryDeviceList = new(); + List processorCacheList = new(); + List processorInformationList = new(); - /// - /// Gets the BIOS release date. - /// - public DateTime? Date { get; } - - /// - /// Gets the size of the physical device containing the BIOS. - /// - public ulong? Size { get; } - - /// - /// Gets the string number of the BIOS Vendor’s Name. - /// - public string Vendor { get; } - - /// - /// Gets the string number of the BIOS Version. This value is a free-form string that may contain Core and OEM version information. - /// - public string Version { get; } - - /// - /// Gets the size. - /// - /// . - private ulong? GetSize() - { - int biosRomSize = GetByte(0x09); - ushort extendedBiosRomSize = GetWord(0x18); - - bool isExtendedBiosRomSize = biosRomSize == 0xFF && extendedBiosRomSize != 0; - if (!isExtendedBiosRomSize) - return 65536 * (ulong)(biosRomSize + 1); - - int unit = (extendedBiosRomSize & 0xC000) >> 14; - ulong extendedSize = (ulong)(extendedBiosRomSize & ~0xC000) * 1024 * 1024; - - switch (unit) + string[] tables = FirmwareTable.EnumerateTables(Kernel32.Provider.RSMB); + if (tables is { Length: > 0 }) { - case 0x00: return extendedSize; // Megabytes - case 0x01: return extendedSize * 1024; // Gigabytes - might overflow in the future - } + _raw = FirmwareTable.GetTable(Kernel32.Provider.RSMB, tables[0]); + if (_raw == null || _raw.Length == 0) + return; - return null; // Other patterns not defined in DMI 3.2.0 - } + byte majorVersion = _raw[1]; + byte minorVersion = _raw[2]; - /// - /// Gets the date. - /// - /// The bios date. - /// . - private static DateTime? GetDate(string date) - { - string[] parts = (date ?? string.Empty).Split('/'); + if (majorVersion > 0 || minorVersion > 0) + _version = new Version(majorVersion, minorVersion); - if (parts.Length == 3 && - int.TryParse(parts[0], out int month) && - int.TryParse(parts[1], out int day) && - int.TryParse(parts[2], out int year)) - { - if (month > 12) + if (_raw is { Length: > 0 }) { - (month, day) = (day, month); - } + int offset = 8; + byte type = _raw[offset]; - return new DateTime(year < 100 ? 1900 + year : year, month, day); + while (offset + 4 < _raw.Length && type != 127) + { + type = _raw[offset]; + int length = _raw[offset + 1]; + + if (offset + length > _raw.Length) + break; + + byte[] data = new byte[length]; + Array.Copy(_raw, offset, data, 0, length); + offset += length; + + List strings = new(); + if (offset < _raw.Length && _raw[offset] == 0) + offset++; + + while (offset < _raw.Length && _raw[offset] != 0) + { + StringBuilder stringBuilder = new(); + + while (offset < _raw.Length && _raw[offset] != 0) + { + stringBuilder.Append((char)_raw[offset]); + offset++; + } + + offset++; + + strings.Add(stringBuilder.ToString()); + } + + offset++; + switch (type) + { + case 0x00: + Bios = new BiosInformation(data, strings); + break; + case 0x01: + System = new SystemInformation(data, strings); + break; + case 0x02: + Board = new BaseBoardInformation(data, strings); + break; + case 0x03: + SystemEnclosure = new SystemEnclosure(data, strings); + break; + case 0x04: + processorInformationList.Add(new ProcessorInformation(data, strings)); + break; + case 0x07: + processorCacheList.Add(new CacheInformation(data, strings)); + break; + case 0x11: + memoryDeviceList.Add(new MemoryDevice(data, strings)); + break; + } + } + } } + MemoryDevices = memoryDeviceList.ToArray(); + ProcessorCaches = processorCacheList.ToArray(); + Processors = processorInformationList.ToArray(); + } + } + + /// + /// Gets + /// + public BiosInformation Bios { get; } + + /// + /// Gets + /// + public BaseBoardInformation Board { get; } + + /// + /// Gets + /// + public MemoryDevice[] MemoryDevices { get; } + + /// + /// Gets + /// + public CacheInformation[] ProcessorCaches { get; } + + /// + /// Gets + /// + public ProcessorInformation[] Processors { get; } + + /// + /// Gets + /// + public SystemInformation System { get; } + + /// + /// Gets + /// + public SystemEnclosure SystemEnclosure { get; } + + private static string ReadSysFs(string path) + { + try + { + if (File.Exists(path)) + { + using StreamReader reader = new(path); + + return reader.ReadLine(); + } + + return null; + } + catch + { return null; } } /// - /// System information obtained from the SMBIOS table. + /// Report containing most of the information that could be read from the SMBIOS table. /// - public class SystemInformation : InformationBase + /// A formatted text string with computer information and the entire SMBIOS table. + public string GetReport() { - internal SystemInformation - ( - string manufacturerName, - string productName, - string version, - string serialNumber, - string family, - SystemWakeUp wakeUp = SystemWakeUp.Unknown) : base(null, null) + StringBuilder r = new(); + + if (_version != null) { - ManufacturerName = manufacturerName; - ProductName = productName; - Version = version; - SerialNumber = serialNumber; - Family = family; - WakeUp = wakeUp; + r.Append("SMBios Version: "); + r.AppendLine(_version.ToString(2)); + r.AppendLine(); } - internal SystemInformation(byte[] data, IList strings) : base(data, strings) + if (Bios != null) { - ManufacturerName = GetString(0x04); - ProductName = GetString(0x05); - Version = GetString(0x06); - SerialNumber = GetString(0x07); - Family = GetString(0x1A); - WakeUp = (SystemWakeUp)GetByte(0x18); - } - - /// - /// Gets the family associated with system. - /// - /// This text string identifies the family to which a particular computer belongs. A family refers to a set of computers that are similar but not identical from a hardware or software point of - /// view. Typically, a family is composed of different computer models, which have different configurations and pricing points. Computers in the same family often have similar branding and cosmetic - /// features. - /// - /// - public string Family { get; } - - /// - /// Gets the manufacturer name associated with system. - /// - public string ManufacturerName { get; } - - /// - /// Gets the product name associated with system. - /// - public string ProductName { get; } - - /// - /// Gets the serial number string associated with system. - /// - public string SerialNumber { get; } - - /// - /// Gets the version string associated with system. - /// - public string Version { get; } - - /// - /// Gets - /// - public SystemWakeUp WakeUp { get; } - } - - /// - /// System enclosure obtained from the SMBIOS table. - /// - public class SystemEnclosure : InformationBase - { - internal SystemEnclosure(byte[] data, IList strings) : base(data, strings) - { - ManufacturerName = GetString(0x04).Trim(); - Version = GetString(0x06).Trim(); - SerialNumber = GetString(0x07).Trim(); - AssetTag = GetString(0x08).Trim(); - RackHeight = GetByte(0x11); - PowerCords = GetByte(0x12); - SKU = GetString(0x15).Trim(); - LockDetected = (GetByte(0x05) & 128) == 128; - Type = (SystemEnclosureType)(GetByte(0x05) & 127); - BootUpState = (SystemEnclosureState)GetByte(0x09); - PowerSupplyState = (SystemEnclosureState)GetByte(0x0A); - ThermalState = (SystemEnclosureState)GetByte(0x0B); - SecurityStatus = (SystemEnclosureSecurityStatus)GetByte(0x0C); - } - - /// - /// Gets the asset tag associated with the enclosure or chassis. - /// - public string AssetTag { get; } - - /// - /// Gets - /// - public SystemEnclosureState BootUpState { get; } - - /// - /// Gets or sets the system enclosure lock. - /// - /// System enclosure lock is present if . Otherwise, either a lock is not present or it is unknown if the enclosure has a lock. - public bool LockDetected { get; set; } - - /// - /// Gets the string describing the chassis or enclosure manufacturer name. - /// - public string ManufacturerName { get; } - - /// - /// Gets the number of power cords associated with the enclosure or chassis. - /// - public byte PowerCords { get; } - - /// - /// Gets the state of the enclosure’s power supply (or supplies) when last booted. - /// - public SystemEnclosureState PowerSupplyState { get; } - - /// - /// Gets the height of the enclosure, in 'U's. A U is a standard unit of measure for the height of a rack or rack-mountable component and is equal to 1.75 inches or 4.445 cm. A value of 0 - /// indicates that the enclosure height is unspecified. - /// - public byte RackHeight { get; } - - /// - /// Gets the physical security status of the enclosure when last booted. - /// - public SystemEnclosureSecurityStatus SecurityStatus { get; set; } - - /// - /// Gets the string describing the chassis or enclosure serial number. - /// - public string SerialNumber { get; } - - /// - /// Gets the string describing the chassis or enclosure SKU number. - /// - public string SKU { get; } - - /// - /// Gets the thermal state of the enclosure when last booted. - /// - public SystemEnclosureState ThermalState { get; } - - /// - /// Gets - /// - public SystemEnclosureType Type { get; } - - /// - /// Gets the number of null-terminated string representing the chassis or enclosure version. - /// - public string Version { get; } - } - - /// - /// Motherboard information obtained from the SMBIOS table. - /// - public class BaseBoardInformation : InformationBase - { - internal BaseBoardInformation(string manufacturerName, string productName, string version, string serialNumber) : base(null, null) - { - ManufacturerName = manufacturerName; - ProductName = productName; - Version = version; - SerialNumber = serialNumber; - } - - internal BaseBoardInformation(byte[] data, IList strings) : base(data, strings) - { - ManufacturerName = GetString(0x04).Trim(); - ProductName = GetString(0x05).Trim(); - Version = GetString(0x06).Trim(); - SerialNumber = GetString(0x07).Trim(); - } - - /// - /// Gets the value that represents the manufacturer's name. - /// - public string ManufacturerName { get; } - - /// - /// Gets the value that represents the motherboard's name. - /// - public string ProductName { get; } - - /// - /// Gets the value that represents the motherboard's serial number. - /// - public string SerialNumber { get; } - - /// - /// Gets the value that represents the motherboard's revision number. - /// - public string Version { get; } - } - - /// - /// Processor information obtained from the SMBIOS table. - /// - public class ProcessorInformation : InformationBase - { - internal ProcessorInformation(byte[] data, IList strings) : base(data, strings) - { - SocketDesignation = GetString(0x04).Trim(); - ManufacturerName = GetString(0x07).Trim(); - Version = GetString(0x10).Trim(); - CoreCount = GetByte(0x23) != 255 ? GetByte(0x23) : GetWord(0x2A); - CoreEnabled = GetByte(0x24) != 255 ? GetByte(0x24) : GetWord(0x2C); - ThreadCount = GetByte(0x25) != 255 ? GetByte(0x25) : GetWord(0x2E); - ExternalClock = GetWord(0x12); - MaxSpeed = GetWord(0x14); - CurrentSpeed = GetWord(0x16); - Serial = GetString(0x20).Trim(); - Id = GetQword(0x08); - Handle = GetWord(0x02); - - byte characteristics1 = GetByte(0x26); - byte characteristics2 = GetByte(0x27); - - Characteristics = ProcessorCharacteristics.None; - if (IsBitSet(characteristics1, 2)) - Characteristics |= ProcessorCharacteristics._64BitCapable; - - if (IsBitSet(characteristics1, 3)) - Characteristics |= ProcessorCharacteristics.MultiCore; - - if (IsBitSet(characteristics1, 4)) - Characteristics |= ProcessorCharacteristics.HardwareThread; - - if (IsBitSet(characteristics1, 5)) - Characteristics |= ProcessorCharacteristics.ExecuteProtection; - - if (IsBitSet(characteristics1, 6)) - Characteristics |= ProcessorCharacteristics.EnhancedVirtualization; - - if (IsBitSet(characteristics1, 7)) - Characteristics |= ProcessorCharacteristics.PowerPerformanceControl; - - if (IsBitSet(characteristics2, 0)) - Characteristics |= ProcessorCharacteristics._128BitCapable; - - ProcessorType = (ProcessorType)GetByte(0x05); - Socket = (ProcessorSocket)GetByte(0x19); - - int family = GetByte(0x06); - Family = (ProcessorFamily)(family == 254 ? GetWord(0x28) : family); - - L1CacheHandle = GetWord(0x1A); - L2CacheHandle = GetWord(0x1C); - L3CacheHandle = GetWord(0x1E); - - bool IsBitSet(byte b, int pos) + r.Append("BIOS Vendor: "); + r.AppendLine(Bios.Vendor); + r.Append("BIOS Version: "); + r.AppendLine(Bios.Version); + if (Bios.Date != null) { - return (b & (1 << pos)) != 0; + r.Append("BIOS Date: "); + r.AppendLine(Bios.Date.Value.ToShortDateString()); + } + + if (Bios.Size != null) + { + const int megabyte = 1024 * 1024; + r.Append("BIOS Size: "); + if (Bios.Size > megabyte) + r.AppendLine((Bios.Size.Value / megabyte) + " MB"); + else + r.AppendLine((Bios.Size.Value / 1024) + " KB"); + } + + r.AppendLine(); + } + + if (System != null) + { + r.Append("System Manufacturer: "); + r.AppendLine(System.ManufacturerName); + r.Append("System Name: "); + r.AppendLine(System.ProductName); + r.Append("System Version: "); + r.AppendLine(System.Version); + r.Append("System Wakeup: "); + r.AppendLine(System.WakeUp.ToString()); + r.AppendLine(); + } + + if (Board != null) + { + r.Append("Motherboard Manufacturer: "); + r.AppendLine(Board.ManufacturerName); + r.Append("Motherboard Name: "); + r.AppendLine(Board.ProductName); + r.Append("Motherboard Version: "); + r.AppendLine(Board.Version); + r.Append("Motherboard Serial: "); + r.AppendLine(Board.SerialNumber); + r.AppendLine(); + } + + if (SystemEnclosure != null) + { + r.Append("System Enclosure Type: "); + r.AppendLine(SystemEnclosure.Type.ToString()); + r.Append("System Enclosure Manufacturer: "); + r.AppendLine(SystemEnclosure.ManufacturerName); + r.Append("System Enclosure Version: "); + r.AppendLine(SystemEnclosure.Version); + r.Append("System Enclosure Serial: "); + r.AppendLine(SystemEnclosure.SerialNumber); + r.Append("System Enclosure Asset Tag: "); + r.AppendLine(SystemEnclosure.AssetTag); + if (!string.IsNullOrEmpty(SystemEnclosure.SKU)) + { + r.Append("System Enclosure SKU: "); + r.AppendLine(SystemEnclosure.SKU); + } + + r.Append("System Enclosure Boot Up State: "); + r.AppendLine(SystemEnclosure.BootUpState.ToString()); + r.Append("System Enclosure Power Supply State: "); + r.AppendLine(SystemEnclosure.PowerSupplyState.ToString()); + r.Append("System Enclosure Thermal State: "); + r.AppendLine(SystemEnclosure.ThermalState.ToString()); + r.Append("System Enclosure Power Cords: "); + r.AppendLine(SystemEnclosure.PowerCords.ToString()); + if (SystemEnclosure.RackHeight > 0) + { + r.Append("System Enclosure Rack Height: "); + r.AppendLine(SystemEnclosure.RackHeight.ToString()); + } + + r.Append("System Enclosure Lock Detected: "); + r.AppendLine(SystemEnclosure.LockDetected ? "Yes" : "No"); + r.Append("System Enclosure Security Status: "); + r.AppendLine(SystemEnclosure.SecurityStatus.ToString()); + r.AppendLine(); + } + + if (Processors != null) + { + foreach (ProcessorInformation processor in Processors) + { + r.Append("Processor Manufacturer: "); + r.AppendLine(processor.ManufacturerName); + r.Append("Processor Type: "); + r.AppendLine(processor.ProcessorType.ToString()); + r.Append("Processor Version: "); + r.AppendLine(processor.Version); + r.Append("Processor Serial: "); + r.AppendLine(processor.Serial); + r.Append("Processor Socket Destignation: "); + r.AppendLine(processor.SocketDesignation); + r.Append("Processor Socket: "); + r.AppendLine(processor.Socket.ToString()); + r.Append("Processor Version: "); + r.AppendLine(processor.Version); + r.Append("Processor Family: "); + r.AppendLine(processor.Family.ToString()); + r.Append("Processor Core Count: "); + r.AppendLine(processor.CoreCount.ToString()); + r.Append("Processor Core Enabled: "); + r.AppendLine(processor.CoreEnabled.ToString()); + r.Append("Processor Thread Count: "); + r.AppendLine(processor.ThreadCount.ToString()); + r.Append("Processor External Clock: "); + r.Append(processor.ExternalClock); + r.AppendLine(" Mhz"); + r.Append("Processor Max Speed: "); + r.Append(processor.MaxSpeed); + r.AppendLine(" Mhz"); + r.Append("Processor Current Speed: "); + r.Append(processor.CurrentSpeed); + r.AppendLine(" Mhz"); + r.AppendLine(); } } - /// - /// Gets the characteristics of the processor. - /// - public ProcessorCharacteristics Characteristics { get; } - - /// - /// Gets the value that represents the number of cores per processor socket. - /// - public ushort CoreCount { get; } - - /// - /// Gets the value that represents the number of enabled cores per processor socket. - /// - public ushort CoreEnabled { get; } - - /// - /// Gets the value that represents the current processor speed (in MHz). - /// - public ushort CurrentSpeed { get; } - - /// - /// Gets the external Clock Frequency, in MHz. If the value is unknown, the field is set to 0. - /// - public ushort ExternalClock { get; } - - /// - /// Gets - /// - public ProcessorFamily Family { get; } - - /// - /// Gets the handle. - /// - /// The handle. - public ushort Handle { get; } - - /// - /// Gets the identifier. - /// - public ulong Id { get; } - - /// - /// Gets the L1 cache handle. - /// - public ushort L1CacheHandle { get; } - - /// - /// Gets the L2 cache handle. - /// - public ushort L2CacheHandle { get; } - - /// - /// Gets the L3 cache handle. - /// - public ushort L3CacheHandle { get; } - - /// - /// Gets the string number of Processor Manufacturer. - /// - public string ManufacturerName { get; } - - /// - /// Gets the value that represents the maximum processor speed (in MHz) supported by the system for this processor socket. - /// - public ushort MaxSpeed { get; } - - /// - /// Gets - /// - public ProcessorType ProcessorType { get; } - - /// - /// Gets the value that represents the string number for the serial number of this processor. - /// This value is set by the manufacturer and normally not changeable. - /// - public string Serial { get; } - - /// - /// Gets - /// - public ProcessorSocket Socket { get; } - - /// - /// Gets the string number for Reference Designation. - /// - public string SocketDesignation { get; } - - /// - /// Gets the value that represents the number of threads per processor socket. - /// - public ushort ThreadCount { get; } - - /// - /// Gets the value that represents the string number describing the Processor. - /// - public string Version { get; } - } - - /// - /// Cache information obtained from the SMBIOS table. - /// - public class CacheInformation : InformationBase - { - internal CacheInformation(byte[] data, IList strings) : base(data, strings) + for (int i = 0; i < ProcessorCaches.Length; i++) { - Handle = GetWord(0x02); - Designation = GetCacheDesignation(); - Associativity = (CacheAssociativity)GetByte(0x12); - Size = GetWord(0x09); + r.Append("Cache [" + ProcessorCaches[i].Designation + "] Size: "); + r.AppendLine(ProcessorCaches[i].Size.ToString()); + r.Append("Cache [" + ProcessorCaches[i].Designation + "] Associativity: "); + r.AppendLine(ProcessorCaches[i].Associativity.ToString().Replace("_", string.Empty)); + r.AppendLine(); } - /// - /// Gets - /// - public CacheAssociativity Associativity { get; } - - /// - /// Gets - /// - public CacheDesignation Designation { get; } - - /// - /// Gets the handle. - /// - public ushort Handle { get; } - - /// - /// Gets the value that represents the installed cache size. - /// - public ushort Size { get; } - - /// - /// Gets the cache designation. - /// - /// . - private CacheDesignation GetCacheDesignation() + for (int i = 0; i < MemoryDevices.Length; i++) { - string rawCacheType = GetString(0x04); - - if (rawCacheType.Contains("L1")) - return CacheDesignation.L1; - - if (rawCacheType.Contains("L2")) - return CacheDesignation.L2; - - if (rawCacheType.Contains("L3")) - return CacheDesignation.L3; - - return CacheDesignation.Other; - } - } - - /// - /// Memory information obtained from the SMBIOS table. - /// - public class MemoryDevice : InformationBase - { - internal MemoryDevice(byte[] data, IList strings) : base(data, strings) - { - DeviceLocator = GetString(0x10).Trim(); - BankLocator = GetString(0x11).Trim(); - ManufacturerName = GetString(0x17).Trim(); - SerialNumber = GetString(0x18).Trim(); - PartNumber = GetString(0x1A).Trim(); - Speed = GetWord(0x15); - Size = GetWord(0x0C); - Type = (MemoryType)GetByte(0x12); - - if (GetWord(0x1C) > 0) - Size += GetWord(0x1C); + r.Append("Memory Device [" + i + "] Manufacturer: "); + r.AppendLine(MemoryDevices[i].ManufacturerName); + r.Append("Memory Device [" + i + "] Part Number: "); + r.AppendLine(MemoryDevices[i].PartNumber); + r.Append("Memory Device [" + i + "] Device Locator: "); + r.AppendLine(MemoryDevices[i].DeviceLocator); + r.Append("Memory Device [" + i + "] Bank Locator: "); + r.AppendLine(MemoryDevices[i].BankLocator); + r.Append("Memory Device [" + i + "] Speed: "); + r.AppendLine(MemoryDevices[i].Speed.ToString()); + r.Append("Memory Device [" + i + "] Size: "); + r.Append(MemoryDevices[i].Size.ToString()); + r.AppendLine(" MB"); + r.AppendLine(); } - /// - /// Gets the string number of the string that identifies the physically labeled bank where the memory device is located. - /// - public string BankLocator { get; } - - /// - /// Gets the string number of the string that identifies the physically-labeled socket or board position where the memory device is located. - /// - public string DeviceLocator { get; } - - /// - /// Gets the string number for the manufacturer of this memory device. - /// - public string ManufacturerName { get; } - - /// - /// Gets the string number for the part number of this memory device. - /// - public string PartNumber { get; } - - /// - /// Gets the string number for the serial number of this memory device. - /// - public string SerialNumber { get; } - - /// - /// Gets the size of the memory device. If the value is 0, no memory device is installed in the socket. - /// - public ushort Size { get; } - - /// - /// Gets the value that identifies the maximum capable speed of the device, in mega transfers per second (MT/s). - /// - public ushort Speed { get; } - - /// - /// Gets the type of this memory device. - /// - /// The type. - public MemoryType Type { get; } - } - - /// - /// Reads and processes information encoded in an SMBIOS table. - /// - public class SMBios - { - private readonly byte[] _raw; - private readonly Version _version; - - /// - /// Initializes a new instance of the class. - /// - public SMBios() + if (_raw != null) { - if (Software.OperatingSystem.IsUnix) + string base64 = Convert.ToBase64String(_raw); + r.AppendLine("SMBios Table"); + r.AppendLine(); + + for (int i = 0; i < Math.Ceiling(base64.Length / 64.0); i++) { - _raw = null; - - string boardVendor = ReadSysFs("/sys/class/dmi/id/board_vendor"); - string boardName = ReadSysFs("/sys/class/dmi/id/board_name"); - string boardVersion = ReadSysFs("/sys/class/dmi/id/board_version"); - Board = new BaseBoardInformation(boardVendor, boardName, boardVersion, null); - - string systemVendor = ReadSysFs("/sys/class/dmi/id/sys_vendor"); - string productName = ReadSysFs("/sys/class/dmi/id/product_name"); - string productVersion = ReadSysFs("/sys/class/dmi/id/product_version"); - System = new SystemInformation(systemVendor, productName, productVersion, null, null); - - string biosVendor = ReadSysFs("/sys/class/dmi/id/bios_vendor"); - string biosVersion = ReadSysFs("/sys/class/dmi/id/bios_version"); - string biosDate = ReadSysFs("/sys/class/dmi/id/bios_date"); - Bios = new BiosInformation(biosVendor, biosVersion, biosDate); - - MemoryDevices = Array.Empty(); - } - else - { - List memoryDeviceList = new(); - List processorCacheList = new(); - List processorInformationList = new(); - - string[] tables = FirmwareTable.EnumerateTables(Kernel32.Provider.RSMB); - if (tables is { Length: > 0 }) + r.Append(" "); + for (int j = 0; j < 0x40; j++) { - _raw = FirmwareTable.GetTable(Kernel32.Provider.RSMB, tables[0]); - if (_raw == null || _raw.Length == 0) - return; - - byte majorVersion = _raw[1]; - byte minorVersion = _raw[2]; - - if (majorVersion > 0 || minorVersion > 0) - _version = new Version(majorVersion, minorVersion); - - if (_raw is { Length: > 0 }) + int index = (i << 6) | j; + if (index < base64.Length) { - int offset = 8; - byte type = _raw[offset]; - - while (offset + 4 < _raw.Length && type != 127) - { - type = _raw[offset]; - int length = _raw[offset + 1]; - - if (offset + length > _raw.Length) - break; - - byte[] data = new byte[length]; - Array.Copy(_raw, offset, data, 0, length); - offset += length; - - List strings = new(); - if (offset < _raw.Length && _raw[offset] == 0) - offset++; - - while (offset < _raw.Length && _raw[offset] != 0) - { - StringBuilder stringBuilder = new(); - - while (offset < _raw.Length && _raw[offset] != 0) - { - stringBuilder.Append((char)_raw[offset]); - offset++; - } - - offset++; - - strings.Add(stringBuilder.ToString()); - } - - offset++; - switch (type) - { - case 0x00: - Bios = new BiosInformation(data, strings); - break; - case 0x01: - System = new SystemInformation(data, strings); - break; - case 0x02: - Board = new BaseBoardInformation(data, strings); - break; - case 0x03: - SystemEnclosure = new SystemEnclosure(data, strings); - break; - case 0x04: - processorInformationList.Add(new ProcessorInformation(data, strings)); - break; - case 0x07: - processorCacheList.Add(new CacheInformation(data, strings)); - break; - case 0x11: - memoryDeviceList.Add(new MemoryDevice(data, strings)); - break; - } - } + r.Append(base64[index]); } } - MemoryDevices = memoryDeviceList.ToArray(); - ProcessorCaches = processorCacheList.ToArray(); - Processors = processorInformationList.ToArray(); + r.AppendLine(); } + + r.AppendLine(); } - /// - /// Gets - /// - public BiosInformation Bios { get; } - - /// - /// Gets - /// - public BaseBoardInformation Board { get; } - - /// - /// Gets - /// - public MemoryDevice[] MemoryDevices { get; } - - /// - /// Gets - /// - public CacheInformation[] ProcessorCaches { get; } - - /// - /// Gets - /// - public ProcessorInformation[] Processors { get; } - - /// - /// Gets - /// - public SystemInformation System { get; } - - /// - /// Gets - /// - public SystemEnclosure SystemEnclosure { get; } - - private static string ReadSysFs(string path) - { - try - { - if (File.Exists(path)) - { - using StreamReader reader = new(path); - - return reader.ReadLine(); - } - - return null; - } - catch - { - return null; - } - } - - /// - /// Report containing most of the information that could be read from the SMBIOS table. - /// - /// A formatted text string with computer information and the entire SMBIOS table. - public string GetReport() - { - StringBuilder r = new(); - - if (_version != null) - { - r.Append("SMBios Version: "); - r.AppendLine(_version.ToString(2)); - r.AppendLine(); - } - - if (Bios != null) - { - r.Append("BIOS Vendor: "); - r.AppendLine(Bios.Vendor); - r.Append("BIOS Version: "); - r.AppendLine(Bios.Version); - if (Bios.Date != null) - { - r.Append("BIOS Date: "); - r.AppendLine(Bios.Date.Value.ToShortDateString()); - } - - if (Bios.Size != null) - { - const int megabyte = 1024 * 1024; - r.Append("BIOS Size: "); - if (Bios.Size > megabyte) - r.AppendLine((Bios.Size.Value / megabyte) + " MB"); - else - r.AppendLine((Bios.Size.Value / 1024) + " KB"); - } - - r.AppendLine(); - } - - if (System != null) - { - r.Append("System Manufacturer: "); - r.AppendLine(System.ManufacturerName); - r.Append("System Name: "); - r.AppendLine(System.ProductName); - r.Append("System Version: "); - r.AppendLine(System.Version); - r.Append("System Wakeup: "); - r.AppendLine(System.WakeUp.ToString()); - r.AppendLine(); - } - - if (Board != null) - { - r.Append("Motherboard Manufacturer: "); - r.AppendLine(Board.ManufacturerName); - r.Append("Motherboard Name: "); - r.AppendLine(Board.ProductName); - r.Append("Motherboard Version: "); - r.AppendLine(Board.Version); - r.Append("Motherboard Serial: "); - r.AppendLine(Board.SerialNumber); - r.AppendLine(); - } - - if (SystemEnclosure != null) - { - r.Append("System Enclosure Type: "); - r.AppendLine(SystemEnclosure.Type.ToString()); - r.Append("System Enclosure Manufacturer: "); - r.AppendLine(SystemEnclosure.ManufacturerName); - r.Append("System Enclosure Version: "); - r.AppendLine(SystemEnclosure.Version); - r.Append("System Enclosure Serial: "); - r.AppendLine(SystemEnclosure.SerialNumber); - r.Append("System Enclosure Asset Tag: "); - r.AppendLine(SystemEnclosure.AssetTag); - if (!string.IsNullOrEmpty(SystemEnclosure.SKU)) - { - r.Append("System Enclosure SKU: "); - r.AppendLine(SystemEnclosure.SKU); - } - - r.Append("System Enclosure Boot Up State: "); - r.AppendLine(SystemEnclosure.BootUpState.ToString()); - r.Append("System Enclosure Power Supply State: "); - r.AppendLine(SystemEnclosure.PowerSupplyState.ToString()); - r.Append("System Enclosure Thermal State: "); - r.AppendLine(SystemEnclosure.ThermalState.ToString()); - r.Append("System Enclosure Power Cords: "); - r.AppendLine(SystemEnclosure.PowerCords.ToString()); - if (SystemEnclosure.RackHeight > 0) - { - r.Append("System Enclosure Rack Height: "); - r.AppendLine(SystemEnclosure.RackHeight.ToString()); - } - - r.Append("System Enclosure Lock Detected: "); - r.AppendLine(SystemEnclosure.LockDetected ? "Yes" : "No"); - r.Append("System Enclosure Security Status: "); - r.AppendLine(SystemEnclosure.SecurityStatus.ToString()); - r.AppendLine(); - } - - if (Processors != null) - { - foreach (ProcessorInformation processor in Processors) - { - r.Append("Processor Manufacturer: "); - r.AppendLine(processor.ManufacturerName); - r.Append("Processor Type: "); - r.AppendLine(processor.ProcessorType.ToString()); - r.Append("Processor Version: "); - r.AppendLine(processor.Version); - r.Append("Processor Serial: "); - r.AppendLine(processor.Serial); - r.Append("Processor Socket Destignation: "); - r.AppendLine(processor.SocketDesignation); - r.Append("Processor Socket: "); - r.AppendLine(processor.Socket.ToString()); - r.Append("Processor Version: "); - r.AppendLine(processor.Version); - r.Append("Processor Family: "); - r.AppendLine(processor.Family.ToString()); - r.Append("Processor Core Count: "); - r.AppendLine(processor.CoreCount.ToString()); - r.Append("Processor Core Enabled: "); - r.AppendLine(processor.CoreEnabled.ToString()); - r.Append("Processor Thread Count: "); - r.AppendLine(processor.ThreadCount.ToString()); - r.Append("Processor External Clock: "); - r.Append(processor.ExternalClock); - r.AppendLine(" Mhz"); - r.Append("Processor Max Speed: "); - r.Append(processor.MaxSpeed); - r.AppendLine(" Mhz"); - r.Append("Processor Current Speed: "); - r.Append(processor.CurrentSpeed); - r.AppendLine(" Mhz"); - r.AppendLine(); - } - } - - for (int i = 0; i < ProcessorCaches.Length; i++) - { - r.Append("Cache [" + ProcessorCaches[i].Designation + "] Size: "); - r.AppendLine(ProcessorCaches[i].Size.ToString()); - r.Append("Cache [" + ProcessorCaches[i].Designation + "] Associativity: "); - r.AppendLine(ProcessorCaches[i].Associativity.ToString().Replace("_", string.Empty)); - r.AppendLine(); - } - - for (int i = 0; i < MemoryDevices.Length; i++) - { - r.Append("Memory Device [" + i + "] Manufacturer: "); - r.AppendLine(MemoryDevices[i].ManufacturerName); - r.Append("Memory Device [" + i + "] Part Number: "); - r.AppendLine(MemoryDevices[i].PartNumber); - r.Append("Memory Device [" + i + "] Device Locator: "); - r.AppendLine(MemoryDevices[i].DeviceLocator); - r.Append("Memory Device [" + i + "] Bank Locator: "); - r.AppendLine(MemoryDevices[i].BankLocator); - r.Append("Memory Device [" + i + "] Speed: "); - r.AppendLine(MemoryDevices[i].Speed.ToString()); - r.Append("Memory Device [" + i + "] Size: "); - r.Append(MemoryDevices[i].Size.ToString()); - r.AppendLine(" MB"); - r.AppendLine(); - } - - if (_raw != null) - { - string base64 = Convert.ToBase64String(_raw); - r.AppendLine("SMBios Table"); - r.AppendLine(); - - for (int i = 0; i < Math.Ceiling(base64.Length / 64.0); i++) - { - r.Append(" "); - for (int j = 0; j < 0x40; j++) - { - int index = (i << 6) | j; - if (index < base64.Length) - { - r.Append(base64[index]); - } - } - - r.AppendLine(); - } - - r.AppendLine(); - } - - return r.ToString(); - } + return r.ToString(); } } diff --git a/LibreHardwareMonitorLib/Hardware/Sensor.cs b/LibreHardwareMonitorLib/Hardware/Sensor.cs index 8b8ebbd..0267854 100644 --- a/LibreHardwareMonitorLib/Hardware/Sensor.cs +++ b/LibreHardwareMonitorLib/Hardware/Sensor.cs @@ -10,263 +10,262 @@ using System.Globalization; using System.IO; using System.IO.Compression; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal class Sensor : ISensor { - internal class Sensor : ISensor + private readonly string _defaultName; + private readonly Hardware _hardware; + private readonly ISettings _settings; + private readonly bool _trackMinMax; + private readonly List _values = new(); + private int _count; + private float? _currentValue; + private string _name; + private float _sum; + private TimeSpan _valuesTimeWindow = TimeSpan.FromDays(1.0); + + public Sensor(string name, int index, SensorType sensorType, Hardware hardware, ISettings settings) : + this(name, index, sensorType, hardware, null, settings) + { } + + public Sensor(string name, int index, SensorType sensorType, Hardware hardware, ParameterDescription[] parameterDescriptions, ISettings settings) : + this(name, index, false, sensorType, hardware, parameterDescriptions, settings) + { } + + public Sensor + ( + string name, + int index, + bool defaultHidden, + SensorType sensorType, + Hardware hardware, + ParameterDescription[] parameterDescriptions, + ISettings settings, + bool disableHistory = false) { - private readonly string _defaultName; - private readonly Hardware _hardware; - private readonly ISettings _settings; - private readonly bool _trackMinMax; - private readonly List _values = new(); - private int _count; - private float? _currentValue; - private string _name; - private float _sum; - private TimeSpan _valuesTimeWindow = TimeSpan.FromDays(1.0); + Index = index; + IsDefaultHidden = defaultHidden; + SensorType = sensorType; + _hardware = hardware; - public Sensor(string name, int index, SensorType sensorType, Hardware hardware, ISettings settings) : - this(name, index, sensorType, hardware, null, settings) - { } - - public Sensor(string name, int index, SensorType sensorType, Hardware hardware, ParameterDescription[] parameterDescriptions, ISettings settings) : - this(name, index, false, sensorType, hardware, parameterDescriptions, settings) - { } - - public Sensor - ( - string name, - int index, - bool defaultHidden, - SensorType sensorType, - Hardware hardware, - ParameterDescription[] parameterDescriptions, - ISettings settings, - bool disableHistory = false) + Parameter[] parameters = new Parameter[parameterDescriptions?.Length ?? 0]; + for (int i = 0; i < parameters.Length; i++) { - Index = index; - IsDefaultHidden = defaultHidden; - SensorType = sensorType; - _hardware = hardware; - - Parameter[] parameters = new Parameter[parameterDescriptions?.Length ?? 0]; - for (int i = 0; i < parameters.Length; i++) - { - if (parameterDescriptions != null) - parameters[i] = new Parameter(parameterDescriptions[i], this, settings); - } - - Parameters = parameters; - - _settings = settings; - _defaultName = name; - _name = settings.GetValue(new Identifier(Identifier, "name").ToString(), name); - _trackMinMax = !disableHistory; - if (disableHistory) - { - _valuesTimeWindow = TimeSpan.Zero; - } - - GetSensorValuesFromSettings(); - - hardware.Closing += delegate { SetSensorValuesToSettings(); }; + if (parameterDescriptions != null) + parameters[i] = new Parameter(parameterDescriptions[i], this, settings); } - public IControl Control { get; internal set; } + Parameters = parameters; - public IHardware Hardware + _settings = settings; + _defaultName = name; + _name = settings.GetValue(new Identifier(Identifier, "name").ToString(), name); + _trackMinMax = !disableHistory; + if (disableHistory) { - get { return _hardware; } + _valuesTimeWindow = TimeSpan.Zero; } - public Identifier Identifier + GetSensorValuesFromSettings(); + + hardware.Closing += delegate { SetSensorValuesToSettings(); }; + } + + public IControl Control { get; internal set; } + + public IHardware Hardware + { + get { return _hardware; } + } + + public Identifier Identifier + { + get { return new Identifier(_hardware.Identifier, SensorType.ToString().ToLowerInvariant(), Index.ToString(CultureInfo.InvariantCulture)); } + } + + public int Index { get; } + + public bool IsDefaultHidden { get; } + + public float? Max { get; private set; } + + public float? Min { get; private set; } + + public string Name + { + get { return _name; } + set { - get { return new Identifier(_hardware.Identifier, SensorType.ToString().ToLowerInvariant(), Index.ToString(CultureInfo.InvariantCulture)); } - } + _name = !string.IsNullOrEmpty(value) ? value : _defaultName; - public int Index { get; } - - public bool IsDefaultHidden { get; } - - public float? Max { get; private set; } - - public float? Min { get; private set; } - - public string Name - { - get { return _name; } - set - { - _name = !string.IsNullOrEmpty(value) ? value : _defaultName; - - _settings.SetValue(new Identifier(Identifier, "name").ToString(), _name); - } - } - - public IReadOnlyList Parameters { get; } - - public SensorType SensorType { get; } - - public virtual float? Value - { - get { return _currentValue; } - set - { - if (_valuesTimeWindow != TimeSpan.Zero) - { - DateTime now = DateTime.UtcNow; - while (_values.Count > 0 && now - _values[0].Time > _valuesTimeWindow) - _values.RemoveAt(0); - - if (value.HasValue) - { - _sum += value.Value; - _count++; - if (_count == 4) - { - AppendValue(_sum / _count, now); - _sum = 0; - _count = 0; - } - } - } - - _currentValue = value; - if (_trackMinMax) - { - if (!Min.HasValue || Min > value) - Min = value; - - if (!Max.HasValue || Max < value) - Max = value; - } - } - } - - public IEnumerable Values - { - get { return _values; } - } - - public TimeSpan ValuesTimeWindow - { - get { return _valuesTimeWindow; } - set - { - _valuesTimeWindow = value; - if (value == TimeSpan.Zero) - _values.Clear(); - } - } - - public void ResetMin() - { - Min = null; - } - - public void ResetMax() - { - Max = null; - } - - public void Accept(IVisitor visitor) - { - if (visitor == null) - throw new ArgumentNullException(nameof(visitor)); - - visitor.VisitSensor(this); - } - - public void Traverse(IVisitor visitor) - { - foreach (IParameter parameter in Parameters) - parameter.Accept(visitor); - } - - private void SetSensorValuesToSettings() - { - using MemoryStream memoryStream = new(); - using GZipStream gZipStream = new(memoryStream, CompressionMode.Compress); - using BufferedStream outputStream = new(gZipStream, 65536); - using (BinaryWriter binaryWriter = new(outputStream)) - { - long t = 0; - - foreach (SensorValue sensorValue in _values) - { - long v = sensorValue.Time.ToBinary(); - binaryWriter.Write(v - t); - t = v; - binaryWriter.Write(sensorValue.Value); - } - - binaryWriter.Flush(); - } - - _settings.SetValue(new Identifier(Identifier, "values").ToString(), Convert.ToBase64String(memoryStream.ToArray())); - } - - private void GetSensorValuesFromSettings() - { - string name = new Identifier(Identifier, "values").ToString(); - string s = _settings.GetValue(name, null); - - if (!string.IsNullOrEmpty(s)) - { - try - { - byte[] array = Convert.FromBase64String(s); - DateTime now = DateTime.UtcNow; - - using MemoryStream memoryStream = new(array); - using GZipStream gZipStream = new(memoryStream, CompressionMode.Decompress); - using MemoryStream destination = new(); - - gZipStream.CopyTo(destination); - destination.Seek(0, SeekOrigin.Begin); - - using BinaryReader reader = new(destination); - try - { - long t = 0; - long readLen = reader.BaseStream.Length - reader.BaseStream.Position; - while (readLen > 0) - { - t += reader.ReadInt64(); - DateTime time = DateTime.FromBinary(t); - if (time > now) - break; - - float value = reader.ReadSingle(); - AppendValue(value, time); - readLen = reader.BaseStream.Length - reader.BaseStream.Position; - } - } - catch (EndOfStreamException) - { } - } - catch - { - // Ignored. - } - } - - if (_values.Count > 0) - AppendValue(float.NaN, DateTime.UtcNow); - - //remove the value string from the settings to reduce memory usage - _settings.Remove(name); - } - - private void AppendValue(float value, DateTime time) - { - if (_values.Count >= 2 && _values[_values.Count - 1].Value == value && _values[_values.Count - 2].Value == value) - { - _values[_values.Count - 1] = new SensorValue(value, time); - return; - } - - _values.Add(new SensorValue(value, time)); + _settings.SetValue(new Identifier(Identifier, "name").ToString(), _name); } } -} + + public IReadOnlyList Parameters { get; } + + public SensorType SensorType { get; } + + public virtual float? Value + { + get { return _currentValue; } + set + { + if (_valuesTimeWindow != TimeSpan.Zero) + { + DateTime now = DateTime.UtcNow; + while (_values.Count > 0 && now - _values[0].Time > _valuesTimeWindow) + _values.RemoveAt(0); + + if (value.HasValue) + { + _sum += value.Value; + _count++; + if (_count == 4) + { + AppendValue(_sum / _count, now); + _sum = 0; + _count = 0; + } + } + } + + _currentValue = value; + if (_trackMinMax) + { + if (!Min.HasValue || Min > value) + Min = value; + + if (!Max.HasValue || Max < value) + Max = value; + } + } + } + + public IEnumerable Values + { + get { return _values; } + } + + public TimeSpan ValuesTimeWindow + { + get { return _valuesTimeWindow; } + set + { + _valuesTimeWindow = value; + if (value == TimeSpan.Zero) + _values.Clear(); + } + } + + public void ResetMin() + { + Min = null; + } + + public void ResetMax() + { + Max = null; + } + + public void Accept(IVisitor visitor) + { + if (visitor == null) + throw new ArgumentNullException(nameof(visitor)); + + visitor.VisitSensor(this); + } + + public void Traverse(IVisitor visitor) + { + foreach (IParameter parameter in Parameters) + parameter.Accept(visitor); + } + + private void SetSensorValuesToSettings() + { + using MemoryStream memoryStream = new(); + using GZipStream gZipStream = new(memoryStream, CompressionMode.Compress); + using BufferedStream outputStream = new(gZipStream, 65536); + using (BinaryWriter binaryWriter = new(outputStream)) + { + long t = 0; + + foreach (SensorValue sensorValue in _values) + { + long v = sensorValue.Time.ToBinary(); + binaryWriter.Write(v - t); + t = v; + binaryWriter.Write(sensorValue.Value); + } + + binaryWriter.Flush(); + } + + _settings.SetValue(new Identifier(Identifier, "values").ToString(), Convert.ToBase64String(memoryStream.ToArray())); + } + + private void GetSensorValuesFromSettings() + { + string name = new Identifier(Identifier, "values").ToString(); + string s = _settings.GetValue(name, null); + + if (!string.IsNullOrEmpty(s)) + { + try + { + byte[] array = Convert.FromBase64String(s); + DateTime now = DateTime.UtcNow; + + using MemoryStream memoryStream = new(array); + using GZipStream gZipStream = new(memoryStream, CompressionMode.Decompress); + using MemoryStream destination = new(); + + gZipStream.CopyTo(destination); + destination.Seek(0, SeekOrigin.Begin); + + using BinaryReader reader = new(destination); + try + { + long t = 0; + long readLen = reader.BaseStream.Length - reader.BaseStream.Position; + while (readLen > 0) + { + t += reader.ReadInt64(); + DateTime time = DateTime.FromBinary(t); + if (time > now) + break; + + float value = reader.ReadSingle(); + AppendValue(value, time); + readLen = reader.BaseStream.Length - reader.BaseStream.Position; + } + } + catch (EndOfStreamException) + { } + } + catch + { + // Ignored. + } + } + + if (_values.Count > 0) + AppendValue(float.NaN, DateTime.UtcNow); + + //remove the value string from the settings to reduce memory usage + _settings.Remove(name); + } + + private void AppendValue(float value, DateTime time) + { + if (_values.Count >= 2 && _values[_values.Count - 1].Value == value && _values[_values.Count - 2].Value == value) + { + _values[_values.Count - 1] = new SensorValue(value, time); + return; + } + + _values.Add(new SensorValue(value, time)); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/SensorVisitor.cs b/LibreHardwareMonitorLib/Hardware/SensorVisitor.cs index 4e4e9ed..d2f26b8 100644 --- a/LibreHardwareMonitorLib/Hardware/SensorVisitor.cs +++ b/LibreHardwareMonitorLib/Hardware/SensorVisitor.cs @@ -6,65 +6,64 @@ using System; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +/// +/// Observer making calls to selected component 's. +/// +public class SensorVisitor : IVisitor { + private readonly SensorEventHandler _handler; + /// - /// Observer making calls to selected component 's. + /// Creates a new observer instance. /// - public class SensorVisitor : IVisitor + /// Instance of the that triggers events during visiting the . + public SensorVisitor(SensorEventHandler handler) { - private readonly SensorEventHandler _handler; - - /// - /// Creates a new observer instance. - /// - /// Instance of the that triggers events during visiting the . - public SensorVisitor(SensorEventHandler handler) - { - _handler = handler ?? throw new ArgumentNullException(nameof(handler)); - } - - /// - /// Goes through all the components of the specified with its . - /// - /// Computer class instance that is derived from the interface. - public void VisitComputer(IComputer computer) - { - if (computer == null) - throw new ArgumentNullException(nameof(computer)); - - computer.Traverse(this); - } - - /// - /// Goes through all the components of the specified with its . - /// - /// Hardware class instance that is derived from the interface. - public void VisitHardware(IHardware hardware) - { - if (hardware == null) - throw new ArgumentNullException(nameof(hardware)); - - hardware.Traverse(this); - } - - /// - /// Goes through all the components of the specified using . - /// - /// Sensor class instance that is derived from the interface. - public void VisitSensor(ISensor sensor) - { - _handler(sensor); - } - - /// - /// Goes through all the components of the specified . - /// - /// - /// - /// - /// Parameter class instance that is derived from the interface. - public void VisitParameter(IParameter parameter) - { } + _handler = handler ?? throw new ArgumentNullException(nameof(handler)); } -} + + /// + /// Goes through all the components of the specified with its . + /// + /// Computer class instance that is derived from the interface. + public void VisitComputer(IComputer computer) + { + if (computer == null) + throw new ArgumentNullException(nameof(computer)); + + computer.Traverse(this); + } + + /// + /// Goes through all the components of the specified with its . + /// + /// Hardware class instance that is derived from the interface. + public void VisitHardware(IHardware hardware) + { + if (hardware == null) + throw new ArgumentNullException(nameof(hardware)); + + hardware.Traverse(this); + } + + /// + /// Goes through all the components of the specified using . + /// + /// Sensor class instance that is derived from the interface. + public void VisitSensor(ISensor sensor) + { + _handler(sensor); + } + + /// + /// Goes through all the components of the specified . + /// + /// + /// + /// + /// Parameter class instance that is derived from the interface. + public void VisitParameter(IParameter parameter) + { } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs index 5692404..2d6c08f 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/ATAStorage.cs @@ -13,281 +13,280 @@ using System.Reflection; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public abstract class AtaStorage : AbstractStorage { - public abstract class AtaStorage : AbstractStorage + // array of all hard drive types, matching type is searched in this order + private static readonly Type[] _hddTypes = { typeof(SsdPlextor), typeof(SsdIntel), typeof(SsdSandforce), typeof(SsdIndilinx), typeof(SsdSamsung), typeof(SsdMicron), typeof(GenericHardDisk) }; + + private IDictionary _sensors; + + /// + /// Gets the SMART data. + /// + public ISmart Smart { get; } + + /// + /// Gets the SMART attributes. + /// + public IReadOnlyList SmartAttributes { get; } + + internal AtaStorage(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, string id, int index, IReadOnlyList smartAttributes, ISettings settings) + : base(storageInfo, name, firmwareRevision, id, index, settings) { - // array of all hard drive types, matching type is searched in this order - private static readonly Type[] _hddTypes = { typeof(SsdPlextor), typeof(SsdIntel), typeof(SsdSandforce), typeof(SsdIndilinx), typeof(SsdSamsung), typeof(SsdMicron), typeof(GenericHardDisk) }; - - private IDictionary _sensors; - - /// - /// Gets the SMART data. - /// - public ISmart Smart { get; } - - /// - /// Gets the SMART attributes. - /// - public IReadOnlyList SmartAttributes { get; } - - internal AtaStorage(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, string id, int index, IReadOnlyList smartAttributes, ISettings settings) - : base(storageInfo, name, firmwareRevision, id, index, settings) - { - Smart = smart; - if (smart.IsValid) - smart.EnableSmart(); + Smart = smart; + if (smart.IsValid) + smart.EnableSmart(); - SmartAttributes = smartAttributes; - CreateSensors(); - } + SmartAttributes = smartAttributes; + CreateSensors(); + } - internal static AbstractStorage CreateInstance(StorageInfo storageInfo, ISettings settings) + internal static AbstractStorage CreateInstance(StorageInfo storageInfo, ISettings settings) + { + ISmart smart = new WindowsSmart(storageInfo.Index); + string name = null; + string firmwareRevision = null; + Kernel32.SMART_ATTRIBUTE[] smartAttributes = { }; + + if (smart.IsValid) { - ISmart smart = new WindowsSmart(storageInfo.Index); - string name = null; - string firmwareRevision = null; - Kernel32.SMART_ATTRIBUTE[] smartAttributes = { }; + bool nameValid = smart.ReadNameAndFirmwareRevision(out name, out firmwareRevision); + bool smartEnabled = smart.EnableSmart(); - if (smart.IsValid) - { - bool nameValid = smart.ReadNameAndFirmwareRevision(out name, out firmwareRevision); - bool smartEnabled = smart.EnableSmart(); - - if (smartEnabled) - smartAttributes = smart.ReadSmartData(); + if (smartEnabled) + smartAttributes = smart.ReadSmartData(); - if (!nameValid) - { - name = null; - firmwareRevision = null; - } - } - else + if (!nameValid) { - string[] logicalDrives = WindowsStorage.GetLogicalDrives(storageInfo.Index); - if (logicalDrives == null || logicalDrives.Length == 0) - { - smart.Close(); - return null; - } - - bool hasNonZeroSizeDrive = false; - foreach (string logicalDrive in logicalDrives) - { - try - { - var driveInfo = new DriveInfo(logicalDrive); - if (driveInfo.TotalSize > 0) - { - hasNonZeroSizeDrive = true; - break; - } - } - catch (ArgumentException) { } - catch (IOException) { } - catch (UnauthorizedAccessException) { } - } - - if (!hasNonZeroSizeDrive) - { - smart.Close(); - return null; - } + name = null; + firmwareRevision = null; } - - if (string.IsNullOrEmpty(name)) - name = string.IsNullOrEmpty(storageInfo.Name) ? "Generic Hard Disk" : storageInfo.Name; - - if (string.IsNullOrEmpty(firmwareRevision)) - firmwareRevision = string.IsNullOrEmpty(storageInfo.Revision) ? "Unknown" : storageInfo.Revision; - - foreach (Type type in _hddTypes) + } + else + { + string[] logicalDrives = WindowsStorage.GetLogicalDrives(storageInfo.Index); + if (logicalDrives == null || logicalDrives.Length == 0) { - // get the array of the required SMART attributes for the current type - - // check if all required attributes are present - bool allAttributesFound = true; - - if (type.GetCustomAttributes(typeof(RequireSmartAttribute), true) is RequireSmartAttribute[] requiredAttributes) - { - foreach (RequireSmartAttribute requireAttribute in requiredAttributes) - { - bool attributeFound = false; - - foreach (Kernel32.SMART_ATTRIBUTE value in smartAttributes) - { - if (value.Id == requireAttribute.AttributeId) - { - attributeFound = true; - break; - } - } - - if (!attributeFound) - { - allAttributesFound = false; - break; - } - } - } - - // if an attribute is missing, then try the next type - if (!allAttributesFound) - continue; - - // check if there is a matching name prefix for this type - if (type.GetCustomAttributes(typeof(NamePrefixAttribute), true) is NamePrefixAttribute[] namePrefixes) - { - foreach (NamePrefixAttribute prefix in namePrefixes) - { - if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) - { - const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; - - return Activator.CreateInstance(type, flags, null, new object[] { storageInfo, smart, name, firmwareRevision, storageInfo.Index, settings }, null) as AtaStorage; - } - } - } + smart.Close(); + return null; } - // no matching type has been found - smart.Close(); - return null; + bool hasNonZeroSizeDrive = false; + foreach (string logicalDrive in logicalDrives) + { + try + { + var driveInfo = new DriveInfo(logicalDrive); + if (driveInfo.TotalSize > 0) + { + hasNonZeroSizeDrive = true; + break; + } + } + catch (ArgumentException) { } + catch (IOException) { } + catch (UnauthorizedAccessException) { } + } + + if (!hasNonZeroSizeDrive) + { + smart.Close(); + return null; + } } - protected sealed override void CreateSensors() + if (string.IsNullOrEmpty(name)) + name = string.IsNullOrEmpty(storageInfo.Name) ? "Generic Hard Disk" : storageInfo.Name; + + if (string.IsNullOrEmpty(firmwareRevision)) + firmwareRevision = string.IsNullOrEmpty(storageInfo.Revision) ? "Unknown" : storageInfo.Revision; + + foreach (Type type in _hddTypes) { - _sensors = new Dictionary(); + // get the array of the required SMART attributes for the current type - if (Smart.IsValid) + // check if all required attributes are present + bool allAttributesFound = true; + + if (type.GetCustomAttributes(typeof(RequireSmartAttribute), true) is RequireSmartAttribute[] requiredAttributes) { - byte[] smartIds = Smart.ReadSmartData().Select(x => x.Id).ToArray(); - - // unique attributes by SensorType and SensorChannel. - IEnumerable smartAttributes = SmartAttributes - .Where(x => x.SensorType.HasValue && smartIds.Contains(x.Id)) - .GroupBy(x => new { x.SensorType.Value, x.SensorChannel }) - .Select(x => x.First()); - - _sensors = smartAttributes.ToDictionary(attribute => attribute, - attribute => new Sensor(attribute.SensorName, - attribute.SensorChannel, - attribute.DefaultHiddenSensor, - attribute.SensorType.GetValueOrDefault(), - this, - attribute.ParameterDescriptions, - _settings)); - - foreach (KeyValuePair sensor in _sensors) - ActivateSensor(sensor.Value); - } - - base.CreateSensors(); - } - - protected virtual void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) { } - - protected override void UpdateSensors() - { - if (Smart.IsValid) - { - Kernel32.SMART_ATTRIBUTE[] smartAttributes = Smart.ReadSmartData(); - - foreach (KeyValuePair keyValuePair in _sensors) + foreach (RequireSmartAttribute requireAttribute in requiredAttributes) { - SmartAttribute attribute = keyValuePair.Key; + bool attributeFound = false; + foreach (Kernel32.SMART_ATTRIBUTE value in smartAttributes) { - if (value.Id == attribute.Id) + if (value.Id == requireAttribute.AttributeId) { - Sensor sensor = keyValuePair.Value; - sensor.Value = attribute.ConvertValue(value, sensor.Parameters); - } - } - } - - UpdateAdditionalSensors(smartAttributes); - } - } - - protected override void GetReport(StringBuilder r) - { - if (Smart.IsValid) - { - Kernel32.SMART_ATTRIBUTE[] values = Smart.ReadSmartData(); - Kernel32.SMART_THRESHOLD[] thresholds = Smart.ReadSmartThresholds(); - if (values.Length > 0) - { - r.AppendFormat(CultureInfo.InvariantCulture, - " {0}{1}{2}{3}{4}{5}{6}{7}", - "Id".PadRight(3), - "Description".PadRight(35), - "Raw Value".PadRight(13), - "Worst".PadRight(6), - "Value".PadRight(6), - "Threshold".PadRight(6), - "Physical".PadRight(8), - Environment.NewLine); - - foreach (Kernel32.SMART_ATTRIBUTE value in values) - { - if (value.Id == 0x00) + attributeFound = true; break; - - byte? threshold = null; - foreach (Kernel32.SMART_THRESHOLD t in thresholds) - { - if (t.Id == value.Id) - { - threshold = t.Threshold; - } } - - string description = "Unknown"; - float? physical = null; - foreach (SmartAttribute a in SmartAttributes) - { - if (a.Id == value.Id) - { - description = a.Name; - if (a.HasRawValueConversion | a.SensorType.HasValue) - physical = a.ConvertValue(value, null); - else - physical = null; - } - } - - string raw = BitConverter.ToString(value.RawValue); - r.AppendFormat(CultureInfo.InvariantCulture, - " {0}{1}{2}{3}{4}{5}{6}{7}", - value.Id.ToString("X2").PadRight(3), - description.PadRight(35), - raw.Replace("-", string.Empty).PadRight(13), - value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6), - value.CurrentValue.ToString(CultureInfo.InvariantCulture).PadRight(6), - (threshold.HasValue - ? threshold.Value.ToString(CultureInfo.InvariantCulture) - : "-").PadRight(6), - (physical.HasValue ? physical.Value.ToString(CultureInfo.InvariantCulture) : "-").PadRight(8), - Environment.NewLine); } - r.AppendLine(); + if (!attributeFound) + { + allAttributesFound = false; + break; + } + } + } + + // if an attribute is missing, then try the next type + if (!allAttributesFound) + continue; + + // check if there is a matching name prefix for this type + if (type.GetCustomAttributes(typeof(NamePrefixAttribute), true) is NamePrefixAttribute[] namePrefixes) + { + foreach (NamePrefixAttribute prefix in namePrefixes) + { + if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) + { + const BindingFlags flags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; + + return Activator.CreateInstance(type, flags, null, new object[] { storageInfo, smart, name, firmwareRevision, storageInfo.Index, settings }, null) as AtaStorage; + } } } } - protected static float RawToInt(byte[] raw, byte value, IReadOnlyList parameters) + // no matching type has been found + smart.Close(); + return null; + } + + protected sealed override void CreateSensors() + { + _sensors = new Dictionary(); + + if (Smart.IsValid) { - return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]; + byte[] smartIds = Smart.ReadSmartData().Select(x => x.Id).ToArray(); + + // unique attributes by SensorType and SensorChannel. + IEnumerable smartAttributes = SmartAttributes + .Where(x => x.SensorType.HasValue && smartIds.Contains(x.Id)) + .GroupBy(x => new { x.SensorType.Value, x.SensorChannel }) + .Select(x => x.First()); + + _sensors = smartAttributes.ToDictionary(attribute => attribute, + attribute => new Sensor(attribute.SensorName, + attribute.SensorChannel, + attribute.DefaultHiddenSensor, + attribute.SensorType.GetValueOrDefault(), + this, + attribute.ParameterDescriptions, + _settings)); + + foreach (KeyValuePair sensor in _sensors) + ActivateSensor(sensor.Value); } - public override void Close() + base.CreateSensors(); + } + + protected virtual void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) { } + + protected override void UpdateSensors() + { + if (Smart.IsValid) { - Smart.Close(); - base.Close(); + Kernel32.SMART_ATTRIBUTE[] smartAttributes = Smart.ReadSmartData(); + + foreach (KeyValuePair keyValuePair in _sensors) + { + SmartAttribute attribute = keyValuePair.Key; + foreach (Kernel32.SMART_ATTRIBUTE value in smartAttributes) + { + if (value.Id == attribute.Id) + { + Sensor sensor = keyValuePair.Value; + sensor.Value = attribute.ConvertValue(value, sensor.Parameters); + } + } + } + + UpdateAdditionalSensors(smartAttributes); } } -} + + protected override void GetReport(StringBuilder r) + { + if (Smart.IsValid) + { + Kernel32.SMART_ATTRIBUTE[] values = Smart.ReadSmartData(); + Kernel32.SMART_THRESHOLD[] thresholds = Smart.ReadSmartThresholds(); + if (values.Length > 0) + { + r.AppendFormat(CultureInfo.InvariantCulture, + " {0}{1}{2}{3}{4}{5}{6}{7}", + "Id".PadRight(3), + "Description".PadRight(35), + "Raw Value".PadRight(13), + "Worst".PadRight(6), + "Value".PadRight(6), + "Threshold".PadRight(6), + "Physical".PadRight(8), + Environment.NewLine); + + foreach (Kernel32.SMART_ATTRIBUTE value in values) + { + if (value.Id == 0x00) + break; + + byte? threshold = null; + foreach (Kernel32.SMART_THRESHOLD t in thresholds) + { + if (t.Id == value.Id) + { + threshold = t.Threshold; + } + } + + string description = "Unknown"; + float? physical = null; + foreach (SmartAttribute a in SmartAttributes) + { + if (a.Id == value.Id) + { + description = a.Name; + if (a.HasRawValueConversion | a.SensorType.HasValue) + physical = a.ConvertValue(value, null); + else + physical = null; + } + } + + string raw = BitConverter.ToString(value.RawValue); + r.AppendFormat(CultureInfo.InvariantCulture, + " {0}{1}{2}{3}{4}{5}{6}{7}", + value.Id.ToString("X2").PadRight(3), + description.PadRight(35), + raw.Replace("-", string.Empty).PadRight(13), + value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6), + value.CurrentValue.ToString(CultureInfo.InvariantCulture).PadRight(6), + (threshold.HasValue + ? threshold.Value.ToString(CultureInfo.InvariantCulture) + : "-").PadRight(6), + (physical.HasValue ? physical.Value.ToString(CultureInfo.InvariantCulture) : "-").PadRight(8), + Environment.NewLine); + } + + r.AppendLine(); + } + } + } + + protected static float RawToInt(byte[] raw, byte value, IReadOnlyList parameters) + { + return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0]; + } + + public override void Close() + { + Smart.Close(); + base.Close(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs index b2b0219..82a6113 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/AbstractStorage.cs @@ -12,287 +12,286 @@ using System.Management; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public abstract class AbstractStorage : Hardware { - public abstract class AbstractStorage : Hardware + private readonly PerformanceValue _perfTotal = new(); + private readonly PerformanceValue _perfWrite = new(); + private readonly StorageInfo _storageInfo; + private readonly TimeSpan _updateInterval = TimeSpan.FromSeconds(60); + + private ulong _lastReadRateCounter; + private double _lastTime; + private DateTime _lastUpdate = DateTime.MinValue; + private ulong _lastWriteRateCounter; + private Sensor _sensorDiskReadRate; + private Sensor _sensorDiskTotalActivity; + private Sensor _sensorDiskWriteActivity; + private Sensor _sensorDiskWriteRate; + private Sensor _usageSensor; + private int _wmiFailureCount; + + internal AbstractStorage(StorageInfo storageInfo, string name, string firmwareRevision, string id, int index, ISettings settings) + : base(name, new Identifier(id, index.ToString(CultureInfo.InvariantCulture)), settings) { - private readonly PerformanceValue _perfTotal = new(); - private readonly PerformanceValue _perfWrite = new(); - private readonly StorageInfo _storageInfo; - private readonly TimeSpan _updateInterval = TimeSpan.FromSeconds(60); + _storageInfo = storageInfo; + FirmwareRevision = firmwareRevision; + Index = index; - private ulong _lastReadRateCounter; - private double _lastTime; - private DateTime _lastUpdate = DateTime.MinValue; - private ulong _lastWriteRateCounter; - private Sensor _sensorDiskReadRate; - private Sensor _sensorDiskTotalActivity; - private Sensor _sensorDiskWriteActivity; - private Sensor _sensorDiskWriteRate; - private Sensor _usageSensor; - private int _wmiFailureCount; + string[] logicalDrives = WindowsStorage.GetLogicalDrives(index); + var driveInfoList = new List(logicalDrives.Length); - internal AbstractStorage(StorageInfo storageInfo, string name, string firmwareRevision, string id, int index, ISettings settings) - : base(name, new Identifier(id, index.ToString(CultureInfo.InvariantCulture)), settings) + foreach (string logicalDrive in logicalDrives) { - _storageInfo = storageInfo; - FirmwareRevision = firmwareRevision; - Index = index; - - string[] logicalDrives = WindowsStorage.GetLogicalDrives(index); - var driveInfoList = new List(logicalDrives.Length); - - foreach (string logicalDrive in logicalDrives) + try { - try + var di = new DriveInfo(logicalDrive); + if (di.TotalSize > 0) + driveInfoList.Add(new DriveInfo(logicalDrive)); + } + catch (ArgumentException) + { } + catch (IOException) + { } + catch (UnauthorizedAccessException) + { } + } + + DriveInfos = driveInfoList.ToArray(); + } + + public DriveInfo[] DriveInfos { get; } + + public string FirmwareRevision { get; } + + public override HardwareType HardwareType => HardwareType.Storage; + + public int Index { get; } + + public static AbstractStorage CreateInstance(string deviceId, uint driveNumber, ulong diskSize, int scsiPort, ISettings settings) + { + StorageInfo info = WindowsStorage.GetStorageInfo(deviceId, driveNumber); + if (info == null) + return null; + + info.DiskSize = diskSize; + info.DeviceId = deviceId; + info.Scsi = $@"\\.\SCSI{scsiPort}:"; + + if (info.Removable || info.BusType is Kernel32.STORAGE_BUS_TYPE.BusTypeVirtual or Kernel32.STORAGE_BUS_TYPE.BusTypeFileBackedVirtual) + return null; + + //fallback, when it is not possible to read out with the nvme implementation, + //try it with the sata smart implementation + if (info.BusType == Kernel32.STORAGE_BUS_TYPE.BusTypeNvme) + { + AbstractStorage x = NVMeGeneric.CreateInstance(info, settings); + if (x != null) + return x; + } + + return info.BusType is Kernel32.STORAGE_BUS_TYPE.BusTypeAta or Kernel32.STORAGE_BUS_TYPE.BusTypeSata or Kernel32.STORAGE_BUS_TYPE.BusTypeNvme + ? AtaStorage.CreateInstance(info, settings) + : StorageGeneric.CreateInstance(info, settings); + } + + protected virtual void CreateSensors() + { + if (DriveInfos.Length > 0) + { + _usageSensor = new Sensor("Used Space", 0, SensorType.Load, this, _settings); + ActivateSensor(_usageSensor); + } + + _sensorDiskWriteActivity = new Sensor("Write Activity", 32, SensorType.Load, this, _settings); + ActivateSensor(_sensorDiskWriteActivity); + + _sensorDiskTotalActivity = new Sensor("Total Activity", 33, SensorType.Load, this, _settings); + ActivateSensor(_sensorDiskTotalActivity); + + _sensorDiskReadRate = new Sensor("Read Rate", 34, SensorType.Throughput, this, _settings); + ActivateSensor(_sensorDiskReadRate); + + _sensorDiskWriteRate = new Sensor("Write Rate", 35, SensorType.Throughput, this, _settings); + ActivateSensor(_sensorDiskWriteRate); + } + + protected abstract void UpdateSensors(); + + private void UpdateStatisticsFromWmi(int driveIndex) + { + string query = $"SELECT * FROM Win32_PerfRawData_PerfDisk_PhysicalDisk Where Name LIKE \"{driveIndex}%\""; + + using var perfData = new ManagementObjectSearcher(query) { Options = { Timeout = TimeSpan.FromSeconds(7.5) } }; + using ManagementObjectCollection collection = perfData.Get(); + using ManagementObject data = collection.OfType().FirstOrDefault(); + + if (data == null) + return; + + ulong value = (ulong)data.Properties["PercentDiskWriteTime"].Value; + ulong valueBase = (ulong)data.Properties["PercentDiskWriteTime_Base"].Value; + _perfWrite.Update(value, valueBase); + _sensorDiskWriteActivity.Value = (float)_perfWrite.Result; + + value = (ulong)data.Properties["PercentIdleTime"].Value; + valueBase = (ulong)data.Properties["PercentIdleTime_Base"].Value; + _perfTotal.Update(value, valueBase); + _sensorDiskTotalActivity.Value = (float)(100.0 - _perfTotal.Result); + + ulong readRateCounter = (ulong)data.Properties["DiskReadBytesPerSec"].Value; + ulong readRate = readRateCounter - _lastReadRateCounter; + _lastReadRateCounter = readRateCounter; + + ulong writeRateCounter = (ulong)data.Properties["DiskWriteBytesPerSec"].Value; + ulong writeRate = writeRateCounter - _lastWriteRateCounter; + _lastWriteRateCounter = writeRateCounter; + + ulong timestampPerfTime = (ulong)data.Properties["Timestamp_PerfTime"].Value; + ulong frequencyPerfTime = (ulong)data.Properties["Frequency_Perftime"].Value; + double currentTime = (double)timestampPerfTime / frequencyPerfTime; + + double timeDeltaSeconds = currentTime - _lastTime; + if (_lastTime == 0 || timeDeltaSeconds > 0.2) + { + double writeSpeed = writeRate * (1 / timeDeltaSeconds); + _sensorDiskWriteRate.Value = (float)writeSpeed; + + double readSpeed = readRate * (1 / timeDeltaSeconds); + _sensorDiskReadRate.Value = (float)readSpeed; + } + + if (_lastTime == 0 || timeDeltaSeconds > 0.2) + _lastTime = currentTime; + } + + public override void Update() + { + const int wmiRetries = 10; + + //update statistics from WMI on every update + if (_storageInfo != null && _wmiFailureCount <= wmiRetries) + { + try + { + UpdateStatisticsFromWmi(_storageInfo.Index); + _wmiFailureCount = 0; + } + catch + { + if (++_wmiFailureCount == wmiRetries) { - var di = new DriveInfo(logicalDrive); - if (di.TotalSize > 0) - driveInfoList.Add(new DriveInfo(logicalDrive)); + DeactivateSensor(_sensorDiskTotalActivity); + DeactivateSensor(_sensorDiskWriteActivity); + DeactivateSensor(_sensorDiskReadRate); + DeactivateSensor(_sensorDiskWriteRate); } - catch (ArgumentException) - { } - catch (IOException) - { } - catch (UnauthorizedAccessException) - { } } - - DriveInfos = driveInfoList.ToArray(); } - public DriveInfo[] DriveInfos { get; } - - public string FirmwareRevision { get; } - - public override HardwareType HardwareType => HardwareType.Storage; - - public int Index { get; } - - public static AbstractStorage CreateInstance(string deviceId, uint driveNumber, ulong diskSize, int scsiPort, ISettings settings) + //read out with updateInterval + TimeSpan tDiff = DateTime.UtcNow - _lastUpdate; + if (tDiff > _updateInterval) { - StorageInfo info = WindowsStorage.GetStorageInfo(deviceId, driveNumber); - if (info == null) - return null; + _lastUpdate = DateTime.UtcNow; - info.DiskSize = diskSize; - info.DeviceId = deviceId; - info.Scsi = $@"\\.\SCSI{scsiPort}:"; + UpdateSensors(); - if (info.Removable || info.BusType is Kernel32.STORAGE_BUS_TYPE.BusTypeVirtual or Kernel32.STORAGE_BUS_TYPE.BusTypeFileBackedVirtual) - return null; - - //fallback, when it is not possible to read out with the nvme implementation, - //try it with the sata smart implementation - if (info.BusType == Kernel32.STORAGE_BUS_TYPE.BusTypeNvme) + if (_usageSensor != null) { - AbstractStorage x = NVMeGeneric.CreateInstance(info, settings); - if (x != null) - return x; - } + long totalSize = 0; + long totalFreeSpace = 0; - return info.BusType is Kernel32.STORAGE_BUS_TYPE.BusTypeAta or Kernel32.STORAGE_BUS_TYPE.BusTypeSata or Kernel32.STORAGE_BUS_TYPE.BusTypeNvme - ? AtaStorage.CreateInstance(info, settings) - : StorageGeneric.CreateInstance(info, settings); - } - - protected virtual void CreateSensors() - { - if (DriveInfos.Length > 0) - { - _usageSensor = new Sensor("Used Space", 0, SensorType.Load, this, _settings); - ActivateSensor(_usageSensor); - } - - _sensorDiskWriteActivity = new Sensor("Write Activity", 32, SensorType.Load, this, _settings); - ActivateSensor(_sensorDiskWriteActivity); - - _sensorDiskTotalActivity = new Sensor("Total Activity", 33, SensorType.Load, this, _settings); - ActivateSensor(_sensorDiskTotalActivity); - - _sensorDiskReadRate = new Sensor("Read Rate", 34, SensorType.Throughput, this, _settings); - ActivateSensor(_sensorDiskReadRate); - - _sensorDiskWriteRate = new Sensor("Write Rate", 35, SensorType.Throughput, this, _settings); - ActivateSensor(_sensorDiskWriteRate); - } - - protected abstract void UpdateSensors(); - - private void UpdateStatisticsFromWmi(int driveIndex) - { - string query = $"SELECT * FROM Win32_PerfRawData_PerfDisk_PhysicalDisk Where Name LIKE \"{driveIndex}%\""; - - using var perfData = new ManagementObjectSearcher(query) { Options = { Timeout = TimeSpan.FromSeconds(7.5) } }; - using ManagementObjectCollection collection = perfData.Get(); - using ManagementObject data = collection.OfType().FirstOrDefault(); - - if (data == null) - return; - - ulong value = (ulong)data.Properties["PercentDiskWriteTime"].Value; - ulong valueBase = (ulong)data.Properties["PercentDiskWriteTime_Base"].Value; - _perfWrite.Update(value, valueBase); - _sensorDiskWriteActivity.Value = (float)_perfWrite.Result; - - value = (ulong)data.Properties["PercentIdleTime"].Value; - valueBase = (ulong)data.Properties["PercentIdleTime_Base"].Value; - _perfTotal.Update(value, valueBase); - _sensorDiskTotalActivity.Value = (float)(100.0 - _perfTotal.Result); - - ulong readRateCounter = (ulong)data.Properties["DiskReadBytesPerSec"].Value; - ulong readRate = readRateCounter - _lastReadRateCounter; - _lastReadRateCounter = readRateCounter; - - ulong writeRateCounter = (ulong)data.Properties["DiskWriteBytesPerSec"].Value; - ulong writeRate = writeRateCounter - _lastWriteRateCounter; - _lastWriteRateCounter = writeRateCounter; - - ulong timestampPerfTime = (ulong)data.Properties["Timestamp_PerfTime"].Value; - ulong frequencyPerfTime = (ulong)data.Properties["Frequency_Perftime"].Value; - double currentTime = (double)timestampPerfTime / frequencyPerfTime; - - double timeDeltaSeconds = currentTime - _lastTime; - if (_lastTime == 0 || timeDeltaSeconds > 0.2) - { - double writeSpeed = writeRate * (1 / timeDeltaSeconds); - _sensorDiskWriteRate.Value = (float)writeSpeed; - - double readSpeed = readRate * (1 / timeDeltaSeconds); - _sensorDiskReadRate.Value = (float)readSpeed; - } - - if (_lastTime == 0 || timeDeltaSeconds > 0.2) - _lastTime = currentTime; - } - - public override void Update() - { - const int wmiRetries = 10; - - //update statistics from WMI on every update - if (_storageInfo != null && _wmiFailureCount <= wmiRetries) - { - try + for (int i = 0; i < DriveInfos.Length; i++) { - UpdateStatisticsFromWmi(_storageInfo.Index); - _wmiFailureCount = 0; - } - catch - { - if (++_wmiFailureCount == wmiRetries) + if (!DriveInfos[i].IsReady) + continue; + + try { - DeactivateSensor(_sensorDiskTotalActivity); - DeactivateSensor(_sensorDiskWriteActivity); - DeactivateSensor(_sensorDiskReadRate); - DeactivateSensor(_sensorDiskWriteRate); + totalSize += DriveInfos[i].TotalSize; + totalFreeSpace += DriveInfos[i].TotalFreeSpace; } + catch (IOException) + { } + catch (UnauthorizedAccessException) + { } } - } - //read out with updateInterval - TimeSpan tDiff = DateTime.UtcNow - _lastUpdate; - if (tDiff > _updateInterval) - { - _lastUpdate = DateTime.UtcNow; - - UpdateSensors(); - - if (_usageSensor != null) - { - long totalSize = 0; - long totalFreeSpace = 0; - - for (int i = 0; i < DriveInfos.Length; i++) - { - if (!DriveInfos[i].IsReady) - continue; - - try - { - totalSize += DriveInfos[i].TotalSize; - totalFreeSpace += DriveInfos[i].TotalFreeSpace; - } - catch (IOException) - { } - catch (UnauthorizedAccessException) - { } - } - - if (totalSize > 0) - _usageSensor.Value = 100.0f - ((100.0f * totalFreeSpace) / totalSize); - else - _usageSensor.Value = null; - } - } - } - - protected abstract void GetReport(StringBuilder r); - - public override string GetReport() - { - var r = new StringBuilder(); - r.AppendLine("Storage"); - r.AppendLine(); - r.AppendLine("Drive Name: " + _name); - r.AppendLine("Firmware Version: " + FirmwareRevision); - r.AppendLine(); - GetReport(r); - - foreach (DriveInfo di in DriveInfos) - { - if (!di.IsReady) - continue; - - try - { - r.AppendLine("Logical Drive Name: " + di.Name); - r.AppendLine("Format: " + di.DriveFormat); - r.AppendLine("Total Size: " + di.TotalSize); - r.AppendLine("Total Free Space: " + di.TotalFreeSpace); - r.AppendLine(); - } - catch (IOException) - { } - catch (UnauthorizedAccessException) - { } - } - - return r.ToString(); - } - - public override void Traverse(IVisitor visitor) - { - foreach (ISensor sensor in Sensors) - sensor.Accept(visitor); - } - - /// - /// Helper to calculate the disk performance with base timestamps - /// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-perfrawdata - /// - private class PerformanceValue - { - public double Result { get; private set; } - - private ulong Time { get; set; } - - private ulong Value { get; set; } - - public void Update(ulong val, ulong valBase) - { - ulong diffValue = val - Value; - ulong diffTime = valBase - Time; - - Value = val; - Time = valBase; - Result = 100.0 / diffTime * diffValue; - - //sometimes it is possible that diff_value > diff_timebase - //limit result to 100%, this is because timing issues during read from pcie controller an latency between IO operation - if (Result > 100) - Result = 100; + if (totalSize > 0) + _usageSensor.Value = 100.0f - ((100.0f * totalFreeSpace) / totalSize); + else + _usageSensor.Value = null; } } } -} + + protected abstract void GetReport(StringBuilder r); + + public override string GetReport() + { + var r = new StringBuilder(); + r.AppendLine("Storage"); + r.AppendLine(); + r.AppendLine("Drive Name: " + _name); + r.AppendLine("Firmware Version: " + FirmwareRevision); + r.AppendLine(); + GetReport(r); + + foreach (DriveInfo di in DriveInfos) + { + if (!di.IsReady) + continue; + + try + { + r.AppendLine("Logical Drive Name: " + di.Name); + r.AppendLine("Format: " + di.DriveFormat); + r.AppendLine("Total Size: " + di.TotalSize); + r.AppendLine("Total Free Space: " + di.TotalFreeSpace); + r.AppendLine(); + } + catch (IOException) + { } + catch (UnauthorizedAccessException) + { } + } + + return r.ToString(); + } + + public override void Traverse(IVisitor visitor) + { + foreach (ISensor sensor in Sensors) + sensor.Accept(visitor); + } + + /// + /// Helper to calculate the disk performance with base timestamps + /// https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-perfrawdata + /// + private class PerformanceValue + { + public double Result { get; private set; } + + private ulong Time { get; set; } + + private ulong Value { get; set; } + + public void Update(ulong val, ulong valBase) + { + ulong diffValue = val - Value; + ulong diffTime = valBase - Time; + + Value = val; + Time = valBase; + Result = 100.0 / diffTime * diffValue; + + //sometimes it is possible that diff_value > diff_timebase + //limit result to 100%, this is because timing issues during read from pcie controller an latency between IO operation + if (Result > 100) + Result = 100; + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/GenericHardDisk.cs b/LibreHardwareMonitorLib/Hardware/Storage/GenericHardDisk.cs index 0a73e34..96a1b72 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/GenericHardDisk.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/GenericHardDisk.cs @@ -6,84 +6,83 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Storage -{ - [NamePrefix("")] - public class GenericHardDisk : AtaStorage - { - private static readonly List _smartAttributes = new() - { - new SmartAttribute(0x01, SmartNames.ReadErrorRate), - new SmartAttribute(0x02, SmartNames.ThroughputPerformance), - new SmartAttribute(0x03, SmartNames.SpinUpTime), - new SmartAttribute(0x04, SmartNames.StartStopCount, RawToInt), - new SmartAttribute(0x05, SmartNames.ReallocatedSectorsCount), - new SmartAttribute(0x06, SmartNames.ReadChannelMargin), - new SmartAttribute(0x07, SmartNames.SeekErrorRate), - new SmartAttribute(0x08, SmartNames.SeekTimePerformance), - new SmartAttribute(0x09, SmartNames.PowerOnHours, RawToInt), - new SmartAttribute(0x0A, SmartNames.SpinRetryCount), - new SmartAttribute(0x0B, SmartNames.RecalibrationRetries), - new SmartAttribute(0x0C, SmartNames.PowerCycleCount, RawToInt), - new SmartAttribute(0x0D, SmartNames.SoftReadErrorRate), - new SmartAttribute(0xAA, SmartNames.Unknown), - new SmartAttribute(0xAB, SmartNames.Unknown), - new SmartAttribute(0xAC, SmartNames.Unknown), - new SmartAttribute(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), - new SmartAttribute(0xB8, SmartNames.EndToEndError), - new SmartAttribute(0xB9, SmartNames.HeadStability), - new SmartAttribute(0xBA, SmartNames.InducedOpVibrationDetection), - new SmartAttribute(0xBB, SmartNames.ReportedUncorrectableErrors, RawToInt), - new SmartAttribute(0xBC, SmartNames.CommandTimeout, RawToInt), - new SmartAttribute(0xBD, SmartNames.HighFlyWrites), - new SmartAttribute(0xBF, SmartNames.GSenseErrorRate), - new SmartAttribute(0xC0, SmartNames.EmergencyRetractCycleCount), - new SmartAttribute(0xC1, SmartNames.LoadCycleCount), - new SmartAttribute(0xC3, SmartNames.HardwareEccRecovered), - new SmartAttribute(0xC4, SmartNames.ReallocationEventCount), - new SmartAttribute(0xC5, SmartNames.CurrentPendingSectorCount), - new SmartAttribute(0xC6, SmartNames.UncorrectableSectorCount), - new SmartAttribute(0xC7, SmartNames.UltraDmaCrcErrorCount), - new SmartAttribute(0xC8, SmartNames.WriteErrorRate), - new SmartAttribute(0xCA, SmartNames.DataAddressMarkErrors), - new SmartAttribute(0xCB, SmartNames.RunOutCancel), - new SmartAttribute(0xCC, SmartNames.SoftEccCorrection), - new SmartAttribute(0xCD, SmartNames.ThermalAsperityRate), - new SmartAttribute(0xCE, SmartNames.FlyingHeight), - new SmartAttribute(0xCF, SmartNames.SpinHighCurrent), - new SmartAttribute(0xD0, SmartNames.SpinBuzz), - new SmartAttribute(0xD1, SmartNames.OfflineSeekPerformance), - new SmartAttribute(0xD3, SmartNames.VibrationDuringWrite), - new SmartAttribute(0xD4, SmartNames.ShockDuringWrite), - new SmartAttribute(0xDC, SmartNames.DiskShift), - new SmartAttribute(0xDD, SmartNames.AlternativeGSenseErrorRate), - new SmartAttribute(0xDE, SmartNames.LoadedHours), - new SmartAttribute(0xDF, SmartNames.LoadUnloadRetryCount), - new SmartAttribute(0xE0, SmartNames.LoadFriction), - new SmartAttribute(0xE1, SmartNames.LoadUnloadCycleCount), - new SmartAttribute(0xE2, SmartNames.LoadInTime), - new SmartAttribute(0xE3, SmartNames.TorqueAmplificationCount), - new SmartAttribute(0xE4, SmartNames.PowerOffRetractCycle), - new SmartAttribute(0xE6, SmartNames.GmrHeadAmplitude), - new SmartAttribute(0xE8, SmartNames.EnduranceRemaining), - new SmartAttribute(0xE9, SmartNames.PowerOnHours), - new SmartAttribute(0xF0, SmartNames.HeadFlyingHours), - new SmartAttribute(0xF1, SmartNames.TotalLbasWritten), - new SmartAttribute(0xF2, SmartNames.TotalLbasRead), - new SmartAttribute(0xFA, SmartNames.ReadErrorRetryRate), - new SmartAttribute(0xFE, SmartNames.FreeFallProtection), - new SmartAttribute(0xC2, SmartNames.Temperature, (r, _, p) => r[0] + (p?[0].Value ?? 0), - SensorType.Temperature, 0, SmartNames.Temperature, false, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\n" + "Temperature = Value + Offset.", 0) }), - new SmartAttribute(0xE7, SmartNames.Temperature, (r, _, p) => r[0] + (p?[0].Value ?? 0), - SensorType.Temperature, 0, SmartNames.Temperature, false, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\n" + "Temperature = Value + Offset.", 0) }), - new SmartAttribute(0xBE, SmartNames.TemperatureDifferenceFrom100, (r, _, p) => r[0] + (p?[0].Value ?? 0), - SensorType.Temperature, 0, "Temperature", false, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\n" + "Temperature = Value + Offset.", 0) }) - }; +namespace LibreHardwareMonitor.Hardware.Storage; - internal GenericHardDisk(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "hdd", index, _smartAttributes, settings) { } - } +[NamePrefix("")] +public class GenericHardDisk : AtaStorage +{ + private static readonly List _smartAttributes = new() + { + new SmartAttribute(0x01, SmartNames.ReadErrorRate), + new SmartAttribute(0x02, SmartNames.ThroughputPerformance), + new SmartAttribute(0x03, SmartNames.SpinUpTime), + new SmartAttribute(0x04, SmartNames.StartStopCount, RawToInt), + new SmartAttribute(0x05, SmartNames.ReallocatedSectorsCount), + new SmartAttribute(0x06, SmartNames.ReadChannelMargin), + new SmartAttribute(0x07, SmartNames.SeekErrorRate), + new SmartAttribute(0x08, SmartNames.SeekTimePerformance), + new SmartAttribute(0x09, SmartNames.PowerOnHours, RawToInt), + new SmartAttribute(0x0A, SmartNames.SpinRetryCount), + new SmartAttribute(0x0B, SmartNames.RecalibrationRetries), + new SmartAttribute(0x0C, SmartNames.PowerCycleCount, RawToInt), + new SmartAttribute(0x0D, SmartNames.SoftReadErrorRate), + new SmartAttribute(0xAA, SmartNames.Unknown), + new SmartAttribute(0xAB, SmartNames.Unknown), + new SmartAttribute(0xAC, SmartNames.Unknown), + new SmartAttribute(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), + new SmartAttribute(0xB8, SmartNames.EndToEndError), + new SmartAttribute(0xB9, SmartNames.HeadStability), + new SmartAttribute(0xBA, SmartNames.InducedOpVibrationDetection), + new SmartAttribute(0xBB, SmartNames.ReportedUncorrectableErrors, RawToInt), + new SmartAttribute(0xBC, SmartNames.CommandTimeout, RawToInt), + new SmartAttribute(0xBD, SmartNames.HighFlyWrites), + new SmartAttribute(0xBF, SmartNames.GSenseErrorRate), + new SmartAttribute(0xC0, SmartNames.EmergencyRetractCycleCount), + new SmartAttribute(0xC1, SmartNames.LoadCycleCount), + new SmartAttribute(0xC3, SmartNames.HardwareEccRecovered), + new SmartAttribute(0xC4, SmartNames.ReallocationEventCount), + new SmartAttribute(0xC5, SmartNames.CurrentPendingSectorCount), + new SmartAttribute(0xC6, SmartNames.UncorrectableSectorCount), + new SmartAttribute(0xC7, SmartNames.UltraDmaCrcErrorCount), + new SmartAttribute(0xC8, SmartNames.WriteErrorRate), + new SmartAttribute(0xCA, SmartNames.DataAddressMarkErrors), + new SmartAttribute(0xCB, SmartNames.RunOutCancel), + new SmartAttribute(0xCC, SmartNames.SoftEccCorrection), + new SmartAttribute(0xCD, SmartNames.ThermalAsperityRate), + new SmartAttribute(0xCE, SmartNames.FlyingHeight), + new SmartAttribute(0xCF, SmartNames.SpinHighCurrent), + new SmartAttribute(0xD0, SmartNames.SpinBuzz), + new SmartAttribute(0xD1, SmartNames.OfflineSeekPerformance), + new SmartAttribute(0xD3, SmartNames.VibrationDuringWrite), + new SmartAttribute(0xD4, SmartNames.ShockDuringWrite), + new SmartAttribute(0xDC, SmartNames.DiskShift), + new SmartAttribute(0xDD, SmartNames.AlternativeGSenseErrorRate), + new SmartAttribute(0xDE, SmartNames.LoadedHours), + new SmartAttribute(0xDF, SmartNames.LoadUnloadRetryCount), + new SmartAttribute(0xE0, SmartNames.LoadFriction), + new SmartAttribute(0xE1, SmartNames.LoadUnloadCycleCount), + new SmartAttribute(0xE2, SmartNames.LoadInTime), + new SmartAttribute(0xE3, SmartNames.TorqueAmplificationCount), + new SmartAttribute(0xE4, SmartNames.PowerOffRetractCycle), + new SmartAttribute(0xE6, SmartNames.GmrHeadAmplitude), + new SmartAttribute(0xE8, SmartNames.EnduranceRemaining), + new SmartAttribute(0xE9, SmartNames.PowerOnHours), + new SmartAttribute(0xF0, SmartNames.HeadFlyingHours), + new SmartAttribute(0xF1, SmartNames.TotalLbasWritten), + new SmartAttribute(0xF2, SmartNames.TotalLbasRead), + new SmartAttribute(0xFA, SmartNames.ReadErrorRetryRate), + new SmartAttribute(0xFE, SmartNames.FreeFallProtection), + new SmartAttribute(0xC2, SmartNames.Temperature, (r, _, p) => r[0] + (p?[0].Value ?? 0), + SensorType.Temperature, 0, SmartNames.Temperature, false, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\n" + "Temperature = Value + Offset.", 0) }), + new SmartAttribute(0xE7, SmartNames.Temperature, (r, _, p) => r[0] + (p?[0].Value ?? 0), + SensorType.Temperature, 0, SmartNames.Temperature, false, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\n" + "Temperature = Value + Offset.", 0) }), + new SmartAttribute(0xBE, SmartNames.TemperatureDifferenceFrom100, (r, _, p) => r[0] + (p?[0].Value ?? 0), + SensorType.Temperature, 0, "Temperature", false, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\n" + "Temperature = Value + Offset.", 0) }) + }; + + internal GenericHardDisk(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, smart, name, firmwareRevision, "hdd", index, _smartAttributes, settings) { } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/INVMeDrive.cs b/LibreHardwareMonitorLib/Hardware/Storage/INVMeDrive.cs index b6d9b7d..f3e96e7 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/INVMeDrive.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/INVMeDrive.cs @@ -6,14 +6,13 @@ using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal interface INVMeDrive { - internal interface INVMeDrive - { - SafeHandle Identify(StorageInfo storageInfo); + SafeHandle Identify(StorageInfo storageInfo); - bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data); + bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data); - bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data); - } -} + bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs index 8263c03..7d5b778 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/ISmart.cs @@ -7,20 +7,19 @@ using System; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public interface ISmart : IDisposable { - public interface ISmart : IDisposable - { - bool IsValid { get; } + bool IsValid { get; } - void Close(); + void Close(); - bool EnableSmart(); + bool EnableSmart(); - Kernel32.SMART_ATTRIBUTE[] ReadSmartData(); + Kernel32.SMART_ATTRIBUTE[] ReadSmartData(); - Kernel32.SMART_THRESHOLD[] ReadSmartThresholds(); + Kernel32.SMART_THRESHOLD[] ReadSmartThresholds(); - bool ReadNameAndFirmwareRevision(out string name, out string firmwareRevision); - } -} + bool ReadNameAndFirmwareRevision(out string name, out string firmwareRevision); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeGeneric.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeGeneric.cs index 3cb4134..799c1fc 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeGeneric.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeGeneric.cs @@ -7,182 +7,181 @@ using System.Collections.Generic; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public sealed class NVMeGeneric : AbstractStorage { - public sealed class NVMeGeneric : AbstractStorage + private const ulong Scale = 1000000; + private const ulong Units = 512; + private readonly NVMeInfo _info; + private readonly List _sensors = new(); + + /// + /// Gets the SMART data. + /// + public NVMeSmart Smart { get; } + + private NVMeGeneric(StorageInfo storageInfo, NVMeInfo info, int index, ISettings settings) + : base(storageInfo, info.Model, info.Revision, "nvme", index, settings) { - private const ulong Scale = 1000000; - private const ulong Units = 512; - private readonly NVMeInfo _info; - private readonly List _sensors = new(); + Smart = new NVMeSmart(storageInfo); + _info = info; + CreateSensors(); + } - /// - /// Gets the SMART data. - /// - public NVMeSmart Smart { get; } + private static NVMeInfo GetDeviceInfo(StorageInfo storageInfo) + { + var smart = new NVMeSmart(storageInfo); + return smart.GetInfo(); + } - private NVMeGeneric(StorageInfo storageInfo, NVMeInfo info, int index, ISettings settings) - : base(storageInfo, info.Model, info.Revision, "nvme", index, settings) + internal static AbstractStorage CreateInstance(StorageInfo storageInfo, ISettings settings) + { + NVMeInfo nvmeInfo = GetDeviceInfo(storageInfo); + return nvmeInfo == null ? null : new NVMeGeneric(storageInfo, nvmeInfo, storageInfo.Index, settings); + } + + protected override void CreateSensors() + { + NVMeHealthInfo log = Smart.GetHealthInfo(); + if (log != null) { - Smart = new NVMeSmart(storageInfo); - _info = info; - CreateSensors(); - } + AddSensor("Temperature", 0, false, SensorType.Temperature, health => health.Temperature); + AddSensor("Available Spare", 1, false, SensorType.Level, health => health.AvailableSpare); + AddSensor("Available Spare Threshold", 2, false, SensorType.Level, health => health.AvailableSpareThreshold); + AddSensor("Percentage Used", 3, false, SensorType.Level, health => health.PercentageUsed); + AddSensor("Data Read", 4, false, SensorType.Data, health => UnitsToData(health.DataUnitRead)); + AddSensor("Data Written", 5, false, SensorType.Data, health => UnitsToData(health.DataUnitWritten)); - private static NVMeInfo GetDeviceInfo(StorageInfo storageInfo) - { - var smart = new NVMeSmart(storageInfo); - return smart.GetInfo(); - } - - internal static AbstractStorage CreateInstance(StorageInfo storageInfo, ISettings settings) - { - NVMeInfo nvmeInfo = GetDeviceInfo(storageInfo); - return nvmeInfo == null ? null : new NVMeGeneric(storageInfo, nvmeInfo, storageInfo.Index, settings); - } - - protected override void CreateSensors() - { - NVMeHealthInfo log = Smart.GetHealthInfo(); - if (log != null) + int sensorIdx = 6; + for (int i = 0; i < log.TemperatureSensors.Length; i++) { - AddSensor("Temperature", 0, false, SensorType.Temperature, health => health.Temperature); - AddSensor("Available Spare", 1, false, SensorType.Level, health => health.AvailableSpare); - AddSensor("Available Spare Threshold", 2, false, SensorType.Level, health => health.AvailableSpareThreshold); - AddSensor("Percentage Used", 3, false, SensorType.Level, health => health.PercentageUsed); - AddSensor("Data Read", 4, false, SensorType.Data, health => UnitsToData(health.DataUnitRead)); - AddSensor("Data Written", 5, false, SensorType.Data, health => UnitsToData(health.DataUnitWritten)); - - int sensorIdx = 6; - for (int i = 0; i < log.TemperatureSensors.Length; i++) + int idx = i; + if (log.TemperatureSensors[idx] > short.MinValue) { - int idx = i; - if (log.TemperatureSensors[idx] > short.MinValue) - { - AddSensor("Temperature " + (idx + 1), sensorIdx, false, SensorType.Temperature, health => health.TemperatureSensors[idx]); - sensorIdx++; - } + AddSensor("Temperature " + (idx + 1), sensorIdx, false, SensorType.Temperature, health => health.TemperatureSensors[idx]); + sensorIdx++; } } - - base.CreateSensors(); } - private void AddSensor(string name, int index, bool defaultHidden, SensorType sensorType, GetSensorValue getValue) + base.CreateSensors(); + } + + private void AddSensor(string name, int index, bool defaultHidden, SensorType sensorType, GetSensorValue getValue) + { + var sensor = new NVMeSensor(name, index, defaultHidden, sensorType, this, _settings, getValue) { - var sensor = new NVMeSensor(name, index, defaultHidden, sensorType, this, _settings, getValue) - { - Value = 0 - }; - ActivateSensor(sensor); - _sensors.Add(sensor); + Value = 0 + }; + ActivateSensor(sensor); + _sensors.Add(sensor); + } + + private static float UnitsToData(ulong u) + { + // one unit is 512 * 1000 bytes, return in GB (not GiB) + return Units * u / Scale; + } + + protected override void UpdateSensors() + { + NVMeHealthInfo health = Smart.GetHealthInfo(); + if (health == null) + return; + + foreach (NVMeSensor sensor in _sensors) + sensor.Update(health); + } + + protected override void GetReport(StringBuilder r) + { + if (_info == null) + return; + + r.AppendLine("PCI Vendor ID: 0x" + _info.VID.ToString("x04")); + if (_info.VID != _info.SSVID) + r.AppendLine("PCI Subsystem Vendor ID: 0x" + _info.VID.ToString("x04")); + + r.AppendLine("IEEE OUI Identifier: 0x" + _info.IEEE[2].ToString("x02") + _info.IEEE[1].ToString("x02") + _info.IEEE[0].ToString("x02")); + r.AppendLine("Total NVM Capacity: " + _info.TotalCapacity); + r.AppendLine("Unallocated NVM Capacity: " + _info.UnallocatedCapacity); + r.AppendLine("Controller ID: " + _info.ControllerId); + r.AppendLine("Number of Namespaces: " + _info.NumberNamespaces); + + NVMeHealthInfo health = Smart.GetHealthInfo(); + if (health == null) + return; + + if (health.CriticalWarning == Kernel32.NVME_CRITICAL_WARNING.None) + r.AppendLine("Critical Warning: -"); + else + { + if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.AvailableSpaceLow) != 0) + r.AppendLine("Critical Warning: the available spare space has fallen below the threshold."); + + if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.TemperatureThreshold) != 0) + r.AppendLine("Critical Warning: a temperature is above an over temperature threshold or below an under temperature threshold."); + + if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.ReliabilityDegraded) != 0) + r.AppendLine("Critical Warning: the device reliability has been degraded due to significant media related errors or any internal error that degrades device reliability."); + + if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.ReadOnly) != 0) + r.AppendLine("Critical Warning: the media has been placed in read only mode."); + + if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.VolatileMemoryBackupDeviceFailed) != 0) + r.AppendLine("Critical Warning: the volatile memory backup device has failed."); } - private static float UnitsToData(ulong u) + r.AppendLine("Temperature: " + health.Temperature + " Celsius"); + r.AppendLine("Available Spare: " + health.AvailableSpare + "%"); + r.AppendLine("Available Spare Threshold: " + health.AvailableSpareThreshold + "%"); + r.AppendLine("Percentage Used: " + health.PercentageUsed + "%"); + r.AppendLine("Data Units Read: " + health.DataUnitRead); + r.AppendLine("Data Units Written: " + health.DataUnitWritten); + r.AppendLine("Host Read Commands: " + health.HostReadCommands); + r.AppendLine("Host Write Commands: " + health.HostWriteCommands); + r.AppendLine("Controller Busy Time: " + health.ControllerBusyTime); + r.AppendLine("Power Cycles: " + health.PowerCycle); + r.AppendLine("Power On Hours: " + health.PowerOnHours); + r.AppendLine("Unsafe Shutdowns: " + health.UnsafeShutdowns); + r.AppendLine("Media Errors: " + health.MediaErrors); + r.AppendLine("Number of Error Information Log Entries: " + health.ErrorInfoLogEntryCount); + r.AppendLine("Warning Composite Temperature Time: " + health.WarningCompositeTemperatureTime); + r.AppendLine("Critical Composite Temperature Time: " + health.CriticalCompositeTemperatureTime); + for (int i = 0; i < health.TemperatureSensors.Length; i++) { - // one unit is 512 * 1000 bytes, return in GB (not GiB) - return Units * u / Scale; + if (health.TemperatureSensors[i] > short.MinValue) + r.AppendLine("Temperature Sensor " + (i + 1) + ": " + health.TemperatureSensors[i] + " Celsius"); + } + } + + public override void Close() + { + Smart?.Close(); + + base.Close(); + } + + private delegate float GetSensorValue(NVMeHealthInfo health); + + private class NVMeSensor : Sensor + { + private readonly GetSensorValue _getValue; + + public NVMeSensor(string name, int index, bool defaultHidden, SensorType sensorType, Hardware hardware, ISettings settings, GetSensorValue getValue) + : base(name, index, defaultHidden, sensorType, hardware, null, settings) + { + _getValue = getValue; } - protected override void UpdateSensors() + public void Update(NVMeHealthInfo health) { - NVMeHealthInfo health = Smart.GetHealthInfo(); - if (health == null) + float v = _getValue(health); + if (SensorType == SensorType.Temperature && v is < -1000 or > 1000) return; - foreach (NVMeSensor sensor in _sensors) - sensor.Update(health); - } - - protected override void GetReport(StringBuilder r) - { - if (_info == null) - return; - - r.AppendLine("PCI Vendor ID: 0x" + _info.VID.ToString("x04")); - if (_info.VID != _info.SSVID) - r.AppendLine("PCI Subsystem Vendor ID: 0x" + _info.VID.ToString("x04")); - - r.AppendLine("IEEE OUI Identifier: 0x" + _info.IEEE[2].ToString("x02") + _info.IEEE[1].ToString("x02") + _info.IEEE[0].ToString("x02")); - r.AppendLine("Total NVM Capacity: " + _info.TotalCapacity); - r.AppendLine("Unallocated NVM Capacity: " + _info.UnallocatedCapacity); - r.AppendLine("Controller ID: " + _info.ControllerId); - r.AppendLine("Number of Namespaces: " + _info.NumberNamespaces); - - NVMeHealthInfo health = Smart.GetHealthInfo(); - if (health == null) - return; - - if (health.CriticalWarning == Kernel32.NVME_CRITICAL_WARNING.None) - r.AppendLine("Critical Warning: -"); - else - { - if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.AvailableSpaceLow) != 0) - r.AppendLine("Critical Warning: the available spare space has fallen below the threshold."); - - if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.TemperatureThreshold) != 0) - r.AppendLine("Critical Warning: a temperature is above an over temperature threshold or below an under temperature threshold."); - - if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.ReliabilityDegraded) != 0) - r.AppendLine("Critical Warning: the device reliability has been degraded due to significant media related errors or any internal error that degrades device reliability."); - - if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.ReadOnly) != 0) - r.AppendLine("Critical Warning: the media has been placed in read only mode."); - - if ((health.CriticalWarning & Kernel32.NVME_CRITICAL_WARNING.VolatileMemoryBackupDeviceFailed) != 0) - r.AppendLine("Critical Warning: the volatile memory backup device has failed."); - } - - r.AppendLine("Temperature: " + health.Temperature + " Celsius"); - r.AppendLine("Available Spare: " + health.AvailableSpare + "%"); - r.AppendLine("Available Spare Threshold: " + health.AvailableSpareThreshold + "%"); - r.AppendLine("Percentage Used: " + health.PercentageUsed + "%"); - r.AppendLine("Data Units Read: " + health.DataUnitRead); - r.AppendLine("Data Units Written: " + health.DataUnitWritten); - r.AppendLine("Host Read Commands: " + health.HostReadCommands); - r.AppendLine("Host Write Commands: " + health.HostWriteCommands); - r.AppendLine("Controller Busy Time: " + health.ControllerBusyTime); - r.AppendLine("Power Cycles: " + health.PowerCycle); - r.AppendLine("Power On Hours: " + health.PowerOnHours); - r.AppendLine("Unsafe Shutdowns: " + health.UnsafeShutdowns); - r.AppendLine("Media Errors: " + health.MediaErrors); - r.AppendLine("Number of Error Information Log Entries: " + health.ErrorInfoLogEntryCount); - r.AppendLine("Warning Composite Temperature Time: " + health.WarningCompositeTemperatureTime); - r.AppendLine("Critical Composite Temperature Time: " + health.CriticalCompositeTemperatureTime); - for (int i = 0; i < health.TemperatureSensors.Length; i++) - { - if (health.TemperatureSensors[i] > short.MinValue) - r.AppendLine("Temperature Sensor " + (i + 1) + ": " + health.TemperatureSensors[i] + " Celsius"); - } - } - - public override void Close() - { - Smart?.Close(); - - base.Close(); - } - - private delegate float GetSensorValue(NVMeHealthInfo health); - - private class NVMeSensor : Sensor - { - private readonly GetSensorValue _getValue; - - public NVMeSensor(string name, int index, bool defaultHidden, SensorType sensorType, Hardware hardware, ISettings settings, GetSensorValue getValue) - : base(name, index, defaultHidden, sensorType, hardware, null, settings) - { - _getValue = getValue; - } - - public void Update(NVMeHealthInfo health) - { - float v = _getValue(health); - if (SensorType == SensorType.Temperature && v is < -1000 or > 1000) - return; - - Value = v; - } + Value = v; } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeHealthInfo.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeHealthInfo.cs index 8b033e5..cfd580e 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeHealthInfo.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeHealthInfo.cs @@ -5,44 +5,43 @@ using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public abstract class NVMeHealthInfo { - public abstract class NVMeHealthInfo - { - public byte AvailableSpare { get; protected set; } + public byte AvailableSpare { get; protected set; } - public byte AvailableSpareThreshold { get; protected set; } + public byte AvailableSpareThreshold { get; protected set; } - public ulong ControllerBusyTime { get; protected set; } + public ulong ControllerBusyTime { get; protected set; } - public uint CriticalCompositeTemperatureTime { get; protected set; } + public uint CriticalCompositeTemperatureTime { get; protected set; } - public Kernel32.NVME_CRITICAL_WARNING CriticalWarning { get; protected set; } + public Kernel32.NVME_CRITICAL_WARNING CriticalWarning { get; protected set; } - public ulong DataUnitRead { get; protected set; } + public ulong DataUnitRead { get; protected set; } - public ulong DataUnitWritten { get; protected set; } + public ulong DataUnitWritten { get; protected set; } - public ulong ErrorInfoLogEntryCount { get; protected set; } + public ulong ErrorInfoLogEntryCount { get; protected set; } - public ulong HostReadCommands { get; protected set; } + public ulong HostReadCommands { get; protected set; } - public ulong HostWriteCommands { get; protected set; } + public ulong HostWriteCommands { get; protected set; } - public ulong MediaErrors { get; protected set; } + public ulong MediaErrors { get; protected set; } - public byte PercentageUsed { get; protected set; } + public byte PercentageUsed { get; protected set; } - public ulong PowerCycle { get; protected set; } + public ulong PowerCycle { get; protected set; } - public ulong PowerOnHours { get; protected set; } + public ulong PowerOnHours { get; protected set; } - public short Temperature { get; protected set; } + public short Temperature { get; protected set; } - public short[] TemperatureSensors { get; protected set; } + public short[] TemperatureSensors { get; protected set; } - public ulong UnsafeShutdowns { get; protected set; } + public ulong UnsafeShutdowns { get; protected set; } - public uint WarningCompositeTemperatureTime { get; protected set; } - } -} + public uint WarningCompositeTemperatureTime { get; protected set; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeInfo.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeInfo.cs index ddcf95e..a11e9a5 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeInfo.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeInfo.cs @@ -3,30 +3,29 @@ // Copyright (C) LibreHardwareMonitor and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public abstract class NVMeInfo { - public abstract class NVMeInfo - { - public ushort ControllerId { get; protected set; } + public ushort ControllerId { get; protected set; } - public byte[] IEEE { get; protected set; } + public byte[] IEEE { get; protected set; } - public int Index { get; protected set; } + public int Index { get; protected set; } - public string Model { get; protected set; } + public string Model { get; protected set; } - public uint NumberNamespaces { get; protected set; } + public uint NumberNamespaces { get; protected set; } - public string Revision { get; protected set; } + public string Revision { get; protected set; } - public string Serial { get; protected set; } + public string Serial { get; protected set; } - public ushort SSVID { get; protected set; } + public ushort SSVID { get; protected set; } - public ulong TotalCapacity { get; protected set; } + public ulong TotalCapacity { get; protected set; } - public ulong UnallocatedCapacity { get; protected set; } + public ulong UnallocatedCapacity { get; protected set; } - public ushort VID { get; protected set; } - } -} + public ushort VID { get; protected set; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs index 2ce43c5..e3ab2d6 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntel.cs @@ -8,149 +8,148 @@ using System.Runtime.InteropServices; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal class NVMeIntel : INVMeDrive { - internal class NVMeIntel : INVMeDrive + //intel nvme access + + public SafeHandle Identify(StorageInfo storageInfo) { - //intel nvme access + return NVMeWindows.IdentifyDevice(storageInfo); + } - public SafeHandle Identify(StorageInfo storageInfo) + public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + + Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); + passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); + passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature1); + passThrough.srb.Timeout = 10; + passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.srb.ReturnCode = 0; + passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.NVMeCmd = new uint[16]; + passThrough.NVMeCmd[0] = 6; //identify + passThrough.NVMeCmd[10] = 1; //return to host + passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.QueueId = 0; + passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; + passThrough.MetaDataLen = 0; + passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(passThrough, buffer, false); + + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) { - return NVMeWindows.IdentifyDevice(storageInfo); - } - - public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); - passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); - passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature1); - passThrough.srb.Timeout = 10; - passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; - passThrough.srb.ReturnCode = 0; - passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); - passThrough.NVMeCmd = new uint[16]; - passThrough.NVMeCmd[0] = 6; //identify - passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; - passThrough.QueueId = 0; - passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; - passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(passThrough, buffer, false); - - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); - var newPtr = IntPtr.Add(buffer, offset.ToInt32()); - int finalSize = Marshal.SizeOf(); - IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); - Kernel32.RtlZeroMemory(ptr, finalSize); - int len = Math.Min(finalSize, passThrough.DataBuffer.Length); - Kernel32.RtlCopyMemory(ptr, newPtr, (uint)len); - Marshal.FreeHGlobal(buffer); - - data = Marshal.PtrToStructure(ptr); - Marshal.FreeHGlobal(ptr); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } - - return result; - } - - public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); - passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); - passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature1); - passThrough.srb.Timeout = 10; - passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; - passThrough.srb.ReturnCode = 0; - passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); - passThrough.NVMeCmd[0] = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; // GetLogPage - passThrough.NVMeCmd[1] = 0xFFFFFFFF; // address - passThrough.NVMeCmd[10] = 0x007f0002; // uint cdw10 = 0x000000002 | (((size / 4) - 1) << 16); - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; - passThrough.QueueId = 0; - passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; - passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(passThrough, buffer, false); - - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); - var newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); - Marshal.FreeHGlobal(buffer); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } - return result; - } - - public static SafeHandle IdentifyDevice(StorageInfo storageInfo) - { - SafeHandle handle = Kernel32.OpenDevice(storageInfo.Scsi); - if (handle?.IsInvalid != false) - return null; - - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); - passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); - passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature1); - passThrough.srb.Timeout = 10; - passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; - passThrough.srb.ReturnCode = 0; - passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); - passThrough.NVMeCmd = new uint[16]; - passThrough.NVMeCmd[0] = 6; //identify - passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; - passThrough.QueueId = 0; - passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; - passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(passThrough, buffer, false); - - bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + var newPtr = IntPtr.Add(buffer, offset.ToInt32()); + int finalSize = Marshal.SizeOf(); + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Kernel32.RtlZeroMemory(ptr, finalSize); + int len = Math.Min(finalSize, passThrough.DataBuffer.Length); + Kernel32.RtlCopyMemory(ptr, newPtr, (uint)len); Marshal.FreeHGlobal(buffer); - if (validTransfer) { } - else - { - handle.Close(); - handle = null; - } - return handle; + data = Marshal.PtrToStructure(ptr); + Marshal.FreeHGlobal(ptr); + result = true; } + else + { + Marshal.FreeHGlobal(buffer); + } + + return result; } -} + + public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + + Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); + passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); + passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature1); + passThrough.srb.Timeout = 10; + passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.srb.ReturnCode = 0; + passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.NVMeCmd[0] = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; // GetLogPage + passThrough.NVMeCmd[1] = 0xFFFFFFFF; // address + passThrough.NVMeCmd[10] = 0x007f0002; // uint cdw10 = 0x000000002 | (((size / 4) - 1) << 16); + passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.QueueId = 0; + passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; + passThrough.MetaDataLen = 0; + passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(passThrough, buffer, false); + + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) + { + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + var newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = Marshal.PtrToStructure(newPtr); + Marshal.FreeHGlobal(buffer); + result = true; + } + else + { + Marshal.FreeHGlobal(buffer); + } + return result; + } + + public static SafeHandle IdentifyDevice(StorageInfo storageInfo) + { + SafeHandle handle = Kernel32.OpenDevice(storageInfo.Scsi); + if (handle?.IsInvalid != false) + return null; + + Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); + passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); + passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature1); + passThrough.srb.Timeout = 10; + passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.srb.ReturnCode = 0; + passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.NVMeCmd = new uint[16]; + passThrough.NVMeCmd[0] = 6; //identify + passThrough.NVMeCmd[10] = 1; //return to host + passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.QueueId = 0; + passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; + passThrough.MetaDataLen = 0; + passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(passThrough, buffer, false); + + bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + Marshal.FreeHGlobal(buffer); + + if (validTransfer) { } + else + { + handle.Close(); + handle = null; + } + return handle; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs index 229387d..344c0c5 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeIntelRst.cs @@ -8,150 +8,149 @@ using System.Runtime.InteropServices; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal class NVMeIntelRst : INVMeDrive { - internal class NVMeIntelRst : INVMeDrive + //intel RST (raid) nvme access + + public SafeHandle Identify(StorageInfo storageInfo) { - //intel RST (raid) nvme access + return NVMeWindows.IdentifyDevice(storageInfo); + } - public SafeHandle Identify(StorageInfo storageInfo) + public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + + Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); + passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); + passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature2); + passThrough.srb.Timeout = 10; + passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.srb.ReturnCode = 0; + passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.NVMeCmd = new uint[16]; + passThrough.NVMeCmd[0] = 6; //identify + passThrough.NVMeCmd[10] = 1; //return to host + passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.QueueId = 0; + passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; + passThrough.MetaDataLen = 0; + passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(passThrough, buffer, false); + + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) { - return NVMeWindows.IdentifyDevice(storageInfo); - } - - public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); - passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); - passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature2); - passThrough.srb.Timeout = 10; - passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; - passThrough.srb.ReturnCode = 0; - passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); - passThrough.NVMeCmd = new uint[16]; - passThrough.NVMeCmd[0] = 6; //identify - passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; - passThrough.QueueId = 0; - passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; - passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(passThrough, buffer, false); - - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); - IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); - int finalSize = Marshal.SizeOf(); - IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); - Kernel32.RtlZeroMemory(ptr, finalSize); - int len = Math.Min(finalSize, passThrough.DataBuffer.Length); - Kernel32.RtlCopyMemory(ptr, newPtr, (uint)len); - Marshal.FreeHGlobal(buffer); - - data = Marshal.PtrToStructure(ptr); - Marshal.FreeHGlobal(ptr); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } - - return result; - } - - public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); - passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); - passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature2); - passThrough.srb.Timeout = 10; - passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; - passThrough.srb.ReturnCode = 0; - passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); - passThrough.NVMeCmd[0] = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; // GetLogPage - passThrough.NVMeCmd[1] = 0xFFFFFFFF; // address - passThrough.NVMeCmd[10] = 0x007f0002; // uint cdw10 = 0x000000002 | (((size / 4) - 1) << 16); - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; - passThrough.QueueId = 0; - passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; - passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(passThrough, buffer, false); - - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); - IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); - Marshal.FreeHGlobal(buffer); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } - - return result; - } - - public static SafeHandle IdentifyDevice(StorageInfo storageInfo) - { - SafeHandle handle = Kernel32.OpenDevice(storageInfo.Scsi); - if (handle?.IsInvalid != false) - return null; - - Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); - passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); - passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature2); - passThrough.srb.Timeout = 10; - passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; - passThrough.srb.ReturnCode = 0; - passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); - passThrough.NVMeCmd = new uint[16]; - passThrough.NVMeCmd[0] = 6; //identify - passThrough.NVMeCmd[10] = 1; //return to host - passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; - passThrough.QueueId = 0; - passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; - passThrough.MetaDataLen = 0; - passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(passThrough, buffer, false); - - bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); + int finalSize = Marshal.SizeOf(); + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf()); + Kernel32.RtlZeroMemory(ptr, finalSize); + int len = Math.Min(finalSize, passThrough.DataBuffer.Length); + Kernel32.RtlCopyMemory(ptr, newPtr, (uint)len); Marshal.FreeHGlobal(buffer); - if (validTransfer) { } - else - { - handle.Close(); - handle = null; - } - return handle; + data = Marshal.PtrToStructure(ptr); + Marshal.FreeHGlobal(ptr); + result = true; } + else + { + Marshal.FreeHGlobal(buffer); + } + + return result; + } + + public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + + Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); + passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); + passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature2); + passThrough.srb.Timeout = 10; + passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.srb.ReturnCode = 0; + passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.NVMeCmd[0] = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; // GetLogPage + passThrough.NVMeCmd[1] = 0xFFFFFFFF; // address + passThrough.NVMeCmd[10] = 0x007f0002; // uint cdw10 = 0x000000002 | (((size / 4) - 1) << 16); + passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.QueueId = 0; + passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; + passThrough.MetaDataLen = 0; + passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(passThrough, buffer, false); + + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) + { + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.NVME_PASS_THROUGH_IOCTL.DataBuffer)); + IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = Marshal.PtrToStructure(newPtr); + Marshal.FreeHGlobal(buffer); + result = true; + } + else + { + Marshal.FreeHGlobal(buffer); + } + + return result; + } + + public static SafeHandle IdentifyDevice(StorageInfo storageInfo) + { + SafeHandle handle = Kernel32.OpenDevice(storageInfo.Scsi); + if (handle?.IsInvalid != false) + return null; + + Kernel32.NVME_PASS_THROUGH_IOCTL passThrough = Kernel32.CreateStruct(); + passThrough.srb.HeaderLenght = (uint)Marshal.SizeOf(); + passThrough.srb.Signature = Encoding.ASCII.GetBytes(Kernel32.IntelNVMeMiniPortSignature2); + passThrough.srb.Timeout = 10; + passThrough.srb.ControlCode = Kernel32.NVME_PASS_THROUGH_SRB_IO_CODE; + passThrough.srb.ReturnCode = 0; + passThrough.srb.Length = (uint)Marshal.SizeOf() - (uint)Marshal.SizeOf(); + passThrough.NVMeCmd = new uint[16]; + passThrough.NVMeCmd[0] = 6; //identify + passThrough.NVMeCmd[10] = 1; //return to host + passThrough.Direction = Kernel32.NVME_DIRECTION.NVME_FROM_DEV_TO_HOST; + passThrough.QueueId = 0; + passThrough.DataBufferLen = (uint)passThrough.DataBuffer.Length; + passThrough.MetaDataLen = 0; + passThrough.ReturnBufferLen = (uint)Marshal.SizeOf(); + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(passThrough, buffer, false); + + bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_MINIPORT, buffer, length, buffer, length, out _, IntPtr.Zero); + Marshal.FreeHGlobal(buffer); + + if (validTransfer) { } + else + { + handle.Close(); + handle = null; + } + return handle; } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs index 42afa9d..152a0fd 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeSamsung.cs @@ -8,104 +8,56 @@ using System.Linq; using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal class NVMeSamsung : INVMeDrive { - internal class NVMeSamsung : INVMeDrive + //samsung nvme access + //https://github.com/hiyohiyo/CrystalDiskInfo + //https://github.com/hiyohiyo/CrystalDiskInfo/blob/master/AtaSmart.cpp + + public SafeHandle Identify(StorageInfo storageInfo) { - //samsung nvme access - //https://github.com/hiyohiyo/CrystalDiskInfo - //https://github.com/hiyohiyo/CrystalDiskInfo/blob/master/AtaSmart.cpp + return NVMeWindows.IdentifyDevice(storageInfo); + } - public SafeHandle Identify(StorageInfo storageInfo) + public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = Kernel32.CreateStruct(); + + buffers.Spt.Length = (ushort)Marshal.SizeOf(); + buffers.Spt.PathId = 0; + buffers.Spt.TargetId = 0; + buffers.Spt.Lun = 0; + buffers.Spt.SenseInfoLength = 24; + buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; + buffers.Spt.TimeOutValue = 2; + buffers.Spt.DataBufferOffset = Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.CdbLength = 16; + buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN + buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol + buffers.Spt.Cdb[3] = 5; // Identify + buffers.Spt.Cdb[8] = 0; // Transfer Length + buffers.Spt.Cdb[9] = 0x40; // Transfer Length + buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; + buffers.DataBuf[0] = 1; + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(buffers, buffer, false); + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + Marshal.FreeHGlobal(buffer); + + if (validTransfer) { - return NVMeWindows.IdentifyDevice(storageInfo); - } - - public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = Kernel32.CreateStruct(); - - buffers.Spt.Length = (ushort)Marshal.SizeOf(); - buffers.Spt.PathId = 0; - buffers.Spt.TargetId = 0; - buffers.Spt.Lun = 0; - buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; - buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); - buffers.Spt.CdbLength = 16; - buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN - buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol - buffers.Spt.Cdb[3] = 5; // Identify - buffers.Spt.Cdb[8] = 0; // Transfer Length - buffers.Spt.Cdb[9] = 0x40; // Transfer Length - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; - buffers.DataBuf[0] = 1; - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(buffers, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); - Marshal.FreeHGlobal(buffer); - - if (validTransfer) - { - //read data from samsung SSD - buffers = Kernel32.CreateStruct(); - buffers.Spt.Length = (ushort)Marshal.SizeOf(); - buffers.Spt.PathId = 0; - buffers.Spt.TargetId = 0; - buffers.Spt.Lun = 0; - buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; - buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); - buffers.Spt.CdbLength = 16; - buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN - buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol - buffers.Spt.Cdb[3] = 5; // Identify - buffers.Spt.Cdb[8] = 2; // Transfer Length (high) - buffers.Spt.Cdb[9] = 0; // Transfer Length (low) - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; - - length = Marshal.SizeOf(); - buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(buffers, buffer, false); - - validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer && buffers.DataBuf.Any(x => x != 0)) - { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); - IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); - Marshal.FreeHGlobal(buffer); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } - } - - return result; - } - - public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = Kernel32.CreateStruct(); - + //read data from samsung SSD + buffers = Kernel32.CreateStruct(); buffers.Spt.Length = (ushort)Marshal.SizeOf(); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; @@ -116,75 +68,151 @@ namespace LibreHardwareMonitor.Hardware.Storage buffers.Spt.DataBufferOffset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); buffers.Spt.CdbLength = 16; - buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN + buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol - buffers.Spt.Cdb[3] = 6; // Log Data - buffers.Spt.Cdb[8] = 0; // Transfer Length - buffers.Spt.Cdb[9] = 0x40; // Transfer Length - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; - buffers.DataBuf[0] = 2; - buffers.DataBuf[4] = 0xff; - buffers.DataBuf[5] = 0xff; - buffers.DataBuf[6] = 0xff; - buffers.DataBuf[7] = 0xff; + buffers.Spt.Cdb[3] = 5; // Identify + buffers.Spt.Cdb[8] = 2; // Transfer Length (high) + buffers.Spt.Cdb[9] = 0; // Transfer Length (low) + buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); + length = Marshal.SizeOf(); + buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); - Marshal.FreeHGlobal(buffer); - if (validTransfer) + validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer && buffers.DataBuf.Any(x => x != 0)) { - //read data from samsung SSD - buffers = Kernel32.CreateStruct(); - buffers.Spt.Length = (ushort)Marshal.SizeOf(); - buffers.Spt.PathId = 0; - buffers.Spt.TargetId = 0; - buffers.Spt.Lun = 0; - buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; - buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); - buffers.Spt.CdbLength = 16; - buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN - buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol - buffers.Spt.Cdb[3] = 6; // Log Data - buffers.Spt.Cdb[8] = 2; // Transfer Length (high) - buffers.Spt.Cdb[9] = 0; // Transfer Length (low) - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; - - length = Marshal.SizeOf(); - buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(buffers, buffer, false); - - validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); - IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); - Marshal.FreeHGlobal(buffer); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = Marshal.PtrToStructure(newPtr); + Marshal.FreeHGlobal(buffer); + result = true; + } + else + { + Marshal.FreeHGlobal(buffer); } - - return result; } - public static SafeHandle IdentifyDevice(StorageInfo storageInfo) + return result; + } + + public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = Kernel32.CreateStruct(); + + buffers.Spt.Length = (ushort)Marshal.SizeOf(); + buffers.Spt.PathId = 0; + buffers.Spt.TargetId = 0; + buffers.Spt.Lun = 0; + buffers.Spt.SenseInfoLength = 24; + buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; + buffers.Spt.TimeOutValue = 2; + buffers.Spt.DataBufferOffset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.CdbLength = 16; + buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN + buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol + buffers.Spt.Cdb[3] = 6; // Log Data + buffers.Spt.Cdb[8] = 0; // Transfer Length + buffers.Spt.Cdb[9] = 0x40; // Transfer Length + buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; + buffers.DataBuf[0] = 2; + buffers.DataBuf[4] = 0xff; + buffers.DataBuf[5] = 0xff; + buffers.DataBuf[6] = 0xff; + buffers.DataBuf[7] = 0xff; + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(buffers, buffer, false); + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + Marshal.FreeHGlobal(buffer); + + if (validTransfer) { - SafeHandle handle = Kernel32.OpenDevice(storageInfo.DeviceId); - if (handle?.IsInvalid != false) - return null; + //read data from samsung SSD + buffers = Kernel32.CreateStruct(); + buffers.Spt.Length = (ushort)Marshal.SizeOf(); + buffers.Spt.PathId = 0; + buffers.Spt.TargetId = 0; + buffers.Spt.Lun = 0; + buffers.Spt.SenseInfoLength = 24; + buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; + buffers.Spt.TimeOutValue = 2; + buffers.Spt.DataBufferOffset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.CdbLength = 16; + buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN + buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol + buffers.Spt.Cdb[3] = 6; // Log Data + buffers.Spt.Cdb[8] = 2; // Transfer Length (high) + buffers.Spt.Cdb[9] = 0; // Transfer Length (low) + buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = Kernel32.CreateStruct(); + length = Marshal.SizeOf(); + buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(buffers, buffer, false); + validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) + { + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + IntPtr newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = Marshal.PtrToStructure(newPtr); + Marshal.FreeHGlobal(buffer); + result = true; + } + else + { + Marshal.FreeHGlobal(buffer); + } + } + + return result; + } + + public static SafeHandle IdentifyDevice(StorageInfo storageInfo) + { + SafeHandle handle = Kernel32.OpenDevice(storageInfo.DeviceId); + if (handle?.IsInvalid != false) + return null; + + Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS buffers = Kernel32.CreateStruct(); + + buffers.Spt.Length = (ushort)Marshal.SizeOf(); + buffers.Spt.PathId = 0; + buffers.Spt.TargetId = 0; + buffers.Spt.Lun = 0; + buffers.Spt.SenseInfoLength = 24; + buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; + buffers.Spt.TimeOutValue = 2; + buffers.Spt.DataBufferOffset = Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); + buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); + buffers.Spt.CdbLength = 16; + buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN + buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol + buffers.Spt.Cdb[3] = 5; // Identify + buffers.Spt.Cdb[8] = 0; // Transfer Length + buffers.Spt.Cdb[9] = 0x40; + buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; + buffers.DataBuf[0] = 1; + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(buffers, buffer, false); + bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); + Marshal.FreeHGlobal(buffer); + + if (validTransfer) + { + //read data from samsung SSD + buffers = Kernel32.CreateStruct(); buffers.Spt.Length = (ushort)Marshal.SizeOf(); buffers.Spt.PathId = 0; buffers.Spt.TargetId = 0; @@ -195,66 +223,37 @@ namespace LibreHardwareMonitor.Hardware.Storage buffers.Spt.DataBufferOffset = Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); buffers.Spt.CdbLength = 16; - buffers.Spt.Cdb[0] = 0xB5; // SECURITY PROTOCOL IN + buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol buffers.Spt.Cdb[3] = 5; // Identify - buffers.Spt.Cdb[8] = 0; // Transfer Length - buffers.Spt.Cdb[9] = 0x40; - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_OUT; - buffers.DataBuf[0] = 1; + buffers.Spt.Cdb[8] = 2; // Transfer Length + buffers.Spt.Cdb[9] = 0; + buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); + length = Marshal.SizeOf(); + buffer = Marshal.AllocHGlobal(length); Marshal.StructureToPtr(buffers, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); - Marshal.FreeHGlobal(buffer); + validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); if (validTransfer) { - //read data from samsung SSD - buffers = Kernel32.CreateStruct(); - buffers.Spt.Length = (ushort)Marshal.SizeOf(); - buffers.Spt.PathId = 0; - buffers.Spt.TargetId = 0; - buffers.Spt.Lun = 0; - buffers.Spt.SenseInfoLength = 24; - buffers.Spt.DataTransferLength = (uint)buffers.DataBuf.Length; - buffers.Spt.TimeOutValue = 2; - buffers.Spt.DataBufferOffset = Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.DataBuf)); - buffers.Spt.SenseInfoOffset = (uint)Marshal.OffsetOf(typeof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS), nameof(Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS.SenseBuf)); - buffers.Spt.CdbLength = 16; - buffers.Spt.Cdb[0] = 0xA2; // SECURITY PROTOCOL IN - buffers.Spt.Cdb[1] = 0xFE; // Samsung Protocol - buffers.Spt.Cdb[3] = 5; // Identify - buffers.Spt.Cdb[8] = 2; // Transfer Length - buffers.Spt.Cdb[9] = 0; - buffers.Spt.DataIn = (byte)Kernel32.SCSI_IOCTL_DATA.SCSI_IOCTL_DATA_IN; + Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS result = Marshal.PtrToStructure(buffer); - length = Marshal.SizeOf(); - buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(buffers, buffer, false); - - validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_SCSI_PASS_THROUGH, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - Kernel32.SCSI_PASS_THROUGH_WITH_BUFFERS result = Marshal.PtrToStructure(buffer); - - if (result.DataBuf.All(x => x == 0)) - { - handle.Close(); - handle = null; - } - } - else + if (result.DataBuf.All(x => x == 0)) { handle.Close(); handle = null; } - - Marshal.FreeHGlobal(buffer); + } + else + { + handle.Close(); + handle = null; } - return handle; + Marshal.FreeHGlobal(buffer); } + + return handle; } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeSmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeSmart.cs index 84f75f1..6f09790 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeSmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeSmart.cs @@ -8,184 +8,183 @@ using System.Runtime.InteropServices; using System.Text; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public class NVMeSmart : IDisposable { - public class NVMeSmart : IDisposable + private readonly int _driveNumber; + private readonly SafeHandle _handle; + + internal NVMeSmart(StorageInfo storageInfo) { - private readonly int _driveNumber; - private readonly SafeHandle _handle; + _driveNumber = storageInfo.Index; + NVMeDrive = null; + string name = storageInfo.Name; - internal NVMeSmart(StorageInfo storageInfo) + // Test Samsung protocol. + if (NVMeDrive == null && name.IndexOf("Samsung", StringComparison.OrdinalIgnoreCase) > -1) { - _driveNumber = storageInfo.Index; - NVMeDrive = null; - string name = storageInfo.Name; - - // Test Samsung protocol. - if (NVMeDrive == null && name.IndexOf("Samsung", StringComparison.OrdinalIgnoreCase) > -1) + _handle = NVMeSamsung.IdentifyDevice(storageInfo); + if (_handle != null) { - _handle = NVMeSamsung.IdentifyDevice(storageInfo); - if (_handle != null) + NVMeDrive = new NVMeSamsung(); + if (!NVMeDrive.IdentifyController(_handle, out _)) { - NVMeDrive = new NVMeSamsung(); - if (!NVMeDrive.IdentifyController(_handle, out _)) - { - NVMeDrive = null; - } - } - } - - // Test Intel protocol. - if (NVMeDrive == null && name.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) > -1) - { - _handle = NVMeIntel.IdentifyDevice(storageInfo); - if (_handle != null) - { - NVMeDrive = new NVMeIntel(); - } - } - - // Test Intel raid protocol. - if (NVMeDrive == null && name.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) > -1) - { - _handle = NVMeIntelRst.IdentifyDevice(storageInfo); - if (_handle != null) - { - NVMeDrive = new NVMeIntelRst(); - } - } - - // Test Windows generic driver protocol. - if (NVMeDrive == null) - { - _handle = NVMeWindows.IdentifyDevice(storageInfo); - if (_handle != null) - { - NVMeDrive = new NVMeWindows(); + NVMeDrive = null; } } } - public bool IsValid + // Test Intel protocol. + if (NVMeDrive == null && name.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) > -1) { - get + _handle = NVMeIntel.IdentifyDevice(storageInfo); + if (_handle != null) { - return _handle is { IsInvalid: false }; + NVMeDrive = new NVMeIntel(); } } - internal INVMeDrive NVMeDrive { get; } - - public void Dispose() + // Test Intel raid protocol. + if (NVMeDrive == null && name.IndexOf("Intel", StringComparison.OrdinalIgnoreCase) > -1) { - Close(); - } - - private static string GetString(byte[] s) - { - return Encoding.ASCII.GetString(s).Trim('\t', '\n', '\r', ' ', '\0'); - } - - private static short KelvinToCelsius(ushort k) - { - return (short)(k > 0 ? k - 273 : short.MinValue); - } - - private static short KelvinToCelsius(byte[] k) - { - return KelvinToCelsius(BitConverter.ToUInt16(k, 0)); - } - - public void Close() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - protected void Dispose(bool disposing) - { - if (disposing && _handle is { IsClosed: false }) + _handle = NVMeIntelRst.IdentifyDevice(storageInfo); + if (_handle != null) { - _handle.Close(); + NVMeDrive = new NVMeIntelRst(); } } - public Storage.NVMeInfo GetInfo() + // Test Windows generic driver protocol. + if (NVMeDrive == null) { - if (_handle?.IsClosed != false) - return null; - - bool valid = false; - var data = new Kernel32.NVME_IDENTIFY_CONTROLLER_DATA(); - if (NVMeDrive != null) - valid = NVMeDrive.IdentifyController(_handle, out data); - - if (!valid) - return null; - - return new NVMeInfo(_driveNumber, data); - } - - public Storage.NVMeHealthInfo GetHealthInfo() - { - if (_handle?.IsClosed != false) - return null; - - bool valid = false; - var data = new Kernel32.NVME_HEALTH_INFO_LOG(); - if (NVMeDrive != null) - valid = NVMeDrive.HealthInfoLog(_handle, out data); - - if (!valid) - return null; - - return new NVMeHealthInfo(data); - } - - private class NVMeInfo : Storage.NVMeInfo - { - public NVMeInfo(int index, Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) + _handle = NVMeWindows.IdentifyDevice(storageInfo); + if (_handle != null) { - Index = index; - VID = data.VID; - SSVID = data.SSVID; - Serial = GetString(data.SN); - Model = GetString(data.MN); - Revision = GetString(data.FR); - IEEE = data.IEEE; - TotalCapacity = BitConverter.ToUInt64(data.TNVMCAP, 0); // 128bit little endian - UnallocatedCapacity = BitConverter.ToUInt64(data.UNVMCAP, 0); - ControllerId = data.CNTLID; - NumberNamespaces = data.NN; - } - } - - private class NVMeHealthInfo : Storage.NVMeHealthInfo - { - public NVMeHealthInfo(Kernel32.NVME_HEALTH_INFO_LOG log) - { - CriticalWarning = (Kernel32.NVME_CRITICAL_WARNING)log.CriticalWarning; - Temperature = KelvinToCelsius(log.CompositeTemp); - AvailableSpare = log.AvailableSpare; - AvailableSpareThreshold = log.AvailableSpareThreshold; - PercentageUsed = log.PercentageUsed; - DataUnitRead = BitConverter.ToUInt64(log.DataUnitRead, 0); - DataUnitWritten = BitConverter.ToUInt64(log.DataUnitWritten, 0); - HostReadCommands = BitConverter.ToUInt64(log.HostReadCommands, 0); - HostWriteCommands = BitConverter.ToUInt64(log.HostWriteCommands, 0); - ControllerBusyTime = BitConverter.ToUInt64(log.ControllerBusyTime, 0); - PowerCycle = BitConverter.ToUInt64(log.PowerCycles, 0); - PowerOnHours = BitConverter.ToUInt64(log.PowerOnHours, 0); - UnsafeShutdowns = BitConverter.ToUInt64(log.UnsafeShutdowns, 0); - MediaErrors = BitConverter.ToUInt64(log.MediaAndDataIntegrityErrors, 0); - ErrorInfoLogEntryCount = BitConverter.ToUInt64(log.NumberErrorInformationLogEntries, 0); - WarningCompositeTemperatureTime = log.WarningCompositeTemperatureTime; - CriticalCompositeTemperatureTime = log.CriticalCompositeTemperatureTime; - - TemperatureSensors = new short[log.TemperatureSensor.Length]; - for (int i = 0; i < TemperatureSensors.Length; i++) - TemperatureSensors[i] = KelvinToCelsius(log.TemperatureSensor[i]); + NVMeDrive = new NVMeWindows(); } } } -} + + public bool IsValid + { + get + { + return _handle is { IsInvalid: false }; + } + } + + internal INVMeDrive NVMeDrive { get; } + + public void Dispose() + { + Close(); + } + + private static string GetString(byte[] s) + { + return Encoding.ASCII.GetString(s).Trim('\t', '\n', '\r', ' ', '\0'); + } + + private static short KelvinToCelsius(ushort k) + { + return (short)(k > 0 ? k - 273 : short.MinValue); + } + + private static short KelvinToCelsius(byte[] k) + { + return KelvinToCelsius(BitConverter.ToUInt16(k, 0)); + } + + public void Close() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + protected void Dispose(bool disposing) + { + if (disposing && _handle is { IsClosed: false }) + { + _handle.Close(); + } + } + + public Storage.NVMeInfo GetInfo() + { + if (_handle?.IsClosed != false) + return null; + + bool valid = false; + var data = new Kernel32.NVME_IDENTIFY_CONTROLLER_DATA(); + if (NVMeDrive != null) + valid = NVMeDrive.IdentifyController(_handle, out data); + + if (!valid) + return null; + + return new NVMeInfo(_driveNumber, data); + } + + public Storage.NVMeHealthInfo GetHealthInfo() + { + if (_handle?.IsClosed != false) + return null; + + bool valid = false; + var data = new Kernel32.NVME_HEALTH_INFO_LOG(); + if (NVMeDrive != null) + valid = NVMeDrive.HealthInfoLog(_handle, out data); + + if (!valid) + return null; + + return new NVMeHealthInfo(data); + } + + private class NVMeInfo : Storage.NVMeInfo + { + public NVMeInfo(int index, Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) + { + Index = index; + VID = data.VID; + SSVID = data.SSVID; + Serial = GetString(data.SN); + Model = GetString(data.MN); + Revision = GetString(data.FR); + IEEE = data.IEEE; + TotalCapacity = BitConverter.ToUInt64(data.TNVMCAP, 0); // 128bit little endian + UnallocatedCapacity = BitConverter.ToUInt64(data.UNVMCAP, 0); + ControllerId = data.CNTLID; + NumberNamespaces = data.NN; + } + } + + private class NVMeHealthInfo : Storage.NVMeHealthInfo + { + public NVMeHealthInfo(Kernel32.NVME_HEALTH_INFO_LOG log) + { + CriticalWarning = (Kernel32.NVME_CRITICAL_WARNING)log.CriticalWarning; + Temperature = KelvinToCelsius(log.CompositeTemp); + AvailableSpare = log.AvailableSpare; + AvailableSpareThreshold = log.AvailableSpareThreshold; + PercentageUsed = log.PercentageUsed; + DataUnitRead = BitConverter.ToUInt64(log.DataUnitRead, 0); + DataUnitWritten = BitConverter.ToUInt64(log.DataUnitWritten, 0); + HostReadCommands = BitConverter.ToUInt64(log.HostReadCommands, 0); + HostWriteCommands = BitConverter.ToUInt64(log.HostWriteCommands, 0); + ControllerBusyTime = BitConverter.ToUInt64(log.ControllerBusyTime, 0); + PowerCycle = BitConverter.ToUInt64(log.PowerCycles, 0); + PowerOnHours = BitConverter.ToUInt64(log.PowerOnHours, 0); + UnsafeShutdowns = BitConverter.ToUInt64(log.UnsafeShutdowns, 0); + MediaErrors = BitConverter.ToUInt64(log.MediaAndDataIntegrityErrors, 0); + ErrorInfoLogEntryCount = BitConverter.ToUInt64(log.NumberErrorInformationLogEntries, 0); + WarningCompositeTemperatureTime = log.WarningCompositeTemperatureTime; + CriticalCompositeTemperatureTime = log.CriticalCompositeTemperatureTime; + + TemperatureSensors = new short[log.TemperatureSensor.Length]; + for (int i = 0; i < TemperatureSensors.Length; i++) + TemperatureSensors[i] = KelvinToCelsius(log.TemperatureSensor[i]); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs b/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs index 313beea..5b161f9 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NVMeWindows.cs @@ -7,122 +7,121 @@ using System; using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal class NVMeWindows : INVMeDrive { - internal class NVMeWindows : INVMeDrive + //windows generic driver nvme access + + public SafeHandle Identify(StorageInfo storageInfo) { - //windows generic driver nvme access - - public SafeHandle Identify(StorageInfo storageInfo) - { - return IdentifyDevice(storageInfo); - } - - public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - Kernel32.STORAGE_QUERY_BUFFER nptwb = Kernel32.CreateStruct(); - nptwb.ProtocolSpecific.ProtocolType = Kernel32.STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; - nptwb.ProtocolSpecific.DataType = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeIdentify; - nptwb.ProtocolSpecific.ProtocolDataRequestValue = (uint)Kernel32.STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE.NVMeIdentifyCnsController; - nptwb.ProtocolSpecific.ProtocolDataOffset = (uint)Marshal.SizeOf(); - nptwb.ProtocolSpecific.ProtocolDataLength = (uint)nptwb.Buffer.Length; - nptwb.PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; - nptwb.QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery; - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(nptwb, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - //map NVME_IDENTIFY_CONTROLLER_DATA to nptwb.Buffer - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.STORAGE_QUERY_BUFFER.Buffer)); - var newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); - Marshal.FreeHGlobal(buffer); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } - - return result; - } - - public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) - { - data = Kernel32.CreateStruct(); - if (hDevice?.IsInvalid != false) - return false; - - bool result = false; - Kernel32.STORAGE_QUERY_BUFFER nptwb = Kernel32.CreateStruct(); - nptwb.ProtocolSpecific.ProtocolType = Kernel32.STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; - nptwb.ProtocolSpecific.DataType = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; - nptwb.ProtocolSpecific.ProtocolDataRequestValue = (uint)Kernel32.NVME_LOG_PAGES.NVME_LOG_PAGE_HEALTH_INFO; - nptwb.ProtocolSpecific.ProtocolDataOffset = (uint)Marshal.SizeOf(); - nptwb.ProtocolSpecific.ProtocolDataLength = (uint)nptwb.Buffer.Length; - nptwb.PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; - nptwb.QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery; - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(nptwb, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - //map NVME_HEALTH_INFO_LOG to nptwb.Buffer - IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.STORAGE_QUERY_BUFFER.Buffer)); - var newPtr = IntPtr.Add(buffer, offset.ToInt32()); - data = Marshal.PtrToStructure(newPtr); - Marshal.FreeHGlobal(buffer); - result = true; - } - else - { - Marshal.FreeHGlobal(buffer); - } - - return result; - } - - public static SafeHandle IdentifyDevice(StorageInfo storageInfo) - { - SafeHandle handle = Kernel32.OpenDevice(storageInfo.DeviceId); - if (handle?.IsInvalid != false) - return null; - - Kernel32.STORAGE_QUERY_BUFFER nptwb = Kernel32.CreateStruct(); - nptwb.ProtocolSpecific.ProtocolType = Kernel32.STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; - nptwb.ProtocolSpecific.DataType = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeIdentify; - nptwb.ProtocolSpecific.ProtocolDataRequestValue = (uint)Kernel32.STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE.NVMeIdentifyCnsController; - nptwb.ProtocolSpecific.ProtocolDataOffset = (uint)Marshal.SizeOf(); - nptwb.ProtocolSpecific.ProtocolDataLength = (uint)nptwb.Buffer.Length; - nptwb.PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; - nptwb.QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery; - - int length = Marshal.SizeOf(); - IntPtr buffer = Marshal.AllocHGlobal(length); - Marshal.StructureToPtr(nptwb, buffer, false); - bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, buffer, length, buffer, length, out _, IntPtr.Zero); - if (validTransfer) - { - Marshal.FreeHGlobal(buffer); - } - else - { - Marshal.FreeHGlobal(buffer); - handle.Close(); - handle = null; - } - - return handle; - } + return IdentifyDevice(storageInfo); } -} + + public bool IdentifyController(SafeHandle hDevice, out Kernel32.NVME_IDENTIFY_CONTROLLER_DATA data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + Kernel32.STORAGE_QUERY_BUFFER nptwb = Kernel32.CreateStruct(); + nptwb.ProtocolSpecific.ProtocolType = Kernel32.STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; + nptwb.ProtocolSpecific.DataType = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeIdentify; + nptwb.ProtocolSpecific.ProtocolDataRequestValue = (uint)Kernel32.STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE.NVMeIdentifyCnsController; + nptwb.ProtocolSpecific.ProtocolDataOffset = (uint)Marshal.SizeOf(); + nptwb.ProtocolSpecific.ProtocolDataLength = (uint)nptwb.Buffer.Length; + nptwb.PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; + nptwb.QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery; + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(nptwb, buffer, false); + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) + { + //map NVME_IDENTIFY_CONTROLLER_DATA to nptwb.Buffer + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.STORAGE_QUERY_BUFFER.Buffer)); + var newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = Marshal.PtrToStructure(newPtr); + Marshal.FreeHGlobal(buffer); + result = true; + } + else + { + Marshal.FreeHGlobal(buffer); + } + + return result; + } + + public bool HealthInfoLog(SafeHandle hDevice, out Kernel32.NVME_HEALTH_INFO_LOG data) + { + data = Kernel32.CreateStruct(); + if (hDevice?.IsInvalid != false) + return false; + + bool result = false; + Kernel32.STORAGE_QUERY_BUFFER nptwb = Kernel32.CreateStruct(); + nptwb.ProtocolSpecific.ProtocolType = Kernel32.STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; + nptwb.ProtocolSpecific.DataType = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeLogPage; + nptwb.ProtocolSpecific.ProtocolDataRequestValue = (uint)Kernel32.NVME_LOG_PAGES.NVME_LOG_PAGE_HEALTH_INFO; + nptwb.ProtocolSpecific.ProtocolDataOffset = (uint)Marshal.SizeOf(); + nptwb.ProtocolSpecific.ProtocolDataLength = (uint)nptwb.Buffer.Length; + nptwb.PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; + nptwb.QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery; + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(nptwb, buffer, false); + bool validTransfer = Kernel32.DeviceIoControl(hDevice, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) + { + //map NVME_HEALTH_INFO_LOG to nptwb.Buffer + IntPtr offset = Marshal.OffsetOf(nameof(Kernel32.STORAGE_QUERY_BUFFER.Buffer)); + var newPtr = IntPtr.Add(buffer, offset.ToInt32()); + data = Marshal.PtrToStructure(newPtr); + Marshal.FreeHGlobal(buffer); + result = true; + } + else + { + Marshal.FreeHGlobal(buffer); + } + + return result; + } + + public static SafeHandle IdentifyDevice(StorageInfo storageInfo) + { + SafeHandle handle = Kernel32.OpenDevice(storageInfo.DeviceId); + if (handle?.IsInvalid != false) + return null; + + Kernel32.STORAGE_QUERY_BUFFER nptwb = Kernel32.CreateStruct(); + nptwb.ProtocolSpecific.ProtocolType = Kernel32.STORAGE_PROTOCOL_TYPE.ProtocolTypeNvme; + nptwb.ProtocolSpecific.DataType = (uint)Kernel32.STORAGE_PROTOCOL_NVME_DATA_TYPE.NVMeDataTypeIdentify; + nptwb.ProtocolSpecific.ProtocolDataRequestValue = (uint)Kernel32.STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE.NVMeIdentifyCnsController; + nptwb.ProtocolSpecific.ProtocolDataOffset = (uint)Marshal.SizeOf(); + nptwb.ProtocolSpecific.ProtocolDataLength = (uint)nptwb.Buffer.Length; + nptwb.PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageAdapterProtocolSpecificProperty; + nptwb.QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery; + + int length = Marshal.SizeOf(); + IntPtr buffer = Marshal.AllocHGlobal(length); + Marshal.StructureToPtr(nptwb, buffer, false); + bool validTransfer = Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, buffer, length, buffer, length, out _, IntPtr.Zero); + if (validTransfer) + { + Marshal.FreeHGlobal(buffer); + } + else + { + Marshal.FreeHGlobal(buffer); + handle.Close(); + handle = null; + } + + return handle; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/NamePrefixAttribute.cs b/LibreHardwareMonitorLib/Hardware/Storage/NamePrefixAttribute.cs index f07f927..fa94076 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/NamePrefixAttribute.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/NamePrefixAttribute.cs @@ -6,16 +6,15 @@ using System; -namespace LibreHardwareMonitor.Hardware.Storage -{ - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - internal class NamePrefixAttribute : Attribute - { - public NamePrefixAttribute(string namePrefix) - { - Prefix = namePrefix; - } +namespace LibreHardwareMonitor.Hardware.Storage; - public string Prefix { get; } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +internal class NamePrefixAttribute : Attribute +{ + public NamePrefixAttribute(string namePrefix) + { + Prefix = namePrefix; } -} + + public string Prefix { get; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/RequireSmartAttribute.cs b/LibreHardwareMonitorLib/Hardware/Storage/RequireSmartAttribute.cs index d821a29..c16aff5 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/RequireSmartAttribute.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/RequireSmartAttribute.cs @@ -6,16 +6,15 @@ using System; -namespace LibreHardwareMonitor.Hardware.Storage -{ - [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] - internal class RequireSmartAttribute : Attribute - { - public RequireSmartAttribute(byte attributeId) - { - AttributeId = attributeId; - } +namespace LibreHardwareMonitor.Hardware.Storage; - public byte AttributeId { get; } +[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)] +internal class RequireSmartAttribute : Attribute +{ + public RequireSmartAttribute(byte attributeId) + { + AttributeId = attributeId; } -} + + public byte AttributeId { get; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs b/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs index c403a04..d55df41 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SmartAttribute.cs @@ -7,97 +7,96 @@ using System.Collections.Generic; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +public class SmartAttribute { - public class SmartAttribute + private readonly RawValueConversion _rawValueConversion; + + public delegate float RawValueConversion(byte[] rawValue, byte value, IReadOnlyList parameters); + + /// + /// Initializes a new instance of the class. + /// + /// The SMART id of the attribute. + /// The name of the attribute. + public SmartAttribute(byte id, string name) : this(id, name, null, null, 0, null) + { } + + /// + /// Initializes a new instance of the class. + /// + /// The SMART id of the attribute. + /// The name of the attribute. + /// + /// A delegate for converting the raw byte + /// array into a value (or null to use the attribute value). + /// + public SmartAttribute(byte id, string name, RawValueConversion rawValueConversion) : this(id, name, rawValueConversion, null, 0, null) + { } + + /// + /// Initializes a new instance of the class. + /// + /// The SMART id of the attribute. + /// The name of the attribute. + /// + /// A delegate for converting the raw byte + /// array into a value (or null to use the attribute value). + /// + /// + /// Type of the sensor or null if no sensor is to + /// be created. + /// + /// + /// If there exists more than one attribute with + /// the same sensor channel and type, then a sensor is created only for the + /// first attribute. + /// + /// + /// The name to be used for the sensor, or null if + /// no sensor is created. + /// + /// True to hide the sensor initially. + /// + /// Description for the parameters of the sensor + /// (or null). + /// + public SmartAttribute(byte id, string name, RawValueConversion rawValueConversion, SensorType? sensorType, int sensorChannel, string sensorName, bool defaultHiddenSensor = false, ParameterDescription[] parameterDescriptions = null) { - private readonly RawValueConversion _rawValueConversion; - - public delegate float RawValueConversion(byte[] rawValue, byte value, IReadOnlyList parameters); - - /// - /// Initializes a new instance of the class. - /// - /// The SMART id of the attribute. - /// The name of the attribute. - public SmartAttribute(byte id, string name) : this(id, name, null, null, 0, null) - { } - - /// - /// Initializes a new instance of the class. - /// - /// The SMART id of the attribute. - /// The name of the attribute. - /// - /// A delegate for converting the raw byte - /// array into a value (or null to use the attribute value). - /// - public SmartAttribute(byte id, string name, RawValueConversion rawValueConversion) : this(id, name, rawValueConversion, null, 0, null) - { } - - /// - /// Initializes a new instance of the class. - /// - /// The SMART id of the attribute. - /// The name of the attribute. - /// - /// A delegate for converting the raw byte - /// array into a value (or null to use the attribute value). - /// - /// - /// Type of the sensor or null if no sensor is to - /// be created. - /// - /// - /// If there exists more than one attribute with - /// the same sensor channel and type, then a sensor is created only for the - /// first attribute. - /// - /// - /// The name to be used for the sensor, or null if - /// no sensor is created. - /// - /// True to hide the sensor initially. - /// - /// Description for the parameters of the sensor - /// (or null). - /// - public SmartAttribute(byte id, string name, RawValueConversion rawValueConversion, SensorType? sensorType, int sensorChannel, string sensorName, bool defaultHiddenSensor = false, ParameterDescription[] parameterDescriptions = null) - { - Id = id; - Name = name; - _rawValueConversion = rawValueConversion; - SensorType = sensorType; - SensorChannel = sensorChannel; - SensorName = sensorName; - DefaultHiddenSensor = defaultHiddenSensor; - ParameterDescriptions = parameterDescriptions; - } - - public bool DefaultHiddenSensor { get; } - - public bool HasRawValueConversion => _rawValueConversion != null; - - /// - /// Gets the SMART identifier. - /// - public byte Id { get; } - - public string Name { get; } - - public ParameterDescription[] ParameterDescriptions { get; } - - public int SensorChannel { get; } - - public string SensorName { get; } - - public SensorType? SensorType { get; } - - internal float ConvertValue(Kernel32.SMART_ATTRIBUTE value, IReadOnlyList parameters) - { - if (_rawValueConversion == null) - return value.CurrentValue; - return _rawValueConversion(value.RawValue, value.CurrentValue, parameters); - } + Id = id; + Name = name; + _rawValueConversion = rawValueConversion; + SensorType = sensorType; + SensorChannel = sensorChannel; + SensorName = sensorName; + DefaultHiddenSensor = defaultHiddenSensor; + ParameterDescriptions = parameterDescriptions; } -} + + public bool DefaultHiddenSensor { get; } + + public bool HasRawValueConversion => _rawValueConversion != null; + + /// + /// Gets the SMART identifier. + /// + public byte Id { get; } + + public string Name { get; } + + public ParameterDescription[] ParameterDescriptions { get; } + + public int SensorChannel { get; } + + public string SensorName { get; } + + public SensorType? SensorType { get; } + + internal float ConvertValue(Kernel32.SMART_ATTRIBUTE value, IReadOnlyList parameters) + { + if (_rawValueConversion == null) + return value.CurrentValue; + return _rawValueConversion(value.RawValue, value.CurrentValue, parameters); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs b/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs index 09ee32b..6fbce31 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SmartNames.cs @@ -4,261 +4,260 @@ // Partial Copyright (C) Michael Möller and Contributors. // All Rights Reserved. -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +/// +/// Localization class for SMART attribute names. +/// +public static class SmartNames { - /// - /// Localization class for SMART attribute names. - /// - public static class SmartNames - { - public static string AirflowTemperature => "Airflow Temperature"; + public static string AirflowTemperature => "Airflow Temperature"; - public static string AlternativeEraseFailCount => "Alternative Erase Fail Count"; + public static string AlternativeEraseFailCount => "Alternative Erase Fail Count"; - public static string AlternativeGSenseErrorRate => "Alternative G-Sense Error Rate"; + public static string AlternativeGSenseErrorRate => "Alternative G-Sense Error Rate"; - public static string AlternativeProgramFailCount => "Alternative Program Fail Count"; + public static string AlternativeProgramFailCount => "Alternative Program Fail Count"; - public static string AvailableReservedSpace => "Available Reserved Space"; + public static string AvailableReservedSpace => "Available Reserved Space"; - public static string AverageEraseCount => "Average Erase Count"; + public static string AverageEraseCount => "Average Erase Count"; - public static string BadBlockFullFlag => "Bad Block Full Flag"; + public static string BadBlockFullFlag => "Bad Block Full Flag"; - public static string BitErrors => "Bit Errors"; + public static string BitErrors => "Bit Errors"; - public static string CalibrationRetryCount => "Calibration Retry Count"; + public static string CalibrationRetryCount => "Calibration Retry Count"; - public static string CommandTimeout => "Command Timeout"; + public static string CommandTimeout => "Command Timeout"; - public static string ControllerWritesToNand => "Controller Writes to NAND"; + public static string ControllerWritesToNand => "Controller Writes to NAND"; - public static string CorrectedErrors => "Corrected Errors"; + public static string CorrectedErrors => "Corrected Errors"; - public static string CrcErrorCount => "CRC Error Count"; + public static string CrcErrorCount => "CRC Error Count"; - public static string CurrentPendingSectorCount => "Current Pending Sector Count"; + public static string CurrentPendingSectorCount => "Current Pending Sector Count"; - public static string DataAddressMarkErrors => "Data Address Mark errors"; + public static string DataAddressMarkErrors => "Data Address Mark errors"; - public static string DiskShift => "Disk Shift"; + public static string DiskShift => "Disk Shift"; - public static string DriveTemperature => "Drive Temperature"; + public static string DriveTemperature => "Drive Temperature"; - public static string EccRate => "ECC Rate"; + public static string EccRate => "ECC Rate"; - public static string EmergencyRetractCycleCount => "Emergency Retract Cycle Count"; + public static string EmergencyRetractCycleCount => "Emergency Retract Cycle Count"; - public static string EndToEndError => "End-to-End error"; + public static string EndToEndError => "End-to-End error"; - public static string EnduranceRemaining => "Endurance Remaining"; + public static string EnduranceRemaining => "Endurance Remaining"; - public static string EraseFailCount => "Erase Fail Count"; + public static string EraseFailCount => "Erase Fail Count"; - public static string EraseFailCountChip => "Erase Fail Count (Chip)"; + public static string EraseFailCountChip => "Erase Fail Count (Chip)"; - public static string EraseFailCountTotal => "Erase Fail Count (Total)"; + public static string EraseFailCountTotal => "Erase Fail Count (Total)"; - public static string EraseFailure => "Erase Failure"; + public static string EraseFailure => "Erase Failure"; - public static string ErrorCorrectionCount => "Error Correction Count"; + public static string ErrorCorrectionCount => "Error Correction Count"; - public static string ExceptionModeStatus => "Exception Mode Status"; + public static string ExceptionModeStatus => "Exception Mode Status"; - public static string FactoryBadBlockCount => "Factory Bad Block Count"; + public static string FactoryBadBlockCount => "Factory Bad Block Count"; - public static string FlyingHeight => "Flying Height"; + public static string FlyingHeight => "Flying Height"; - public static string FreeFallProtection => "Free Fall Protection"; + public static string FreeFallProtection => "Free Fall Protection"; - public static string FTLProgramNANDPagesCount => "FTL Program NAND Pages Count"; + public static string FTLProgramNANDPagesCount => "FTL Program NAND Pages Count"; - public static string GmrHeadAmplitude => "GMR Head Amplitude"; + public static string GmrHeadAmplitude => "GMR Head Amplitude"; - public static string GSenseErrorRate => "G-sense Error Rate"; + public static string GSenseErrorRate => "G-sense Error Rate"; - public static string HardwareEccRecovered => "Hardware ECC Recovered"; + public static string HardwareEccRecovered => "Hardware ECC Recovered"; - public static string HeadFlyingHours => "Head Flying Hours"; + public static string HeadFlyingHours => "Head Flying Hours"; - public static string HeadStability => "Head Stability"; + public static string HeadStability => "Head Stability"; - public static string HighFlyWrites => "High Fly Writes"; + public static string HighFlyWrites => "High Fly Writes"; - public static string HostProgramNANDPagesCount => "Host Program NAND Pages Count"; + public static string HostProgramNANDPagesCount => "Host Program NAND Pages Count"; - public static string HostReads => "Host Reads"; + public static string HostReads => "Host Reads"; - public static string HostWrites => "Host Writes"; + public static string HostWrites => "Host Writes"; - public static string HostWritesToController => "Host Writes to Controller"; + public static string HostWritesToController => "Host Writes to Controller"; - public static string InducedOpVibrationDetection => "Induced Op-Vibration Detection"; + public static string InducedOpVibrationDetection => "Induced Op-Vibration Detection"; - public static string InitialBadBlockCount => "Initial Bad Block Count"; + public static string InitialBadBlockCount => "Initial Bad Block Count"; - public static string LoadCycleCount => "Load Cycle Count"; + public static string LoadCycleCount => "Load Cycle Count"; - public static string LoadedHours => "Loaded Hours"; + public static string LoadedHours => "Loaded Hours"; - public static string LoadFriction => "Load Friction"; + public static string LoadFriction => "Load Friction"; - public static string LoadInTime => "Load 'In'-time"; + public static string LoadInTime => "Load 'In'-time"; - public static string LoadUnloadCycleCount => "Load/Unload Cycle Count"; + public static string LoadUnloadCycleCount => "Load/Unload Cycle Count"; - public static string LoadUnloadCycleCountFujitsu => "Load/Unload Cycle Count (Fujitus)"; + public static string LoadUnloadCycleCountFujitsu => "Load/Unload Cycle Count (Fujitus)"; - public static string LoadUnloadRetryCount => "Load/Unload Retry Count"; + public static string LoadUnloadRetryCount => "Load/Unload Retry Count"; - public static string MaxCellCycles => "Max Cell Cycles"; + public static string MaxCellCycles => "Max Cell Cycles"; - public static string MaxErase => "Max Erase"; + public static string MaxErase => "Max Erase"; - public static string MediaWearOutIndicator => "Media Wear Out Indicator"; + public static string MediaWearOutIndicator => "Media Wear Out Indicator"; - public static string MinErase => "Min Erase"; + public static string MinErase => "Min Erase"; - public static string MultiZoneErrorRate => "Multi-Zone Error Rate"; + public static string MultiZoneErrorRate => "Multi-Zone Error Rate"; - public static string NewFailingBlockCount => "New Failing Block Count"; + public static string NewFailingBlockCount => "New Failing Block Count"; - public static string Non4KAlignedAccess => "Non-4k Aligned Access"; + public static string Non4KAlignedAccess => "Non-4k Aligned Access"; - public static string OfflineSeekPerformance => "Offline Seek Performance"; + public static string OfflineSeekPerformance => "Offline Seek Performance"; - public static string OffLineUncorrectableErrorCount => "Off-Line Uncorrectable Error Count"; + public static string OffLineUncorrectableErrorCount => "Off-Line Uncorrectable Error Count"; - public static string PowerCycleCount => "Power Cycle Count"; + public static string PowerCycleCount => "Power Cycle Count"; - public static string PowerOffRetractCycle => "Power-Off Retract Cycle"; + public static string PowerOffRetractCycle => "Power-Off Retract Cycle"; - public static string PowerOnHours => "Power-On Hours (POH)"; + public static string PowerOnHours => "Power-On Hours (POH)"; - public static string PowerRecoveryCount => "Power Recovery Count"; + public static string PowerRecoveryCount => "Power Recovery Count"; - public static string ProgramFailCount => "Program Fail Count"; + public static string ProgramFailCount => "Program Fail Count"; - public static string ProgramFailCountChip => "Program Fail Count (Chip)"; + public static string ProgramFailCountChip => "Program Fail Count (Chip)"; - public static string ProgramFailCountTotal => "Program Fail Count (Total)"; + public static string ProgramFailCountTotal => "Program Fail Count (Total)"; - public static string ProgramFailure => "Program Failure"; + public static string ProgramFailure => "Program Failure"; - public static string RawReadErrorRate => "Raw Read Error Rate"; + public static string RawReadErrorRate => "Raw Read Error Rate"; - public static string ReadChannelMargin => "Read Channel Margin"; + public static string ReadChannelMargin => "Read Channel Margin"; - public static string ReadCommands => "Read Commands"; + public static string ReadCommands => "Read Commands"; - public static string ReadErrorRate => "Read Error Rate"; + public static string ReadErrorRate => "Read Error Rate"; - public static string ReadErrorRetryRate => "Read Error Retry Rate"; + public static string ReadErrorRetryRate => "Read Error Retry Rate"; - public static string ReadFailure => "Read Failure"; + public static string ReadFailure => "Read Failure"; - public static string ReallocatedNANDBlockCount => "Reallocated NAND Block Count"; + public static string ReallocatedNANDBlockCount => "Reallocated NAND Block Count"; - public static string ReallocatedSectorsCount => "Reallocated Sectors Count"; + public static string ReallocatedSectorsCount => "Reallocated Sectors Count"; - public static string ReallocationEventCount => "Reallocation Event Count"; + public static string ReallocationEventCount => "Reallocation Event Count"; - public static string RecalibrationRetries => "Recalibration Retries"; + public static string RecalibrationRetries => "Recalibration Retries"; - public static string RemainingLife => "Remaining Life"; + public static string RemainingLife => "Remaining Life"; - public static string ReportedUncorrectableErrors => "Reported Uncorrectable Errors"; + public static string ReportedUncorrectableErrors => "Reported Uncorrectable Errors"; - public static string RetiredBlockCount => "Retired Block Count"; + public static string RetiredBlockCount => "Retired Block Count"; - public static string RunOutCancel => "Run Out Cancel"; + public static string RunOutCancel => "Run Out Cancel"; - public static string RuntimeBadBlockTotal => "Runtime Bad Block Total"; + public static string RuntimeBadBlockTotal => "Runtime Bad Block Total"; - public static string SataDownshiftErrorCount => "SATA Downshift Error Count"; + public static string SataDownshiftErrorCount => "SATA Downshift Error Count"; - public static string SataErrorCountCrc => "SATA Error Count CRC"; + public static string SataErrorCountCrc => "SATA Error Count CRC"; - public static string SataErrorCountHandshake => "SATA Error Count Handshake"; + public static string SataErrorCountHandshake => "SATA Error Count Handshake"; - public static string SectorsRead => "Sectors Read"; + public static string SectorsRead => "Sectors Read"; - public static string SectorsWritten => "Sectors Written"; + public static string SectorsWritten => "Sectors Written"; - public static string SeekErrorRate => "Seek Error Rate"; + public static string SeekErrorRate => "Seek Error Rate"; - public static string SeekTimePerformance => "Seek Time Performance"; + public static string SeekTimePerformance => "Seek Time Performance"; - public static string ShockDuringWrite => "Shock During Write"; + public static string ShockDuringWrite => "Shock During Write"; - public static string SoftEccCorrection => "Soft ECC Correction"; + public static string SoftEccCorrection => "Soft ECC Correction"; - public static string SoftReadErrorRate => "Soft Read Error Rate"; + public static string SoftReadErrorRate => "Soft Read Error Rate"; - public static string SpinBuzz => "Spin Buzz"; + public static string SpinBuzz => "Spin Buzz"; - public static string SpinHighCurrent => "Spin High Current"; + public static string SpinHighCurrent => "Spin High Current"; - public static string SpinRetryCount => "Spin Retry Count"; + public static string SpinRetryCount => "Spin Retry Count"; - public static string SpinUpTime => "Spin-Up Time"; + public static string SpinUpTime => "Spin-Up Time"; - public static string StartStopCount => "Start/Stop Count"; + public static string StartStopCount => "Start/Stop Count"; - public static string SuccessfulRAINRecoveryCount => "Successful RAIN Recovery Count"; + public static string SuccessfulRAINRecoveryCount => "Successful RAIN Recovery Count"; - public static string SupercapStatus => "Supercap Status"; + public static string SupercapStatus => "Supercap Status"; - public static string TaCounterDetected => "TA Counter Detected"; + public static string TaCounterDetected => "TA Counter Detected"; - public static string Temperature => "Temperature"; + public static string Temperature => "Temperature"; - public static string TemperatureDifferenceFrom100 => "Temperature Difference from 100"; + public static string TemperatureDifferenceFrom100 => "Temperature Difference from 100"; - public static string TemperatureExceedCount => "Temperature Exceed Count"; + public static string TemperatureExceedCount => "Temperature Exceed Count"; - public static string ThermalAsperityRate => "Thermal Asperity Rate (TAR)"; + public static string ThermalAsperityRate => "Thermal Asperity Rate (TAR)"; - public static string ThroughputPerformance => "Throughput Performance"; + public static string ThroughputPerformance => "Throughput Performance"; - public static string TorqueAmplificationCount => "Torque Amplification Count"; + public static string TorqueAmplificationCount => "Torque Amplification Count"; - public static string TotalLbasRead => "Total LBAs Read"; + public static string TotalLbasRead => "Total LBAs Read"; - public static string TotalLbasWritten => "Total LBAs Written"; + public static string TotalLbasWritten => "Total LBAs Written"; - public static string TransferErrorRate => "Transfer Error Rate"; + public static string TransferErrorRate => "Transfer Error Rate"; - public static string UltraDmaCrcErrorCount => "UltraDMA CRC Error Count"; + public static string UltraDmaCrcErrorCount => "UltraDMA CRC Error Count"; - public static string UncorrectableErrorCount => "Uncorrectable Error Count"; + public static string UncorrectableErrorCount => "Uncorrectable Error Count"; - public static string UncorrectableSectorCount => "Uncorrectable Sector Count"; + public static string UncorrectableSectorCount => "Uncorrectable Sector Count"; - public static string UnexpectedPowerLossCount => "Unexpected Power Loss Count"; + public static string UnexpectedPowerLossCount => "Unexpected Power Loss Count"; - public static string Unknown => "Unknown"; + public static string Unknown => "Unknown"; - public static string UnknownUnique => "Unknown Unique"; + public static string UnknownUnique => "Unknown Unique"; - public static string UnrecoverableEcc => "Unrecoverable ECC"; + public static string UnrecoverableEcc => "Unrecoverable ECC"; - public static string UnsafeShutdownCount => "Unsafe Shutdown Count"; + public static string UnsafeShutdownCount => "Unsafe Shutdown Count"; - public static string UnusedReserveNANDBlocks => "Unused Reserve NAND Blocks"; + public static string UnusedReserveNANDBlocks => "Unused Reserve NAND Blocks"; - public static string UsedReservedBlockCountChip => "Used Reserved Block Count (Chip)"; + public static string UsedReservedBlockCountChip => "Used Reserved Block Count (Chip)"; - public static string UsedReservedBlockCountTotal => "Used Reserved Block Count (Total)"; + public static string UsedReservedBlockCountTotal => "Used Reserved Block Count (Total)"; - public static string VibrationDuringWrite => "Vibration During Write"; + public static string VibrationDuringWrite => "Vibration During Write"; - public static string WearLevelingCount => "Wear Leveling Count"; + public static string WearLevelingCount => "Wear Leveling Count"; - public static string WearRangeDelta => "Wear Range Delta"; + public static string WearRangeDelta => "Wear Range Delta"; - public static string WriteCommands => "Write Commands"; + public static string WriteCommands => "Write Commands"; - public static string WriteErrorRate => "Write Error Rate"; - } -} + public static string WriteErrorRate => "Write Error Rate"; +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs index 49ff3a1..3f69875 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdIndilinx.cs @@ -6,39 +6,38 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Storage -{ - [NamePrefix(""), RequireSmart(0x01), RequireSmart(0x09), RequireSmart(0x0C), RequireSmart(0xD1), RequireSmart(0xCE), RequireSmart(0xCF)] - internal class SsdIndilinx : AtaStorage - { - private static readonly IReadOnlyList _smartAttributes = new List - { - new(0x01, SmartNames.ReadErrorRate), - new(0x09, SmartNames.PowerOnHours), - new(0x0C, SmartNames.PowerCycleCount), - new(0xB8, SmartNames.InitialBadBlockCount), - new(0xC3, SmartNames.ProgramFailure), - new(0xC4, SmartNames.EraseFailure), - new(0xC5, SmartNames.ReadFailure), - new(0xC6, SmartNames.SectorsRead), - new(0xC7, SmartNames.SectorsWritten), - new(0xC8, SmartNames.ReadCommands), - new(0xC9, SmartNames.WriteCommands), - new(0xCA, SmartNames.BitErrors), - new(0xCB, SmartNames.CorrectedErrors), - new(0xCC, SmartNames.BadBlockFullFlag), - new(0xCD, SmartNames.MaxCellCycles), - new(0xCE, SmartNames.MinErase), - new(0xCF, SmartNames.MaxErase), - new(0xD0, SmartNames.AverageEraseCount), - new(0xD1, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), - new(0xD2, SmartNames.UnknownUnique), - new(0xD3, SmartNames.SataErrorCountCrc), - new(0xD4, SmartNames.SataErrorCountHandshake) - }; +namespace LibreHardwareMonitor.Hardware.Storage; - public SsdIndilinx(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) - { } - } +[NamePrefix(""), RequireSmart(0x01), RequireSmart(0x09), RequireSmart(0x0C), RequireSmart(0xD1), RequireSmart(0xCE), RequireSmart(0xCF)] +internal class SsdIndilinx : AtaStorage +{ + private static readonly IReadOnlyList _smartAttributes = new List + { + new(0x01, SmartNames.ReadErrorRate), + new(0x09, SmartNames.PowerOnHours), + new(0x0C, SmartNames.PowerCycleCount), + new(0xB8, SmartNames.InitialBadBlockCount), + new(0xC3, SmartNames.ProgramFailure), + new(0xC4, SmartNames.EraseFailure), + new(0xC5, SmartNames.ReadFailure), + new(0xC6, SmartNames.SectorsRead), + new(0xC7, SmartNames.SectorsWritten), + new(0xC8, SmartNames.ReadCommands), + new(0xC9, SmartNames.WriteCommands), + new(0xCA, SmartNames.BitErrors), + new(0xCB, SmartNames.CorrectedErrors), + new(0xCC, SmartNames.BadBlockFullFlag), + new(0xCD, SmartNames.MaxCellCycles), + new(0xCE, SmartNames.MinErase), + new(0xCF, SmartNames.MaxErase), + new(0xD0, SmartNames.AverageEraseCount), + new(0xD1, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), + new(0xD2, SmartNames.UnknownUnique), + new(0xD3, SmartNames.SataErrorCountCrc), + new(0xD4, SmartNames.SataErrorCountHandshake) + }; + + public SsdIndilinx(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs index 20d52da..8c09f09 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdIntel.cs @@ -6,45 +6,44 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Storage -{ - [NamePrefix("INTEL SSD"), RequireSmart(0xE1), RequireSmart(0xE8), RequireSmart(0xE9)] - internal class SsdIntel : AtaStorage - { - private static readonly IReadOnlyList _smartAttributes = new List - { - new(0x01, SmartNames.ReadErrorRate), - new(0x03, SmartNames.SpinUpTime), - new(0x04, SmartNames.StartStopCount, RawToInt), - new(0x05, SmartNames.ReallocatedSectorsCount), - new(0x09, SmartNames.PowerOnHours, RawToInt), - new(0x0C, SmartNames.PowerCycleCount, RawToInt), - new(0xAA, SmartNames.AvailableReservedSpace), - new(0xAB, SmartNames.ProgramFailCount), - new(0xAC, SmartNames.EraseFailCount), - new(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), - new(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), - new(0xB8, SmartNames.EndToEndError), - new(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), - new(0xBE, - SmartNames.Temperature, - (r, _, p) => r[0] + (p?[0].Value ?? 0), - SensorType.Temperature, - 0, - SmartNames.AirflowTemperature, - false, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), - new(0xC0, SmartNames.UnsafeShutdownCount), - new(0xC7, SmartNames.CrcErrorCount, RawToInt), - new(0xE1, SmartNames.HostWrites, (r, v, p) => RawToInt(r, v, p) / 0x20, SensorType.Data, 0, SmartNames.HostWrites), - new(0xE8, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), - new(0xE9, SmartNames.MediaWearOutIndicator), - new(0xF1, SmartNames.HostWrites, (r, v, p) => RawToInt(r, v, p) / 0x20, SensorType.Data, 0, SmartNames.HostWrites), - new(0xF2, SmartNames.HostReads, (r, v, p) => RawToInt(r, v, p) / 0x20, SensorType.Data, 1, SmartNames.HostReads) - }; +namespace LibreHardwareMonitor.Hardware.Storage; - public SsdIntel(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) - { } - } +[NamePrefix("INTEL SSD"), RequireSmart(0xE1), RequireSmart(0xE8), RequireSmart(0xE9)] +internal class SsdIntel : AtaStorage +{ + private static readonly IReadOnlyList _smartAttributes = new List + { + new(0x01, SmartNames.ReadErrorRate), + new(0x03, SmartNames.SpinUpTime), + new(0x04, SmartNames.StartStopCount, RawToInt), + new(0x05, SmartNames.ReallocatedSectorsCount), + new(0x09, SmartNames.PowerOnHours, RawToInt), + new(0x0C, SmartNames.PowerCycleCount, RawToInt), + new(0xAA, SmartNames.AvailableReservedSpace), + new(0xAB, SmartNames.ProgramFailCount), + new(0xAC, SmartNames.EraseFailCount), + new(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), + new(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), + new(0xB8, SmartNames.EndToEndError), + new(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), + new(0xBE, + SmartNames.Temperature, + (r, _, p) => r[0] + (p?[0].Value ?? 0), + SensorType.Temperature, + 0, + SmartNames.AirflowTemperature, + false, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), + new(0xC0, SmartNames.UnsafeShutdownCount), + new(0xC7, SmartNames.CrcErrorCount, RawToInt), + new(0xE1, SmartNames.HostWrites, (r, v, p) => RawToInt(r, v, p) / 0x20, SensorType.Data, 0, SmartNames.HostWrites), + new(0xE8, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), + new(0xE9, SmartNames.MediaWearOutIndicator), + new(0xF1, SmartNames.HostWrites, (r, v, p) => RawToInt(r, v, p) / 0x20, SensorType.Data, 0, SmartNames.HostWrites), + new(0xF2, SmartNames.HostReads, (r, v, p) => RawToInt(r, v, p) / 0x20, SensorType.Data, 1, SmartNames.HostReads) + }; + + public SsdIntel(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs index c8c68e7..5db2477 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdMicron.cs @@ -7,109 +7,108 @@ using System.Collections.Generic; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +[NamePrefix(""), RequireSmart(0xAB), RequireSmart(0xAC), RequireSmart(0xAD), RequireSmart(0xAE), RequireSmart(0xC4), RequireSmart(0xCA), RequireSmart(0xCE)] +internal class SsdMicron : AtaStorage { - [NamePrefix(""), RequireSmart(0xAB), RequireSmart(0xAC), RequireSmart(0xAD), RequireSmart(0xAE), RequireSmart(0xC4), RequireSmart(0xCA), RequireSmart(0xCE)] - internal class SsdMicron : AtaStorage + private static readonly IReadOnlyList _smartAttributes = new List { - private static readonly IReadOnlyList _smartAttributes = new List + new(0x01, SmartNames.ReadErrorRate, RawToInt), + new(0x05, SmartNames.ReallocatedNANDBlockCount, RawToInt), + new(0x09, SmartNames.PowerOnHours, RawToInt), + new(0x0C, SmartNames.PowerCycleCount, RawToInt), + new(0xAA, SmartNames.NewFailingBlockCount, RawToInt), + new(0xAB, SmartNames.ProgramFailCount, RawToInt), + new(0xAC, SmartNames.EraseFailCount, RawToInt), + new(0xAD, SmartNames.WearLevelingCount, RawToInt), + new(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), + new(0xB4, SmartNames.UnusedReserveNANDBlocks, RawToInt), + new(0xB5, SmartNames.Non4KAlignedAccess, (raw, _, _) => 6e4f * ((raw[5] << 8) | raw[4])), + new(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), + new(0xB8, SmartNames.ErrorCorrectionCount, RawToInt), + new(0xBB, SmartNames.ReportedUncorrectableErrors, RawToInt), + new(0xBC, SmartNames.CommandTimeout, RawToInt), + new(0xBD, SmartNames.FactoryBadBlockCount, RawToInt), + new(0xC2, SmartNames.Temperature, RawToInt), + new(0xC4, SmartNames.ReallocationEventCount, RawToInt), + new(0xC5, SmartNames.CurrentPendingSectorCount), + new(0xC6, SmartNames.OffLineUncorrectableErrorCount, RawToInt), + new(0xC7, SmartNames.UltraDmaCrcErrorCount, RawToInt), + new(0xCA, SmartNames.RemainingLife, (raw, value, p) => 100 - RawToInt(raw, value, p), SensorType.Level, 0, SmartNames.RemainingLife), + new(0xCE, SmartNames.WriteErrorRate, (raw, _, _) => 6e4f * ((raw[1] << 8) | raw[0])), + new(0xD2, SmartNames.SuccessfulRAINRecoveryCount, RawToInt), + new(0xF6, + SmartNames.TotalLbasWritten, + (r, _, _) => (((long)r[5] << 40) | + ((long)r[4] << 32) | + ((long)r[3] << 24) | + ((long)r[2] << 16) | + ((long)r[1] << 8) | + r[0]) * + (512.0f / 1024 / 1024 / 1024), + SensorType.Data, + 0, + "Total Bytes Written"), + new(0xF7, SmartNames.HostProgramNANDPagesCount, RawToInt), + new(0xF8, SmartNames.FTLProgramNANDPagesCount, RawToInt) + }; + + private readonly Sensor _temperature; + private readonly Sensor _writeAmplification; + + public SsdMicron(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { + _temperature = new Sensor("Temperature", + 0, + false, + SensorType.Temperature, + this, + new[] + { + new ParameterDescription("Offset [°C]", + "Temperature offset of the thermal sensor.\n" + + "Temperature = Value + Offset.", + 0) + }, + settings); + + _writeAmplification = new Sensor("Write Amplification", + 0, + SensorType.Factor, + this, + settings); + } + + /// + protected override void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) + { + float? hostProgramPagesCount = null; + float? ftlProgramPagesCount = null; + + foreach (Kernel32.SMART_ATTRIBUTE value in values) { - new(0x01, SmartNames.ReadErrorRate, RawToInt), - new(0x05, SmartNames.ReallocatedNANDBlockCount, RawToInt), - new(0x09, SmartNames.PowerOnHours, RawToInt), - new(0x0C, SmartNames.PowerCycleCount, RawToInt), - new(0xAA, SmartNames.NewFailingBlockCount, RawToInt), - new(0xAB, SmartNames.ProgramFailCount, RawToInt), - new(0xAC, SmartNames.EraseFailCount, RawToInt), - new(0xAD, SmartNames.WearLevelingCount, RawToInt), - new(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), - new(0xB4, SmartNames.UnusedReserveNANDBlocks, RawToInt), - new(0xB5, SmartNames.Non4KAlignedAccess, (raw, _, _) => 6e4f * ((raw[5] << 8) | raw[4])), - new(0xB7, SmartNames.SataDownshiftErrorCount, RawToInt), - new(0xB8, SmartNames.ErrorCorrectionCount, RawToInt), - new(0xBB, SmartNames.ReportedUncorrectableErrors, RawToInt), - new(0xBC, SmartNames.CommandTimeout, RawToInt), - new(0xBD, SmartNames.FactoryBadBlockCount, RawToInt), - new(0xC2, SmartNames.Temperature, RawToInt), - new(0xC4, SmartNames.ReallocationEventCount, RawToInt), - new(0xC5, SmartNames.CurrentPendingSectorCount), - new(0xC6, SmartNames.OffLineUncorrectableErrorCount, RawToInt), - new(0xC7, SmartNames.UltraDmaCrcErrorCount, RawToInt), - new(0xCA, SmartNames.RemainingLife, (raw, value, p) => 100 - RawToInt(raw, value, p), SensorType.Level, 0, SmartNames.RemainingLife), - new(0xCE, SmartNames.WriteErrorRate, (raw, _, _) => 6e4f * ((raw[1] << 8) | raw[0])), - new(0xD2, SmartNames.SuccessfulRAINRecoveryCount, RawToInt), - new(0xF6, - SmartNames.TotalLbasWritten, - (r, _, _) => (((long)r[5] << 40) | - ((long)r[4] << 32) | - ((long)r[3] << 24) | - ((long)r[2] << 16) | - ((long)r[1] << 8) | - r[0]) * - (512.0f / 1024 / 1024 / 1024), - SensorType.Data, - 0, - "Total Bytes Written"), - new(0xF7, SmartNames.HostProgramNANDPagesCount, RawToInt), - new(0xF8, SmartNames.FTLProgramNANDPagesCount, RawToInt) - }; + if (value.Id == 0xF7) + hostProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); - private readonly Sensor _temperature; - private readonly Sensor _writeAmplification; + if (value.Id == 0xF8) + ftlProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); - public SsdMicron(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) - { - _temperature = new Sensor("Temperature", - 0, - false, - SensorType.Temperature, - this, - new[] - { - new ParameterDescription("Offset [°C]", - "Temperature offset of the thermal sensor.\n" + - "Temperature = Value + Offset.", - 0) - }, - settings); + if (value.Id == 0xC2) + { + _temperature.Value = value.RawValue[0] + _temperature.Parameters[0].Value; - _writeAmplification = new Sensor("Write Amplification", - 0, - SensorType.Factor, - this, - settings); + if (value.RawValue[0] != 0) + ActivateSensor(_temperature); + } } - /// - protected override void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) + if (hostProgramPagesCount.HasValue && ftlProgramPagesCount.HasValue) { - float? hostProgramPagesCount = null; - float? ftlProgramPagesCount = null; + _writeAmplification.Value = hostProgramPagesCount.Value > 0 ? (hostProgramPagesCount.Value + ftlProgramPagesCount) / hostProgramPagesCount.Value : 0; - foreach (Kernel32.SMART_ATTRIBUTE value in values) - { - if (value.Id == 0xF7) - hostProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); - - if (value.Id == 0xF8) - ftlProgramPagesCount = RawToInt(value.RawValue, value.CurrentValue, null); - - if (value.Id == 0xC2) - { - _temperature.Value = value.RawValue[0] + _temperature.Parameters[0].Value; - - if (value.RawValue[0] != 0) - ActivateSensor(_temperature); - } - } - - if (hostProgramPagesCount.HasValue && ftlProgramPagesCount.HasValue) - { - _writeAmplification.Value = hostProgramPagesCount.Value > 0 ? (hostProgramPagesCount.Value + ftlProgramPagesCount) / hostProgramPagesCount.Value : 0; - - ActivateSensor(_writeAmplification); - } + ActivateSensor(_writeAmplification); } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs index 438ca47..361e5af 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdPlextor.cs @@ -6,26 +6,25 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +[NamePrefix("PLEXTOR")] +internal class SsdPlextor : AtaStorage { - [NamePrefix("PLEXTOR")] - internal class SsdPlextor : AtaStorage + private static readonly IReadOnlyList _smartAttributes = new List { - private static readonly IReadOnlyList _smartAttributes = new List - { - new(0x09, SmartNames.PowerOnHours, RawToInt), - new(0x0C, SmartNames.PowerCycleCount, RawToInt), - new(0xF1, SmartNames.HostWrites, RawToGb, SensorType.Data, 0, SmartNames.HostWrites), - new(0xF2, SmartNames.HostReads, RawToGb, SensorType.Data, 1, SmartNames.HostReads) - }; + new(0x09, SmartNames.PowerOnHours, RawToInt), + new(0x0C, SmartNames.PowerCycleCount, RawToInt), + new(0xF1, SmartNames.HostWrites, RawToGb, SensorType.Data, 0, SmartNames.HostWrites), + new(0xF2, SmartNames.HostReads, RawToGb, SensorType.Data, 1, SmartNames.HostReads) + }; - public SsdPlextor(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) - { } + public SsdPlextor(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } - private static float RawToGb(byte[] rawValue, byte value, IReadOnlyList parameters) - { - return RawToInt(rawValue, value, parameters) / 32; - } + private static float RawToGb(byte[] rawValue, byte value, IReadOnlyList parameters) + { + return RawToInt(rawValue, value, parameters) / 32; } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs index cb62d6a..73492d2 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdSamsung.cs @@ -6,53 +6,52 @@ using System.Collections.Generic; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +[NamePrefix(""), RequireSmart(0xB1), RequireSmart(0xB3), RequireSmart(0xB5), RequireSmart(0xB6), RequireSmart(0xB7), RequireSmart(0xBB), RequireSmart(0xC3), RequireSmart(0xC7)] +internal class SsdSamsung : AtaStorage { - [NamePrefix(""), RequireSmart(0xB1), RequireSmart(0xB3), RequireSmart(0xB5), RequireSmart(0xB6), RequireSmart(0xB7), RequireSmart(0xBB), RequireSmart(0xC3), RequireSmart(0xC7)] - internal class SsdSamsung : AtaStorage + private static readonly IReadOnlyList _smartAttributes = new List { - private static readonly IReadOnlyList _smartAttributes = new List - { - new(0x05, SmartNames.ReallocatedSectorsCount), - new(0x09, SmartNames.PowerOnHours, RawToInt), - new(0x0C, SmartNames.PowerCycleCount, RawToInt), - new(0xAF, SmartNames.ProgramFailCountChip, RawToInt), - new(0xB0, SmartNames.EraseFailCountChip, RawToInt), - new(0xB1, SmartNames.WearLevelingCount, RawToInt), - new(0xB2, SmartNames.UsedReservedBlockCountChip, RawToInt), - new(0xB3, SmartNames.UsedReservedBlockCountTotal, RawToInt), + new(0x05, SmartNames.ReallocatedSectorsCount), + new(0x09, SmartNames.PowerOnHours, RawToInt), + new(0x0C, SmartNames.PowerCycleCount, RawToInt), + new(0xAF, SmartNames.ProgramFailCountChip, RawToInt), + new(0xB0, SmartNames.EraseFailCountChip, RawToInt), + new(0xB1, SmartNames.WearLevelingCount, RawToInt), + new(0xB2, SmartNames.UsedReservedBlockCountChip, RawToInt), + new(0xB3, SmartNames.UsedReservedBlockCountTotal, RawToInt), - // Unused Reserved Block Count (Total) - new(0xB4, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), - new(0xB5, SmartNames.ProgramFailCountTotal, RawToInt), - new(0xB6, SmartNames.EraseFailCountTotal, RawToInt), - new(0xB7, SmartNames.RuntimeBadBlockTotal, RawToInt), - new(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), - new(0xBE, - SmartNames.Temperature, - (r, _, p) => r[0] + (p?[0].Value ?? 0), - SensorType.Temperature, - 0, - SmartNames.Temperature, - false, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), - new(0xC2, SmartNames.AirflowTemperature), - new(0xC3, SmartNames.EccRate), - new(0xC6, SmartNames.OffLineUncorrectableErrorCount, RawToInt), - new(0xC7, SmartNames.CrcErrorCount, RawToInt), - new(0xC9, SmartNames.SupercapStatus), - new(0xCA, SmartNames.ExceptionModeStatus), - new(0xEB, SmartNames.PowerRecoveryCount), - new(0xF1, - SmartNames.TotalLbasWritten, - (r, _, _) => (((long)r[5] << 40) | ((long)r[4] << 32) | ((long)r[3] << 24) | ((long)r[2] << 16) | ((long)r[1] << 8) | r[0]) * (512.0f / 1024 / 1024 / 1024), - SensorType.Data, - 0, - "Total Bytes Written") - }; + // Unused Reserved Block Count (Total) + new(0xB4, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), + new(0xB5, SmartNames.ProgramFailCountTotal, RawToInt), + new(0xB6, SmartNames.EraseFailCountTotal, RawToInt), + new(0xB7, SmartNames.RuntimeBadBlockTotal, RawToInt), + new(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), + new(0xBE, + SmartNames.Temperature, + (r, _, p) => r[0] + (p?[0].Value ?? 0), + SensorType.Temperature, + 0, + SmartNames.Temperature, + false, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), + new(0xC2, SmartNames.AirflowTemperature), + new(0xC3, SmartNames.EccRate), + new(0xC6, SmartNames.OffLineUncorrectableErrorCount, RawToInt), + new(0xC7, SmartNames.CrcErrorCount, RawToInt), + new(0xC9, SmartNames.SupercapStatus), + new(0xCA, SmartNames.ExceptionModeStatus), + new(0xEB, SmartNames.PowerRecoveryCount), + new(0xF1, + SmartNames.TotalLbasWritten, + (r, _, _) => (((long)r[5] << 40) | ((long)r[4] << 32) | ((long)r[3] << 24) | ((long)r[2] << 16) | ((long)r[1] << 8) | r[0]) * (512.0f / 1024 / 1024 / 1024), + SensorType.Data, + 0, + "Total Bytes Written") + }; - public SsdSamsung(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) - { } - } + public SsdSamsung(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs b/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs index 5122fda..5e16353 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/SsdSandforce.cs @@ -7,71 +7,70 @@ using System.Collections.Generic; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +[NamePrefix(""), RequireSmart(0xAB), RequireSmart(0xB1)] +internal class SsdSandforce : AtaStorage { - [NamePrefix(""), RequireSmart(0xAB), RequireSmart(0xB1)] - internal class SsdSandforce : AtaStorage + private static readonly IReadOnlyList _smartAttributes = new List { - private static readonly IReadOnlyList _smartAttributes = new List - { - new(0x01, SmartNames.RawReadErrorRate), - new(0x05, SmartNames.RetiredBlockCount, RawToInt), - new(0x09, SmartNames.PowerOnHours, RawToInt), - new(0x0C, SmartNames.PowerCycleCount, RawToInt), - new(0xAB, SmartNames.ProgramFailCount, RawToInt), - new(0xAC, SmartNames.EraseFailCount, RawToInt), - new(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), - new(0xB1, SmartNames.WearRangeDelta, RawToInt), - new(0xB5, SmartNames.AlternativeProgramFailCount, RawToInt), - new(0xB6, SmartNames.AlternativeEraseFailCount, RawToInt), - new(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), - new(0xC2, - SmartNames.Temperature, - (_, value, p) => value + (p?[0].Value ?? 0), - SensorType.Temperature, - 0, - SmartNames.Temperature, - true, - new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), - new(0xC3, SmartNames.UnrecoverableEcc), - new(0xC4, SmartNames.ReallocationEventCount, RawToInt), - new(0xE7, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), - new(0xE9, SmartNames.ControllerWritesToNand, RawToInt, SensorType.Data, 0, SmartNames.ControllerWritesToNand), - new(0xEA, SmartNames.HostWritesToController, RawToInt, SensorType.Data, 1, SmartNames.HostWritesToController), - new(0xF1, SmartNames.HostWrites, RawToInt, SensorType.Data, 1, SmartNames.HostWrites), - new(0xF2, SmartNames.HostReads, RawToInt, SensorType.Data, 2, SmartNames.HostReads) - }; + new(0x01, SmartNames.RawReadErrorRate), + new(0x05, SmartNames.RetiredBlockCount, RawToInt), + new(0x09, SmartNames.PowerOnHours, RawToInt), + new(0x0C, SmartNames.PowerCycleCount, RawToInt), + new(0xAB, SmartNames.ProgramFailCount, RawToInt), + new(0xAC, SmartNames.EraseFailCount, RawToInt), + new(0xAE, SmartNames.UnexpectedPowerLossCount, RawToInt), + new(0xB1, SmartNames.WearRangeDelta, RawToInt), + new(0xB5, SmartNames.AlternativeProgramFailCount, RawToInt), + new(0xB6, SmartNames.AlternativeEraseFailCount, RawToInt), + new(0xBB, SmartNames.UncorrectableErrorCount, RawToInt), + new(0xC2, + SmartNames.Temperature, + (_, value, p) => value + (p?[0].Value ?? 0), + SensorType.Temperature, + 0, + SmartNames.Temperature, + true, + new[] { new ParameterDescription("Offset [°C]", "Temperature offset of the thermal sensor.\nTemperature = Value + Offset.", 0) }), + new(0xC3, SmartNames.UnrecoverableEcc), + new(0xC4, SmartNames.ReallocationEventCount, RawToInt), + new(0xE7, SmartNames.RemainingLife, null, SensorType.Level, 0, SmartNames.RemainingLife), + new(0xE9, SmartNames.ControllerWritesToNand, RawToInt, SensorType.Data, 0, SmartNames.ControllerWritesToNand), + new(0xEA, SmartNames.HostWritesToController, RawToInt, SensorType.Data, 1, SmartNames.HostWritesToController), + new(0xF1, SmartNames.HostWrites, RawToInt, SensorType.Data, 1, SmartNames.HostWrites), + new(0xF2, SmartNames.HostReads, RawToInt, SensorType.Data, 2, SmartNames.HostReads) + }; - private readonly Sensor _writeAmplification; + private readonly Sensor _writeAmplification; - public SsdSandforce(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + public SsdSandforce(StorageInfo storageInfo, ISmart smart, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, smart, name, firmwareRevision, "ssd", index, _smartAttributes, settings) + { + _writeAmplification = new Sensor("Write Amplification", 1, SensorType.Factor, this, settings); + } + + protected override void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) + { + float? controllerWritesToNand = null; + float? hostWritesToController = null; + foreach (Kernel32.SMART_ATTRIBUTE value in values) { - _writeAmplification = new Sensor("Write Amplification", 1, SensorType.Factor, this, settings); + if (value.Id == 0xE9) + controllerWritesToNand = RawToInt(value.RawValue, value.CurrentValue, null); + + if (value.Id == 0xEA) + hostWritesToController = RawToInt(value.RawValue, value.CurrentValue, null); } - protected override void UpdateAdditionalSensors(Kernel32.SMART_ATTRIBUTE[] values) + if (controllerWritesToNand.HasValue && hostWritesToController.HasValue) { - float? controllerWritesToNand = null; - float? hostWritesToController = null; - foreach (Kernel32.SMART_ATTRIBUTE value in values) - { - if (value.Id == 0xE9) - controllerWritesToNand = RawToInt(value.RawValue, value.CurrentValue, null); + if (hostWritesToController.Value > 0) + _writeAmplification.Value = controllerWritesToNand.Value / hostWritesToController.Value; + else + _writeAmplification.Value = 0; - if (value.Id == 0xEA) - hostWritesToController = RawToInt(value.RawValue, value.CurrentValue, null); - } - - if (controllerWritesToNand.HasValue && hostWritesToController.HasValue) - { - if (hostWritesToController.Value > 0) - _writeAmplification.Value = controllerWritesToNand.Value / hostWritesToController.Value; - else - _writeAmplification.Value = 0; - - ActivateSensor(_writeAmplification); - } + ActivateSensor(_writeAmplification); } } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/StorageGeneric.cs b/LibreHardwareMonitorLib/Hardware/Storage/StorageGeneric.cs index 634ef92..980966c 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/StorageGeneric.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/StorageGeneric.cs @@ -6,25 +6,24 @@ using System.Text; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal sealed class StorageGeneric : AbstractStorage { - internal sealed class StorageGeneric : AbstractStorage + private StorageGeneric(StorageInfo storageInfo, string name, string firmwareRevision, int index, ISettings settings) + : base(storageInfo, name, firmwareRevision, "hdd", index, settings) { - private StorageGeneric(StorageInfo storageInfo, string name, string firmwareRevision, int index, ISettings settings) - : base(storageInfo, name, firmwareRevision, "hdd", index, settings) - { - CreateSensors(); - } - - public static AbstractStorage CreateInstance(StorageInfo info, ISettings settings) - { - string name = string.IsNullOrEmpty(info.Name) ? "Generic Hard Disk" : info.Name; - string firmwareRevision = string.IsNullOrEmpty(info.Revision) ? "Unknown" : info.Revision; - return new StorageGeneric(info, name, firmwareRevision, info.Index, settings); - } - - protected override void UpdateSensors() { } - - protected override void GetReport(StringBuilder r) { } + CreateSensors(); } -} + + public static AbstractStorage CreateInstance(StorageInfo info, ISettings settings) + { + string name = string.IsNullOrEmpty(info.Name) ? "Generic Hard Disk" : info.Name; + string firmwareRevision = string.IsNullOrEmpty(info.Revision) ? "Unknown" : info.Revision; + return new StorageGeneric(info, name, firmwareRevision, info.Index, settings); + } + + protected override void UpdateSensors() { } + + protected override void GetReport(StringBuilder r) { } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs index d060cb6..b3e039b 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/StorageGroup.cs @@ -8,48 +8,47 @@ using System; using System.Collections.Generic; using System.Management; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal class StorageGroup : IGroup { - internal class StorageGroup : IGroup + private readonly List _hardware = new(); + + public StorageGroup(ISettings settings) { - private readonly List _hardware = new(); + if (Software.OperatingSystem.IsUnix) + return; - public StorageGroup(ISettings settings) + //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskdrive + using var diskDriveSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive") { Options = { Timeout = TimeSpan.FromSeconds(10) } }; + foreach (ManagementBaseObject diskDrive in diskDriveSearcher.Get()) { - if (Software.OperatingSystem.IsUnix) - return; + string deviceId = (string)diskDrive.Properties["DeviceId"].Value; // is \\.\PhysicalDrive0..n + uint idx = Convert.ToUInt32(diskDrive.Properties["Index"].Value); + ulong diskSize = Convert.ToUInt64(diskDrive.Properties["Size"].Value); + int scsi = Convert.ToInt32(diskDrive.Properties["SCSIPort"].Value); - //https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-diskdrive - using var diskDriveSearcher = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive") { Options = { Timeout = TimeSpan.FromSeconds(10) } }; - foreach (ManagementBaseObject diskDrive in diskDriveSearcher.Get()) + if (deviceId != null) { - string deviceId = (string)diskDrive.Properties["DeviceId"].Value; // is \\.\PhysicalDrive0..n - uint idx = Convert.ToUInt32(diskDrive.Properties["Index"].Value); - ulong diskSize = Convert.ToUInt64(diskDrive.Properties["Size"].Value); - int scsi = Convert.ToInt32(diskDrive.Properties["SCSIPort"].Value); - - if (deviceId != null) + var instance = AbstractStorage.CreateInstance(deviceId, idx, diskSize, scsi, settings); + if (instance != null) { - var instance = AbstractStorage.CreateInstance(deviceId, idx, diskSize, scsi, settings); - if (instance != null) - { - _hardware.Add(instance); - } + _hardware.Add(instance); } } } - - public IReadOnlyList Hardware => _hardware; - - public string GetReport() - { - return null; - } - - public void Close() - { - foreach (AbstractStorage storage in _hardware) - storage.Close(); - } } -} + + public IReadOnlyList Hardware => _hardware; + + public string GetReport() + { + return null; + } + + public void Close() + { + foreach (AbstractStorage storage in _hardware) + storage.Close(); + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/StorageInfo.cs b/LibreHardwareMonitorLib/Hardware/Storage/StorageInfo.cs index 912a6f4..9971eaa 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/StorageInfo.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/StorageInfo.cs @@ -6,32 +6,31 @@ using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal abstract class StorageInfo { - internal abstract class StorageInfo - { - public Kernel32.STORAGE_BUS_TYPE BusType { get; protected set; } + public Kernel32.STORAGE_BUS_TYPE BusType { get; protected set; } - public string DeviceId { get; set; } + public string DeviceId { get; set; } - public ulong DiskSize { get; set; } + public ulong DiskSize { get; set; } - public int Index { get; protected set; } + public int Index { get; protected set; } - public string Name => (Vendor + " " + Product).Trim(); + public string Name => (Vendor + " " + Product).Trim(); - public string Product { get; protected set; } + public string Product { get; protected set; } - public byte[] RawData { get; protected set; } + public byte[] RawData { get; protected set; } - public bool Removable { get; protected set; } + public bool Removable { get; protected set; } - public string Revision { get; protected set; } + public string Revision { get; protected set; } - public string Scsi { get; set; } + public string Scsi { get; set; } - public string Serial { get; protected set; } + public string Serial { get; protected set; } - public string Vendor { get; protected set; } - } -} + public string Vendor { get; protected set; } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs b/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs index e4d6ba4..b21a5d0 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/WindowsSmart.cs @@ -10,176 +10,175 @@ using System.IO; using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal class WindowsSmart : ISmart { - internal class WindowsSmart : ISmart + private readonly int _driveNumber; + private readonly SafeHandle _handle; + + public WindowsSmart(int driveNumber) { - private readonly int _driveNumber; - private readonly SafeHandle _handle; + _driveNumber = driveNumber; + _handle = Kernel32.CreateFile(@"\\.\PhysicalDrive" + driveNumber, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); + } - public WindowsSmart(int driveNumber) + public bool IsValid => !_handle.IsInvalid && !_handle.IsClosed; + + public void Dispose() + { + Close(); + } + + public void Close() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + public bool EnableSmart() + { + if (_handle.IsClosed) + throw new ObjectDisposedException(nameof(WindowsSmart)); + + var parameter = new Kernel32.SENDCMDINPARAMS { - _driveNumber = driveNumber; - _handle = Kernel32.CreateFile(@"\\.\PhysicalDrive" + driveNumber, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); - } + bDriveNumber = (byte)_driveNumber, + irDriveRegs = { bFeaturesReg = Kernel32.SMART_FEATURES.ENABLE_SMART, bCylLowReg = Kernel32.SMART_LBA_MID, bCylHighReg = Kernel32.SMART_LBA_HI, bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART} + }; - public bool IsValid => !_handle.IsInvalid && !_handle.IsClosed; + return Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_SEND_DRIVE_COMMAND, ref parameter, Marshal.SizeOf(parameter), + out Kernel32.SENDCMDOUTPARAMS _, Marshal.SizeOf(), out _, IntPtr.Zero); + } - public void Dispose() + public Kernel32.SMART_ATTRIBUTE[] ReadSmartData() + { + if (_handle.IsClosed) + throw new ObjectDisposedException(nameof(WindowsSmart)); + + var parameter = new Kernel32.SENDCMDINPARAMS { - Close(); - } - - public void Close() - { - Dispose(true); - GC.SuppressFinalize(this); - } - - public bool EnableSmart() - { - if (_handle.IsClosed) - throw new ObjectDisposedException(nameof(WindowsSmart)); - - var parameter = new Kernel32.SENDCMDINPARAMS - { - bDriveNumber = (byte)_driveNumber, - irDriveRegs = { bFeaturesReg = Kernel32.SMART_FEATURES.ENABLE_SMART, bCylLowReg = Kernel32.SMART_LBA_MID, bCylHighReg = Kernel32.SMART_LBA_HI, bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART} - }; - - return Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_SEND_DRIVE_COMMAND, ref parameter, Marshal.SizeOf(parameter), - out Kernel32.SENDCMDOUTPARAMS _, Marshal.SizeOf(), out _, IntPtr.Zero); - } - - public Kernel32.SMART_ATTRIBUTE[] ReadSmartData() - { - if (_handle.IsClosed) - throw new ObjectDisposedException(nameof(WindowsSmart)); - - var parameter = new Kernel32.SENDCMDINPARAMS - { - bDriveNumber = (byte)_driveNumber, irDriveRegs = { - bFeaturesReg = Kernel32.SMART_FEATURES.SMART_READ_DATA, - bCylLowReg = Kernel32.SMART_LBA_MID, - bCylHighReg = Kernel32.SMART_LBA_HI, - bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART - } - }; - - bool isValid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, ref parameter, Marshal.SizeOf(parameter), - out Kernel32.ATTRIBUTECMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); - - return isValid ? result.Attributes : Array.Empty(); - } - - public Kernel32.SMART_THRESHOLD[] ReadSmartThresholds() - { - if (_handle.IsClosed) - throw new ObjectDisposedException(nameof(WindowsSmart)); - - var parameter = new Kernel32.SENDCMDINPARAMS - { - bDriveNumber = (byte)_driveNumber, irDriveRegs = { - bFeaturesReg = Kernel32.SMART_FEATURES.READ_THRESHOLDS, - bCylLowReg = Kernel32.SMART_LBA_MID, - bCylHighReg = Kernel32.SMART_LBA_HI, - bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART - } - }; - - bool isValid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, ref parameter, Marshal.SizeOf(parameter), - out Kernel32.THRESHOLDCMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); - - return isValid ? result.Thresholds : Array.Empty(); - } - - public bool ReadNameAndFirmwareRevision(out string name, out string firmwareRevision) - { - if (_handle.IsClosed) - throw new ObjectDisposedException(nameof(WindowsSmart)); - - var parameter = new Kernel32.SENDCMDINPARAMS - { - bDriveNumber = (byte)_driveNumber, - irDriveRegs = { bCommandReg = Kernel32.ATA_COMMAND.ATA_IDENTIFY_DEVICE } - }; - - bool valid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, ref parameter, Marshal.SizeOf(parameter), - out Kernel32.IDENTIFYCMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); - - if (!valid) - { - name = null; - firmwareRevision = null; - return false; + bDriveNumber = (byte)_driveNumber, irDriveRegs = { + bFeaturesReg = Kernel32.SMART_FEATURES.SMART_READ_DATA, + bCylLowReg = Kernel32.SMART_LBA_MID, + bCylHighReg = Kernel32.SMART_LBA_HI, + bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART } + }; - name = GetString(result.Identify.ModelNumber); - firmwareRevision = GetString(result.Identify.FirmwareRevision); - return true; + bool isValid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, ref parameter, Marshal.SizeOf(parameter), + out Kernel32.ATTRIBUTECMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); + + return isValid ? result.Attributes : Array.Empty(); + } + + public Kernel32.SMART_THRESHOLD[] ReadSmartThresholds() + { + if (_handle.IsClosed) + throw new ObjectDisposedException(nameof(WindowsSmart)); + + var parameter = new Kernel32.SENDCMDINPARAMS + { + bDriveNumber = (byte)_driveNumber, irDriveRegs = { + bFeaturesReg = Kernel32.SMART_FEATURES.READ_THRESHOLDS, + bCylLowReg = Kernel32.SMART_LBA_MID, + bCylHighReg = Kernel32.SMART_LBA_HI, + bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART + } + }; + + bool isValid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, ref parameter, Marshal.SizeOf(parameter), + out Kernel32.THRESHOLDCMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); + + return isValid ? result.Thresholds : Array.Empty(); + } + + public bool ReadNameAndFirmwareRevision(out string name, out string firmwareRevision) + { + if (_handle.IsClosed) + throw new ObjectDisposedException(nameof(WindowsSmart)); + + var parameter = new Kernel32.SENDCMDINPARAMS + { + bDriveNumber = (byte)_driveNumber, + irDriveRegs = { bCommandReg = Kernel32.ATA_COMMAND.ATA_IDENTIFY_DEVICE } + }; + + bool valid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_RECEIVE_DRIVE_DATA, ref parameter, Marshal.SizeOf(parameter), + out Kernel32.IDENTIFYCMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); + + if (!valid) + { + name = null; + firmwareRevision = null; + return false; } - /// - /// Reads Smart health status of the drive - /// - /// True, if drive is healthy; False, if unhealthy; Null, if it cannot be read - public bool? ReadSmartHealth() + name = GetString(result.Identify.ModelNumber); + firmwareRevision = GetString(result.Identify.FirmwareRevision); + return true; + } + + /// + /// Reads Smart health status of the drive + /// + /// True, if drive is healthy; False, if unhealthy; Null, if it cannot be read + public bool? ReadSmartHealth() + { + if (_handle.IsClosed) + throw new ObjectDisposedException(nameof(WindowsSmart)); + + var parameter = new Kernel32.SENDCMDINPARAMS { - if (_handle.IsClosed) - throw new ObjectDisposedException(nameof(WindowsSmart)); - - var parameter = new Kernel32.SENDCMDINPARAMS - { - bDriveNumber = (byte)_driveNumber, - irDriveRegs = { - bFeaturesReg = Kernel32.SMART_FEATURES.RETURN_SMART_STATUS, - bCylLowReg = Kernel32.SMART_LBA_MID, - bCylHighReg = Kernel32.SMART_LBA_HI, - bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART - } - }; - - bool isValid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_SEND_DRIVE_COMMAND, ref parameter, Marshal.SizeOf(parameter), - out Kernel32.STATUSCMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); - - if (!isValid) - { - return null; + bDriveNumber = (byte)_driveNumber, + irDriveRegs = { + bFeaturesReg = Kernel32.SMART_FEATURES.RETURN_SMART_STATUS, + bCylLowReg = Kernel32.SMART_LBA_MID, + bCylHighReg = Kernel32.SMART_LBA_HI, + bCommandReg = Kernel32.ATA_COMMAND.ATA_SMART } + }; - // reference: https://github.com/smartmontools/smartmontools/blob/master/smartmontools/atacmds.cpp - if (Kernel32.SMART_LBA_HI == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID == result.irDriveRegs.bCylLowReg) - { - // high and mid registers are unchanged, which means that the drive is healthy - return true; - } + bool isValid = Kernel32.DeviceIoControl(_handle, Kernel32.DFP.DFP_SEND_DRIVE_COMMAND, ref parameter, Marshal.SizeOf(parameter), + out Kernel32.STATUSCMDOUTPARAMS result, Marshal.SizeOf(), out _, IntPtr.Zero); - if (Kernel32.SMART_LBA_HI_EXCEEDED == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID_EXCEEDED == result.irDriveRegs.bCylLowReg) - { - // high and mid registers are exceeded, which means that the drive is unhealthy - return false; - } - // response is not clear + if (!isValid) + { return null; } - protected void Dispose(bool disposing) + // reference: https://github.com/smartmontools/smartmontools/blob/master/smartmontools/atacmds.cpp + if (Kernel32.SMART_LBA_HI == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID == result.irDriveRegs.bCylLowReg) { - if (disposing && !_handle.IsClosed) - { - _handle.Close(); - } + // high and mid registers are unchanged, which means that the drive is healthy + return true; } - private static string GetString(IReadOnlyList bytes) + if (Kernel32.SMART_LBA_HI_EXCEEDED == result.irDriveRegs.bCylHighReg && Kernel32.SMART_LBA_MID_EXCEEDED == result.irDriveRegs.bCylLowReg) { - char[] chars = new char[bytes.Count]; - for (int i = 0; i < bytes.Count; i += 2) - { - chars[i] = (char)bytes[i + 1]; - chars[i + 1] = (char)bytes[i]; - } - return new string(chars).Trim(' ', '\0'); + // high and mid registers are exceeded, which means that the drive is unhealthy + return false; + } + // response is not clear + return null; + } + + protected void Dispose(bool disposing) + { + if (disposing && !_handle.IsClosed) + { + _handle.Close(); } } + + private static string GetString(IReadOnlyList bytes) + { + char[] chars = new char[bytes.Count]; + for (int i = 0; i < bytes.Count; i += 2) + { + chars[i] = (char)bytes[i + 1]; + chars[i + 1] = (char)bytes[i]; + } + return new string(chars).Trim(' ', '\0'); + } } diff --git a/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs b/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs index a6502f6..378acde 100644 --- a/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs +++ b/LibreHardwareMonitorLib/Hardware/Storage/WindowsStorage.cs @@ -9,90 +9,89 @@ using System.Management; using System.Runtime.InteropServices; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware.Storage +namespace LibreHardwareMonitor.Hardware.Storage; + +internal static class WindowsStorage { - internal static class WindowsStorage + public static Storage.StorageInfo GetStorageInfo(string deviceId, uint driveIndex) { - public static Storage.StorageInfo GetStorageInfo(string deviceId, uint driveIndex) + using SafeHandle handle = Kernel32.OpenDevice(deviceId); + if (handle?.IsInvalid != false) + return null; + + var query = new Kernel32.STORAGE_PROPERTY_QUERY { PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageDeviceProperty, QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery }; + + if (!Kernel32.DeviceIoControl(handle, + Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, + ref query, + Marshal.SizeOf(query), + out Kernel32.STORAGE_DEVICE_DESCRIPTOR_HEADER header, + Marshal.SizeOf(), + out _, + IntPtr.Zero)) { - using SafeHandle handle = Kernel32.OpenDevice(deviceId); - if (handle?.IsInvalid != false) - return null; - - var query = new Kernel32.STORAGE_PROPERTY_QUERY { PropertyId = Kernel32.STORAGE_PROPERTY_ID.StorageDeviceProperty, QueryType = Kernel32.STORAGE_QUERY_TYPE.PropertyStandardQuery }; - - if (!Kernel32.DeviceIoControl(handle, - Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, - ref query, - Marshal.SizeOf(query), - out Kernel32.STORAGE_DEVICE_DESCRIPTOR_HEADER header, - Marshal.SizeOf(), - out _, - IntPtr.Zero)) - { - return null; - } - - IntPtr descriptorPtr = Marshal.AllocHGlobal((int)header.Size); - try - { - if (!Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, ref query, Marshal.SizeOf(query), descriptorPtr, header.Size, out _, IntPtr.Zero)) - return null; - - return new StorageInfo((int)driveIndex, descriptorPtr); - } - finally - { - Marshal.FreeHGlobal(descriptorPtr); - } + return null; } - public static string[] GetLogicalDrives(int driveIndex) + IntPtr descriptorPtr = Marshal.AllocHGlobal((int)header.Size); + try { - var list = new List(); + if (!Kernel32.DeviceIoControl(handle, Kernel32.IOCTL.IOCTL_STORAGE_QUERY_PROPERTY, ref query, Marshal.SizeOf(query), descriptorPtr, header.Size, out _, IntPtr.Zero)) + return null; - try + return new StorageInfo((int)driveIndex, descriptorPtr); + } + finally + { + Marshal.FreeHGlobal(descriptorPtr); + } + } + + public static string[] GetLogicalDrives(int driveIndex) + { + var list = new List(); + + try + { + using var s = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DiskPartition " + "WHERE DiskIndex = " + driveIndex); + foreach (ManagementBaseObject o in s.Get()) { - using var s = new ManagementObjectSearcher("root\\CIMV2", "SELECT * FROM Win32_DiskPartition " + "WHERE DiskIndex = " + driveIndex); - foreach (ManagementBaseObject o in s.Get()) + if (o is ManagementObject dp) { - if (o is ManagementObject dp) + foreach (ManagementBaseObject ld in dp.GetRelated("Win32_LogicalDisk")) { - foreach (ManagementBaseObject ld in dp.GetRelated("Win32_LogicalDisk")) - { - list.Add(((string)ld["Name"]).TrimEnd(':')); - } + list.Add(((string)ld["Name"]).TrimEnd(':')); } } } - catch - { - // Ignored. - } - - return list.ToArray(); + } + catch + { + // Ignored. } - private class StorageInfo : Storage.StorageInfo - { - public StorageInfo(int index, IntPtr descriptorPtr) - { - Kernel32.STORAGE_DEVICE_DESCRIPTOR descriptor = Marshal.PtrToStructure(descriptorPtr); - Index = index; - Vendor = GetString(descriptorPtr, descriptor.VendorIdOffset); - Product = GetString(descriptorPtr, descriptor.ProductIdOffset); - Revision = GetString(descriptorPtr, descriptor.ProductRevisionOffset); - Serial = GetString(descriptorPtr, descriptor.SerialNumberOffset); - BusType = descriptor.BusType; - Removable = descriptor.RemovableMedia; - RawData = new byte[descriptor.Size]; - Marshal.Copy(descriptorPtr, RawData, 0, RawData.Length); - } + return list.ToArray(); + } - private static string GetString(IntPtr descriptorPtr, uint offset) - { - return offset > 0 ? Marshal.PtrToStringAnsi(new IntPtr(descriptorPtr.ToInt64() + offset))?.Trim() : string.Empty; - } + private class StorageInfo : Storage.StorageInfo + { + public StorageInfo(int index, IntPtr descriptorPtr) + { + Kernel32.STORAGE_DEVICE_DESCRIPTOR descriptor = Marshal.PtrToStructure(descriptorPtr); + Index = index; + Vendor = GetString(descriptorPtr, descriptor.VendorIdOffset); + Product = GetString(descriptorPtr, descriptor.ProductIdOffset); + Revision = GetString(descriptorPtr, descriptor.ProductRevisionOffset); + Serial = GetString(descriptorPtr, descriptor.SerialNumberOffset); + BusType = descriptor.BusType; + Removable = descriptor.RemovableMedia; + RawData = new byte[descriptor.Size]; + Marshal.Copy(descriptorPtr, RawData, 0, RawData.Length); + } + + private static string GetString(IntPtr descriptorPtr, uint offset) + { + return offset > 0 ? Marshal.PtrToStringAnsi(new IntPtr(descriptorPtr.ToInt64() + offset))?.Trim() : string.Empty; } } } diff --git a/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs b/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs index 20f1010..340af2c 100644 --- a/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs +++ b/LibreHardwareMonitorLib/Hardware/ThreadAffinity.cs @@ -7,113 +7,112 @@ using System; using LibreHardwareMonitor.Interop; -namespace LibreHardwareMonitor.Hardware +namespace LibreHardwareMonitor.Hardware; + +internal static class ThreadAffinity { - internal static class ThreadAffinity + /// + /// Initializes static members of the class. + /// + static ThreadAffinity() { - /// - /// Initializes static members of the class. - /// - static ThreadAffinity() - { - ProcessorGroupCount = Software.OperatingSystem.IsUnix ? 1 : Kernel32.GetActiveProcessorGroupCount(); + ProcessorGroupCount = Software.OperatingSystem.IsUnix ? 1 : Kernel32.GetActiveProcessorGroupCount(); - if (ProcessorGroupCount < 1) - ProcessorGroupCount = 1; + if (ProcessorGroupCount < 1) + ProcessorGroupCount = 1; + } + + /// + /// Gets the processor group count. + /// + public static int ProcessorGroupCount { get; } + + /// + /// Returns true if the is valid. + /// + /// The affinity. + /// true if the specified affinity is valid; otherwise, false. + public static bool IsValid(GroupAffinity affinity) + { + if (Software.OperatingSystem.IsUnix && affinity.Group > 0) + { + return false; } - /// - /// Gets the processor group count. - /// - public static int ProcessorGroupCount { get; } - - /// - /// Returns true if the is valid. - /// - /// The affinity. - /// true if the specified affinity is valid; otherwise, false. - public static bool IsValid(GroupAffinity affinity) + try { - if (Software.OperatingSystem.IsUnix && affinity.Group > 0) - { + GroupAffinity previousAffinity = Set(affinity); + if (previousAffinity == GroupAffinity.Undefined) return false; - } - try - { - GroupAffinity previousAffinity = Set(affinity); - if (previousAffinity == GroupAffinity.Undefined) - return false; - - Set(previousAffinity); - return true; - } - catch - { - return false; - } + Set(previousAffinity); + return true; } - - /// - /// Sets the processor group affinity for the current thread. - /// - /// The processor group affinity. - /// The previous processor group affinity. - public static GroupAffinity Set(GroupAffinity affinity) + catch { - if (affinity == GroupAffinity.Undefined) - return GroupAffinity.Undefined; - - if (Software.OperatingSystem.IsUnix) - { - if (affinity.Group > 0) - throw new ArgumentOutOfRangeException(nameof(affinity)); - - ulong result = 0; - if (LibC.sched_getaffinity(0, (IntPtr)8, ref result) != 0) - return GroupAffinity.Undefined; - - ulong mask = affinity.Mask; - if (LibC.sched_setaffinity(0, (IntPtr)8, ref mask) != 0) - return GroupAffinity.Undefined; - - return new GroupAffinity(0, result); - } - - UIntPtr uIntPtrMask; - try - { - uIntPtrMask = (UIntPtr)affinity.Mask; - } - catch (OverflowException) - { - throw new ArgumentOutOfRangeException(nameof(affinity)); - } - - var groupAffinity = new Kernel32.GROUP_AFFINITY { Group = affinity.Group, Mask = uIntPtrMask }; - - IntPtr currentThread = Kernel32.GetCurrentThread(); - - try - { - if (Kernel32.SetThreadGroupAffinity(currentThread, - ref groupAffinity, - out Kernel32.GROUP_AFFINITY previousGroupAffinity)) - { - return new GroupAffinity(previousGroupAffinity.Group, (ulong)previousGroupAffinity.Mask); - } - - return GroupAffinity.Undefined; - } - catch (EntryPointNotFoundException) - { - if (affinity.Group > 0) - throw new ArgumentOutOfRangeException(nameof(affinity)); - - ulong previous = (ulong)Kernel32.SetThreadAffinityMask(currentThread, uIntPtrMask); - - return new GroupAffinity(0, previous); - } + return false; } } -} + + /// + /// Sets the processor group affinity for the current thread. + /// + /// The processor group affinity. + /// The previous processor group affinity. + public static GroupAffinity Set(GroupAffinity affinity) + { + if (affinity == GroupAffinity.Undefined) + return GroupAffinity.Undefined; + + if (Software.OperatingSystem.IsUnix) + { + if (affinity.Group > 0) + throw new ArgumentOutOfRangeException(nameof(affinity)); + + ulong result = 0; + if (LibC.sched_getaffinity(0, (IntPtr)8, ref result) != 0) + return GroupAffinity.Undefined; + + ulong mask = affinity.Mask; + if (LibC.sched_setaffinity(0, (IntPtr)8, ref mask) != 0) + return GroupAffinity.Undefined; + + return new GroupAffinity(0, result); + } + + UIntPtr uIntPtrMask; + try + { + uIntPtrMask = (UIntPtr)affinity.Mask; + } + catch (OverflowException) + { + throw new ArgumentOutOfRangeException(nameof(affinity)); + } + + var groupAffinity = new Kernel32.GROUP_AFFINITY { Group = affinity.Group, Mask = uIntPtrMask }; + + IntPtr currentThread = Kernel32.GetCurrentThread(); + + try + { + if (Kernel32.SetThreadGroupAffinity(currentThread, + ref groupAffinity, + out Kernel32.GROUP_AFFINITY previousGroupAffinity)) + { + return new GroupAffinity(previousGroupAffinity.Group, (ulong)previousGroupAffinity.Mask); + } + + return GroupAffinity.Undefined; + } + catch (EntryPointNotFoundException) + { + if (affinity.Group > 0) + throw new ArgumentOutOfRangeException(nameof(affinity)); + + ulong previous = (ulong)Kernel32.SetThreadAffinityMask(currentThread, uIntPtrMask); + + return new GroupAffinity(0, previous); + } + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/AdvApi32.cs b/LibreHardwareMonitorLib/Interop/AdvApi32.cs index 792643a..807edfe 100644 --- a/LibreHardwareMonitorLib/Interop/AdvApi32.cs +++ b/LibreHardwareMonitorLib/Interop/AdvApi32.cs @@ -8,144 +8,143 @@ using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal class AdvApi32 { - internal class AdvApi32 + private const string DllName = "advapi32.dll"; + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, SC_MANAGER_ACCESS_MASK dwDesiredAccess); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool CloseServiceHandle(IntPtr hSCObject); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr CreateService + ( + IntPtr hSCManager, + string lpServiceName, + string lpDisplayName, + SERVICE_ACCESS_MASK dwDesiredAccess, + SERVICE_TYPE dwServiceType, + SERVICE_START dwStartType, + SERVICE_ERROR dwErrorControl, + string lpBinaryPathName, + string lpLoadOrderGroup, + string lpdwTagId, + string lpDependencies, + string lpServiceStartName, + string lpPassword); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, SERVICE_ACCESS_MASK dwDesiredAccess); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeleteService(IntPtr hService); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool StartService(IntPtr hService, uint dwNumServiceArgs, string[] lpServiceArgVectors); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus); + + [Flags] + internal enum SC_MANAGER_ACCESS_MASK : uint { - private const string DllName = "advapi32.dll"; - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr OpenSCManager(string lpMachineName, string lpDatabaseName, SC_MANAGER_ACCESS_MASK dwDesiredAccess); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool CloseServiceHandle(IntPtr hSCObject); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr CreateService - ( - IntPtr hSCManager, - string lpServiceName, - string lpDisplayName, - SERVICE_ACCESS_MASK dwDesiredAccess, - SERVICE_TYPE dwServiceType, - SERVICE_START dwStartType, - SERVICE_ERROR dwErrorControl, - string lpBinaryPathName, - string lpLoadOrderGroup, - string lpdwTagId, - string lpDependencies, - string lpServiceStartName, - string lpPassword); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, SERVICE_ACCESS_MASK dwDesiredAccess); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeleteService(IntPtr hService); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool StartService(IntPtr hService, uint dwNumServiceArgs, string[] lpServiceArgVectors); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool ControlService(IntPtr hService, SERVICE_CONTROL dwControl, ref SERVICE_STATUS lpServiceStatus); - - [Flags] - internal enum SC_MANAGER_ACCESS_MASK : uint - { - SC_MANAGER_CONNECT = 0x00001, - SC_MANAGER_CREATE_SERVICE = 0x00002, - SC_MANAGER_ENUMERATE_SERVICE = 0x00004, - SC_MANAGER_LOCK = 0x00008, - SC_MANAGER_QUERY_LOCK_STATUS = 0x00010, - SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020, - SC_MANAGER_ALL_ACCESS = 0xF003F - } - - internal enum SERVICE_ACCESS_MASK : uint - { - SERVICE_QUERY_CONFIG = 0x00001, - SERVICE_CHANGE_CONFIG = 0x00002, - SERVICE_QUERY_STATUS = 0x00004, - SERVICE_ENUMERATE_DEPENDENTS = 0x00008, - SERVICE_START = 0x00010, - SERVICE_STOP = 0x00020, - SERVICE_PAUSE_CONTINUE = 0x00040, - SERVICE_INTERROGATE = 0x00080, - SERVICE_USER_DEFINED_CONTROL = 0x00100, - SERVICE_ALL_ACCESS = 0xF01FF - } - - internal enum SERVICE_TYPE : uint - { - SERVICE_DRIVER = 0x0000000B, - SERVICE_WIN32 = 0x00000030, - SERVICE_ADAPTER = 0x00000004, - SERVICE_FILE_SYSTEM_DRIVER = 0x00000002, - SERVICE_KERNEL_DRIVER = 0x00000001, - SERVICE_RECOGNIZER_DRIVER = 0x00000008, - SERVICE_WIN32_OWN_PROCESS = 0x00000010, - SERVICE_WIN32_SHARE_PROCESS = 0x00000020, - SERVICE_USER_OWN_PROCESS = 0x00000050, - SERVICE_USER_SHARE_PROCESS = 0x00000060, - SERVICE_INTERACTIVE_PROCESS = 0x00000100 - } - - internal enum SERVICE_START : uint - { - SERVICE_BOOT_START = 0, - SERVICE_SYSTEM_START = 1, - SERVICE_AUTO_START = 2, - SERVICE_DEMAND_START = 3, - SERVICE_DISABLED = 4 - } - - internal enum SERVICE_ERROR : uint - { - SERVICE_ERROR_IGNORE = 0, - SERVICE_ERROR_NORMAL = 1, - SERVICE_ERROR_SEVERE = 2, - SERVICE_ERROR_CRITICAL = 3 - } - - internal enum SERVICE_CONTROL : uint - { - SERVICE_CONTROL_STOP = 1, - SERVICE_CONTROL_PAUSE = 2, - SERVICE_CONTROL_CONTINUE = 3, - SERVICE_CONTROL_INTERROGATE = 4, - SERVICE_CONTROL_SHUTDOWN = 5, - SERVICE_CONTROL_PARAMCHANGE = 6, - SERVICE_CONTROL_NETBINDADD = 7, - SERVICE_CONTROL_NETBINDREMOVE = 8, - SERVICE_CONTROL_NETBINDENABLE = 9, - SERVICE_CONTROL_NETBINDDISABLE = 10, - SERVICE_CONTROL_DEVICEEVENT = 11, - SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12, - SERVICE_CONTROL_POWEREVENT = 13, - SERVICE_CONTROL_SESSIONCHANGE = 14 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct SERVICE_STATUS - { - public uint dwServiceType; - public uint dwCurrentState; - public uint dwControlsAccepted; - public uint dwWin32ExitCode; - public uint dwServiceSpecificExitCode; - public uint dwCheckPoint; - public uint dwWaitHint; - } + SC_MANAGER_CONNECT = 0x00001, + SC_MANAGER_CREATE_SERVICE = 0x00002, + SC_MANAGER_ENUMERATE_SERVICE = 0x00004, + SC_MANAGER_LOCK = 0x00008, + SC_MANAGER_QUERY_LOCK_STATUS = 0x00010, + SC_MANAGER_MODIFY_BOOT_CONFIG = 0x00020, + SC_MANAGER_ALL_ACCESS = 0xF003F } -} + + internal enum SERVICE_ACCESS_MASK : uint + { + SERVICE_QUERY_CONFIG = 0x00001, + SERVICE_CHANGE_CONFIG = 0x00002, + SERVICE_QUERY_STATUS = 0x00004, + SERVICE_ENUMERATE_DEPENDENTS = 0x00008, + SERVICE_START = 0x00010, + SERVICE_STOP = 0x00020, + SERVICE_PAUSE_CONTINUE = 0x00040, + SERVICE_INTERROGATE = 0x00080, + SERVICE_USER_DEFINED_CONTROL = 0x00100, + SERVICE_ALL_ACCESS = 0xF01FF + } + + internal enum SERVICE_TYPE : uint + { + SERVICE_DRIVER = 0x0000000B, + SERVICE_WIN32 = 0x00000030, + SERVICE_ADAPTER = 0x00000004, + SERVICE_FILE_SYSTEM_DRIVER = 0x00000002, + SERVICE_KERNEL_DRIVER = 0x00000001, + SERVICE_RECOGNIZER_DRIVER = 0x00000008, + SERVICE_WIN32_OWN_PROCESS = 0x00000010, + SERVICE_WIN32_SHARE_PROCESS = 0x00000020, + SERVICE_USER_OWN_PROCESS = 0x00000050, + SERVICE_USER_SHARE_PROCESS = 0x00000060, + SERVICE_INTERACTIVE_PROCESS = 0x00000100 + } + + internal enum SERVICE_START : uint + { + SERVICE_BOOT_START = 0, + SERVICE_SYSTEM_START = 1, + SERVICE_AUTO_START = 2, + SERVICE_DEMAND_START = 3, + SERVICE_DISABLED = 4 + } + + internal enum SERVICE_ERROR : uint + { + SERVICE_ERROR_IGNORE = 0, + SERVICE_ERROR_NORMAL = 1, + SERVICE_ERROR_SEVERE = 2, + SERVICE_ERROR_CRITICAL = 3 + } + + internal enum SERVICE_CONTROL : uint + { + SERVICE_CONTROL_STOP = 1, + SERVICE_CONTROL_PAUSE = 2, + SERVICE_CONTROL_CONTINUE = 3, + SERVICE_CONTROL_INTERROGATE = 4, + SERVICE_CONTROL_SHUTDOWN = 5, + SERVICE_CONTROL_PARAMCHANGE = 6, + SERVICE_CONTROL_NETBINDADD = 7, + SERVICE_CONTROL_NETBINDREMOVE = 8, + SERVICE_CONTROL_NETBINDENABLE = 9, + SERVICE_CONTROL_NETBINDDISABLE = 10, + SERVICE_CONTROL_DEVICEEVENT = 11, + SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12, + SERVICE_CONTROL_POWEREVENT = 13, + SERVICE_CONTROL_SESSIONCHANGE = 14 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct SERVICE_STATUS + { + public uint dwServiceType; + public uint dwCurrentState; + public uint dwControlsAccepted; + public uint dwWin32ExitCode; + public uint dwServiceSpecificExitCode; + public uint dwCheckPoint; + public uint dwWaitHint; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/AtiAdlxx.cs b/LibreHardwareMonitorLib/Interop/AtiAdlxx.cs index 7dc797b..d5370dd 100644 --- a/LibreHardwareMonitorLib/Interop/AtiAdlxx.cs +++ b/LibreHardwareMonitorLib/Interop/AtiAdlxx.cs @@ -9,535 +9,534 @@ using System.Text.RegularExpressions; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class AtiAdlxx { - internal static class AtiAdlxx + public const int ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED = 1; + + public const int ADL_DL_FANCTRL_SPEED_TYPE_PERCENT = 1; + public const int ADL_DL_FANCTRL_SPEED_TYPE_RPM = 2; + + public const int ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ = 1; + public const int ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE = 2; + public const int ADL_DL_FANCTRL_SUPPORTS_RPM_READ = 4; + public const int ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE = 8; + + public const int ADL_DRIVER_OK = 0; + + public const int ADL_FALSE = 0; + + public const int ADL_MAX_ADAPTERS = 40; + public const int ADL_MAX_DEVICENAME = 32; + public const int ADL_MAX_DISPLAYS = 40; + public const int ADL_MAX_GLSYNC_PORT_LEDS = 8; + public const int ADL_MAX_GLSYNC_PORTS = 8; + public const int ADL_MAX_NUM_DISPLAYMODES = 1024; + public const int ADL_MAX_PATH = 256; + public const int ADL_TRUE = 1; + + public const int ATI_VENDOR_ID = 0x1002; + + internal const int ADL_PMLOG_MAX_SENSORS = 256; + + internal const string DllName = "atiadlxx.dll"; + + public static Context Context_Alloc = Marshal.AllocHGlobal; + + // create a Main_Memory_Alloc delegate and keep it alive + public static ADL_Main_Memory_AllocDelegate Main_Memory_Alloc = Marshal.AllocHGlobal; + + public delegate IntPtr ADL_Main_Memory_AllocDelegate(int size); + + public delegate IntPtr Context(int size); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Main_Control_Create(ADL_Main_Memory_AllocDelegate callback, int enumConnectedAdapters); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Main_Control_Destroy(); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Adapter_AdapterInfo_Get(IntPtr info, int size); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Adapter_NumberOfAdapters_Get(); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Adapter_NumberOfAdapters_Get(ref int numAdapters); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Adapter_ID_Get(int adapterIndex, out int adapterId); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Display_AdapterID_Get(int adapterIndex, out int adapterId); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Adapter_Active_Get(int adapterIndex, out int status); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive5_ODParameters_Get(int adapterIndex, out ADLODParameters parameters); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive5_CurrentActivity_Get(int iAdapterIndex, ref ADLPMActivity activity); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive5_Temperature_Get(int adapterIndex, int thermalControllerIndex, ref ADLTemperature temperature); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_OverdriveN_Temperature_Get(IntPtr context, int adapterIndex, ADLODNTemperatureType iTemperatureType, ref int temp); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive5_FanSpeed_Get(int adapterIndex, int thermalControllerIndex, ref ADLFanSpeedValue fanSpeedValue); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive5_FanSpeedInfo_Get(int adapterIndex, int thermalControllerIndex, ref ADLFanSpeedInfo fanSpeedInfo); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive5_FanSpeedToDefault_Set(int adapterIndex, int thermalControllerIndex); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive5_FanSpeed_Set(int adapterIndex, int thermalControllerIndex, ref ADLFanSpeedValue fanSpeedValue); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_OverdriveN_PerformanceStatus_Get(IntPtr context, int adapterIndex, out ADLODNPerformanceStatus performanceStatus); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Overdrive_Caps(int adapterIndex, ref int supported, ref int enabled, ref int version); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_Overdrive6_CurrentPower_Get(IntPtr context, int adapterIndex, ADLODNCurrentPowerType powerType, ref int currentValue); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_Main_Control_Create(ADL_Main_Memory_AllocDelegate callback, int connectedAdapters, ref IntPtr context); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_Main_Control_Destroy(IntPtr context); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_New_QueryPMLogData_Get(IntPtr context, int adapterIndex, ref ADLPMLogDataOutput aDLPMLogDataOutput); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL_Graphics_Versions_Get(out ADLVersionsInfo versionInfo); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_Adapter_FrameMetrics_Caps(IntPtr context, int adapterIndex, ref int supported); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_Adapter_FrameMetrics_Get(IntPtr context, int adapterIndex, int displayIndex, ref float fps); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_Adapter_FrameMetrics_Start(IntPtr context, int adapterIndex, int displayIndex); + + [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern ADLStatus ADL2_Adapter_FrameMetrics_Stop(IntPtr context, int adapterIndex, int displayIndex); + + public static bool ADL_Method_Exists(string ADL_Method) { - public const int ADL_DL_FANCTRL_FLAG_USER_DEFINED_SPEED = 1; - - public const int ADL_DL_FANCTRL_SPEED_TYPE_PERCENT = 1; - public const int ADL_DL_FANCTRL_SPEED_TYPE_RPM = 2; - - public const int ADL_DL_FANCTRL_SUPPORTS_PERCENT_READ = 1; - public const int ADL_DL_FANCTRL_SUPPORTS_PERCENT_WRITE = 2; - public const int ADL_DL_FANCTRL_SUPPORTS_RPM_READ = 4; - public const int ADL_DL_FANCTRL_SUPPORTS_RPM_WRITE = 8; - - public const int ADL_DRIVER_OK = 0; - - public const int ADL_FALSE = 0; - - public const int ADL_MAX_ADAPTERS = 40; - public const int ADL_MAX_DEVICENAME = 32; - public const int ADL_MAX_DISPLAYS = 40; - public const int ADL_MAX_GLSYNC_PORT_LEDS = 8; - public const int ADL_MAX_GLSYNC_PORTS = 8; - public const int ADL_MAX_NUM_DISPLAYMODES = 1024; - public const int ADL_MAX_PATH = 256; - public const int ADL_TRUE = 1; - - public const int ATI_VENDOR_ID = 0x1002; - - internal const int ADL_PMLOG_MAX_SENSORS = 256; - - internal const string DllName = "atiadlxx.dll"; - - public static Context Context_Alloc = Marshal.AllocHGlobal; - - // create a Main_Memory_Alloc delegate and keep it alive - public static ADL_Main_Memory_AllocDelegate Main_Memory_Alloc = Marshal.AllocHGlobal; - - public delegate IntPtr ADL_Main_Memory_AllocDelegate(int size); - - public delegate IntPtr Context(int size); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Main_Control_Create(ADL_Main_Memory_AllocDelegate callback, int enumConnectedAdapters); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Main_Control_Destroy(); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Adapter_AdapterInfo_Get(IntPtr info, int size); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Adapter_NumberOfAdapters_Get(); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Adapter_NumberOfAdapters_Get(ref int numAdapters); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Adapter_ID_Get(int adapterIndex, out int adapterId); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Display_AdapterID_Get(int adapterIndex, out int adapterId); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Adapter_Active_Get(int adapterIndex, out int status); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive5_ODParameters_Get(int adapterIndex, out ADLODParameters parameters); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive5_CurrentActivity_Get(int iAdapterIndex, ref ADLPMActivity activity); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive5_Temperature_Get(int adapterIndex, int thermalControllerIndex, ref ADLTemperature temperature); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_OverdriveN_Temperature_Get(IntPtr context, int adapterIndex, ADLODNTemperatureType iTemperatureType, ref int temp); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive5_FanSpeed_Get(int adapterIndex, int thermalControllerIndex, ref ADLFanSpeedValue fanSpeedValue); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive5_FanSpeedInfo_Get(int adapterIndex, int thermalControllerIndex, ref ADLFanSpeedInfo fanSpeedInfo); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive5_FanSpeedToDefault_Set(int adapterIndex, int thermalControllerIndex); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive5_FanSpeed_Set(int adapterIndex, int thermalControllerIndex, ref ADLFanSpeedValue fanSpeedValue); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_OverdriveN_PerformanceStatus_Get(IntPtr context, int adapterIndex, out ADLODNPerformanceStatus performanceStatus); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Overdrive_Caps(int adapterIndex, ref int supported, ref int enabled, ref int version); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_Overdrive6_CurrentPower_Get(IntPtr context, int adapterIndex, ADLODNCurrentPowerType powerType, ref int currentValue); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_Main_Control_Create(ADL_Main_Memory_AllocDelegate callback, int connectedAdapters, ref IntPtr context); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_Main_Control_Destroy(IntPtr context); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_New_QueryPMLogData_Get(IntPtr context, int adapterIndex, ref ADLPMLogDataOutput aDLPMLogDataOutput); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL_Graphics_Versions_Get(out ADLVersionsInfo versionInfo); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_Adapter_FrameMetrics_Caps(IntPtr context, int adapterIndex, ref int supported); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_Adapter_FrameMetrics_Get(IntPtr context, int adapterIndex, int displayIndex, ref float fps); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_Adapter_FrameMetrics_Start(IntPtr context, int adapterIndex, int displayIndex); - - [DllImport(DllName, CallingConvention = CallingConvention.Cdecl)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern ADLStatus ADL2_Adapter_FrameMetrics_Stop(IntPtr context, int adapterIndex, int displayIndex); - - public static bool ADL_Method_Exists(string ADL_Method) + IntPtr module = Kernel32.LoadLibrary(DllName); + if (module != IntPtr.Zero) { - IntPtr module = Kernel32.LoadLibrary(DllName); - if (module != IntPtr.Zero) - { - bool result = Kernel32.GetProcAddress(module, ADL_Method) != IntPtr.Zero; - Kernel32.FreeLibrary(module); - return result; - } - - return false; - } - - public static ADLStatus ADL_Main_Control_Create(int enumConnectedAdapters) - { - try - { - return ADL_Method_Exists(nameof(ADL_Main_Control_Create)) ? ADL_Main_Control_Create(Main_Memory_Alloc, enumConnectedAdapters) : ADLStatus.ADL_ERR; - } - catch - { - return ADLStatus.ADL_ERR; - } - } - - public static ADLStatus ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo[] info) - { - int elementSize = Marshal.SizeOf(typeof(ADLAdapterInfo)); - int size = info.Length * elementSize; - IntPtr ptr = Marshal.AllocHGlobal(size); - ADLStatus result = ADL_Adapter_AdapterInfo_Get(ptr, size); - for (int i = 0; i < info.Length; i++) - info[i] = (ADLAdapterInfo)Marshal.PtrToStructure((IntPtr)((long)ptr + (i * elementSize)), typeof(ADLAdapterInfo)); - - Marshal.FreeHGlobal(ptr); - - // the ADLAdapterInfo.VendorID field reported by ADL is wrong on - // Windows systems (parse error), so we fix this here - for (int i = 0; i < info.Length; i++) - { - // try Windows UDID format - Match m = Regex.Match(info[i].UDID, "PCI_VEN_([A-Fa-f0-9]{1,4})&.*"); - if (m.Success && m.Groups.Count == 2) - { - info[i].VendorID = Convert.ToInt32(m.Groups[1].Value, 16); - continue; - } - - // if above failed, try Unix UDID format - m = Regex.Match(info[i].UDID, "[0-9]+:[0-9]+:([0-9]+):[0-9]+:[0-9]+"); - if (m.Success && m.Groups.Count == 2) - { - info[i].VendorID = Convert.ToInt32(m.Groups[1].Value, 10); - } - } - + bool result = Kernel32.GetProcAddress(module, ADL_Method) != IntPtr.Zero; + Kernel32.FreeLibrary(module); return result; } - public static void Main_Memory_Free(IntPtr buffer) + return false; + } + + public static ADLStatus ADL_Main_Control_Create(int enumConnectedAdapters) + { + try { - if (IntPtr.Zero != buffer) - Marshal.FreeHGlobal(buffer); + return ADL_Method_Exists(nameof(ADL_Main_Control_Create)) ? ADL_Main_Control_Create(Main_Memory_Alloc, enumConnectedAdapters) : ADLStatus.ADL_ERR; } - - internal enum ADLStatus + catch { - /// - /// All OK, but need to wait. - /// - ADL_OK_WAIT = 4, - - /// - /// All OK, but need restart. - /// - ADL_OK_RESTART = 3, - - /// - /// All OK but need mode change. - /// - ADL_OK_MODE_CHANGE = 2, - - /// - /// All OK, but with warning. - /// - ADL_OK_WARNING = 1, - - /// - /// ADL function completed successfully. - /// - ADL_OK = 0, - - /// - /// Generic Error. Most likely one or more of the Escape calls to the driver - /// failed! - /// - ADL_ERR = -1, - - /// - /// ADL not initialized. - /// - ADL_ERR_NOT_INIT = -2, - - /// - /// One of the parameter passed is invalid. - /// - ADL_ERR_INVALID_PARAM = -3, - - /// - /// One of the parameter size is invalid. - /// - ADL_ERR_INVALID_PARAM_SIZE = -4, - - /// - /// Invalid ADL index passed. - /// - ADL_ERR_INVALID_ADL_IDX = -5, - - /// - /// Invalid controller index passed. - /// - ADL_ERR_INVALID_CONTROLLER_IDX = -6, - - /// - /// Invalid display index passed. - /// - ADL_ERR_INVALID_DIPLAY_IDX = -7, - - /// - /// Function not supported by the driver. - /// - ADL_ERR_NOT_SUPPORTED = -8, - - /// - /// Null Pointer error. - /// - ADL_ERR_NULL_POINTER = -9, - - /// - /// Call can't be made due to disabled adapter. - /// - ADL_ERR_DISABLED_ADAPTER = -10, - - /// - /// Invalid Callback. - /// - ADL_ERR_INVALID_CALLBACK = -11, - - /// - /// Display Resource conflict. - /// - ADL_ERR_RESOURCE_CONFLICT = -12, - - /// - /// Failed to update some of the values. Can be returned by set request that - /// include multiple values if not all values were successfully committed. - /// - ADL_ERR_SET_INCOMPLETE = -20, - - /// - /// There's no Linux XDisplay in Linux Console environment. - /// - ADL_ERR_NO_XDISPLAY = -21 - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLAdapterInfo - { - public int Size; - public int AdapterIndex; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] - public string UDID; - - public int BusNumber; - public int DeviceNumber; - public int FunctionNumber; - public int VendorID; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] - public string AdapterName; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] - public string DisplayName; - - public int Present; - public int Exist; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] - public string DriverPath; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] - public string DriverPathExt; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] - public string PNPString; - - public int OSDisplayIndex; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLODParameterRange - { - public int Min; - public int Max; - public int Step; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLODParameters - { - public int Size; - public int NumberOfPerformanceLevels; - public int ActivityReportingSupported; - public int DiscretePerformanceLevels; - public int Reserved; - public ADLODParameterRange EngineClock; - public ADLODParameterRange MemoryClock; - public ADLODParameterRange Vddc; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLPMActivity - { - public int Size; - public int EngineClock; - public int MemoryClock; - public int Vddc; - public int ActivityPercent; - public int CurrentPerformanceLevel; - public int CurrentBusSpeed; - public int CurrentBusLanes; - public int MaximumBusLanes; - public int Reserved; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLTemperature - { - public int Size; - public int Temperature; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLFanSpeedValue - { - public int Size; - public int SpeedType; - public int FanSpeed; - public int Flags; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLFanSpeedInfo - { - public int Size; - public int Flags; - public int MinPercent; - public int MaxPercent; - public int MinRPM; - public int MaxRPM; - } - - internal enum ADLODNCurrentPowerType - { - ODN_GPU_TOTAL_POWER = 0, - ODN_GPU_PPT_POWER, - ODN_GPU_SOCKET_POWER, - ODN_GPU_CHIP_POWER - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLVersionsInfo - { - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] - public string DriverVer; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] - public string CatalystVersion; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] - public string CatalystWebLink; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLODNPerformanceStatus - { - public int CoreClock; - public int MemoryClock; - public int DCEFClock; - public int GFXClock; - public int UVDClock; - public int VCEClock; - public int GPUActivityPercent; - public int CurrentCorePerformanceLevel; - public int CurrentMemoryPerformanceLevel; - public int CurrentDCEFPerformanceLevel; - public int CurrentGFXPerformanceLevel; - public int UVDPerformanceLevel; - public int VCEPerformanceLevel; - public int CurrentBusSpeed; - public int CurrentBusLanes; - public int MaximumBusLanes; - public int VDDC; - public int VDDCI; - } - - internal enum ADLODNTemperatureType - { - // This typed is named like this in the documentation but for some reason AMD failed to include it... - // Yet it seems these correspond with ADL_PMLOG_TEMPERATURE_xxx. - EDGE = 1, - MEM = 2, - VRVDDC = 3, - VRMVDD = 4, - LIQUID = 5, - PLX = 6, - HOTSPOT = 7 - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLSingleSensorData - { - public int supported; - public int value; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct ADLPMLogDataOutput - { - public int size; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = ADL_PMLOG_MAX_SENSORS)] - public ADLSingleSensorData[] sensors; - } - - internal enum ADLSensorType - { - SENSOR_MAXTYPES = 0, - PMLOG_CLK_GFXCLK = 1, - PMLOG_CLK_MEMCLK = 2, - PMLOG_CLK_SOCCLK = 3, - PMLOG_CLK_UVDCLK1 = 4, - PMLOG_CLK_UVDCLK2 = 5, - PMLOG_CLK_VCECLK = 6, - PMLOG_CLK_VCNCLK = 7, - PMLOG_TEMPERATURE_EDGE = 8, - PMLOG_TEMPERATURE_MEM = 9, - PMLOG_TEMPERATURE_VRVDDC = 10, - PMLOG_TEMPERATURE_VRMVDD = 11, - PMLOG_TEMPERATURE_LIQUID = 12, - PMLOG_TEMPERATURE_PLX = 13, - PMLOG_FAN_RPM = 14, - PMLOG_FAN_PERCENTAGE = 15, - PMLOG_SOC_VOLTAGE = 16, - PMLOG_SOC_POWER = 17, - PMLOG_SOC_CURRENT = 18, - PMLOG_INFO_ACTIVITY_GFX = 19, - PMLOG_INFO_ACTIVITY_MEM = 20, - PMLOG_GFX_VOLTAGE = 21, - PMLOG_MEM_VOLTAGE = 22, - PMLOG_ASIC_POWER = 23, - PMLOG_TEMPERATURE_VRSOC = 24, - PMLOG_TEMPERATURE_VRMVDD0 = 25, - PMLOG_TEMPERATURE_VRMVDD1 = 26, - PMLOG_TEMPERATURE_HOTSPOT = 27, - PMLOG_TEMPERATURE_GFX = 28, - PMLOG_TEMPERATURE_SOC = 29, - PMLOG_GFX_POWER = 30, - PMLOG_GFX_CURRENT = 31, - PMLOG_TEMPERATURE_CPU = 32, - PMLOG_CPU_POWER = 33, - PMLOG_CLK_CPUCLK = 34, - PMLOG_THROTTLER_STATUS = 35, - PMLOG_CLK_VCN1CLK1 = 36, - PMLOG_CLK_VCN1CLK2 = 37, - PMLOG_SMART_POWERSHIFT_CPU = 38, - PMLOG_SMART_POWERSHIFT_DGPU = 39, - PMLOG_MAX_SENSORS_REAL + return ADLStatus.ADL_ERR; } } -} + + public static ADLStatus ADL_Adapter_AdapterInfo_Get(ADLAdapterInfo[] info) + { + int elementSize = Marshal.SizeOf(typeof(ADLAdapterInfo)); + int size = info.Length * elementSize; + IntPtr ptr = Marshal.AllocHGlobal(size); + ADLStatus result = ADL_Adapter_AdapterInfo_Get(ptr, size); + for (int i = 0; i < info.Length; i++) + info[i] = (ADLAdapterInfo)Marshal.PtrToStructure((IntPtr)((long)ptr + (i * elementSize)), typeof(ADLAdapterInfo)); + + Marshal.FreeHGlobal(ptr); + + // the ADLAdapterInfo.VendorID field reported by ADL is wrong on + // Windows systems (parse error), so we fix this here + for (int i = 0; i < info.Length; i++) + { + // try Windows UDID format + Match m = Regex.Match(info[i].UDID, "PCI_VEN_([A-Fa-f0-9]{1,4})&.*"); + if (m.Success && m.Groups.Count == 2) + { + info[i].VendorID = Convert.ToInt32(m.Groups[1].Value, 16); + continue; + } + + // if above failed, try Unix UDID format + m = Regex.Match(info[i].UDID, "[0-9]+:[0-9]+:([0-9]+):[0-9]+:[0-9]+"); + if (m.Success && m.Groups.Count == 2) + { + info[i].VendorID = Convert.ToInt32(m.Groups[1].Value, 10); + } + } + + return result; + } + + public static void Main_Memory_Free(IntPtr buffer) + { + if (IntPtr.Zero != buffer) + Marshal.FreeHGlobal(buffer); + } + + internal enum ADLStatus + { + /// + /// All OK, but need to wait. + /// + ADL_OK_WAIT = 4, + + /// + /// All OK, but need restart. + /// + ADL_OK_RESTART = 3, + + /// + /// All OK but need mode change. + /// + ADL_OK_MODE_CHANGE = 2, + + /// + /// All OK, but with warning. + /// + ADL_OK_WARNING = 1, + + /// + /// ADL function completed successfully. + /// + ADL_OK = 0, + + /// + /// Generic Error. Most likely one or more of the Escape calls to the driver + /// failed! + /// + ADL_ERR = -1, + + /// + /// ADL not initialized. + /// + ADL_ERR_NOT_INIT = -2, + + /// + /// One of the parameter passed is invalid. + /// + ADL_ERR_INVALID_PARAM = -3, + + /// + /// One of the parameter size is invalid. + /// + ADL_ERR_INVALID_PARAM_SIZE = -4, + + /// + /// Invalid ADL index passed. + /// + ADL_ERR_INVALID_ADL_IDX = -5, + + /// + /// Invalid controller index passed. + /// + ADL_ERR_INVALID_CONTROLLER_IDX = -6, + + /// + /// Invalid display index passed. + /// + ADL_ERR_INVALID_DIPLAY_IDX = -7, + + /// + /// Function not supported by the driver. + /// + ADL_ERR_NOT_SUPPORTED = -8, + + /// + /// Null Pointer error. + /// + ADL_ERR_NULL_POINTER = -9, + + /// + /// Call can't be made due to disabled adapter. + /// + ADL_ERR_DISABLED_ADAPTER = -10, + + /// + /// Invalid Callback. + /// + ADL_ERR_INVALID_CALLBACK = -11, + + /// + /// Display Resource conflict. + /// + ADL_ERR_RESOURCE_CONFLICT = -12, + + /// + /// Failed to update some of the values. Can be returned by set request that + /// include multiple values if not all values were successfully committed. + /// + ADL_ERR_SET_INCOMPLETE = -20, + + /// + /// There's no Linux XDisplay in Linux Console environment. + /// + ADL_ERR_NO_XDISPLAY = -21 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLAdapterInfo + { + public int Size; + public int AdapterIndex; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] + public string UDID; + + public int BusNumber; + public int DeviceNumber; + public int FunctionNumber; + public int VendorID; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] + public string AdapterName; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] + public string DisplayName; + + public int Present; + public int Exist; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] + public string DriverPath; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] + public string DriverPathExt; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = ADL_MAX_PATH)] + public string PNPString; + + public int OSDisplayIndex; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLODParameterRange + { + public int Min; + public int Max; + public int Step; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLODParameters + { + public int Size; + public int NumberOfPerformanceLevels; + public int ActivityReportingSupported; + public int DiscretePerformanceLevels; + public int Reserved; + public ADLODParameterRange EngineClock; + public ADLODParameterRange MemoryClock; + public ADLODParameterRange Vddc; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLPMActivity + { + public int Size; + public int EngineClock; + public int MemoryClock; + public int Vddc; + public int ActivityPercent; + public int CurrentPerformanceLevel; + public int CurrentBusSpeed; + public int CurrentBusLanes; + public int MaximumBusLanes; + public int Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLTemperature + { + public int Size; + public int Temperature; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLFanSpeedValue + { + public int Size; + public int SpeedType; + public int FanSpeed; + public int Flags; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLFanSpeedInfo + { + public int Size; + public int Flags; + public int MinPercent; + public int MaxPercent; + public int MinRPM; + public int MaxRPM; + } + + internal enum ADLODNCurrentPowerType + { + ODN_GPU_TOTAL_POWER = 0, + ODN_GPU_PPT_POWER, + ODN_GPU_SOCKET_POWER, + ODN_GPU_CHIP_POWER + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLVersionsInfo + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string DriverVer; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string CatalystVersion; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)] + public string CatalystWebLink; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLODNPerformanceStatus + { + public int CoreClock; + public int MemoryClock; + public int DCEFClock; + public int GFXClock; + public int UVDClock; + public int VCEClock; + public int GPUActivityPercent; + public int CurrentCorePerformanceLevel; + public int CurrentMemoryPerformanceLevel; + public int CurrentDCEFPerformanceLevel; + public int CurrentGFXPerformanceLevel; + public int UVDPerformanceLevel; + public int VCEPerformanceLevel; + public int CurrentBusSpeed; + public int CurrentBusLanes; + public int MaximumBusLanes; + public int VDDC; + public int VDDCI; + } + + internal enum ADLODNTemperatureType + { + // This typed is named like this in the documentation but for some reason AMD failed to include it... + // Yet it seems these correspond with ADL_PMLOG_TEMPERATURE_xxx. + EDGE = 1, + MEM = 2, + VRVDDC = 3, + VRMVDD = 4, + LIQUID = 5, + PLX = 6, + HOTSPOT = 7 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLSingleSensorData + { + public int supported; + public int value; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct ADLPMLogDataOutput + { + public int size; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = ADL_PMLOG_MAX_SENSORS)] + public ADLSingleSensorData[] sensors; + } + + internal enum ADLSensorType + { + SENSOR_MAXTYPES = 0, + PMLOG_CLK_GFXCLK = 1, + PMLOG_CLK_MEMCLK = 2, + PMLOG_CLK_SOCCLK = 3, + PMLOG_CLK_UVDCLK1 = 4, + PMLOG_CLK_UVDCLK2 = 5, + PMLOG_CLK_VCECLK = 6, + PMLOG_CLK_VCNCLK = 7, + PMLOG_TEMPERATURE_EDGE = 8, + PMLOG_TEMPERATURE_MEM = 9, + PMLOG_TEMPERATURE_VRVDDC = 10, + PMLOG_TEMPERATURE_VRMVDD = 11, + PMLOG_TEMPERATURE_LIQUID = 12, + PMLOG_TEMPERATURE_PLX = 13, + PMLOG_FAN_RPM = 14, + PMLOG_FAN_PERCENTAGE = 15, + PMLOG_SOC_VOLTAGE = 16, + PMLOG_SOC_POWER = 17, + PMLOG_SOC_CURRENT = 18, + PMLOG_INFO_ACTIVITY_GFX = 19, + PMLOG_INFO_ACTIVITY_MEM = 20, + PMLOG_GFX_VOLTAGE = 21, + PMLOG_MEM_VOLTAGE = 22, + PMLOG_ASIC_POWER = 23, + PMLOG_TEMPERATURE_VRSOC = 24, + PMLOG_TEMPERATURE_VRMVDD0 = 25, + PMLOG_TEMPERATURE_VRMVDD1 = 26, + PMLOG_TEMPERATURE_HOTSPOT = 27, + PMLOG_TEMPERATURE_GFX = 28, + PMLOG_TEMPERATURE_SOC = 29, + PMLOG_GFX_POWER = 30, + PMLOG_GFX_CURRENT = 31, + PMLOG_TEMPERATURE_CPU = 32, + PMLOG_CPU_POWER = 33, + PMLOG_CLK_CPUCLK = 34, + PMLOG_THROTTLER_STATUS = 35, + PMLOG_CLK_VCN1CLK1 = 36, + PMLOG_CLK_VCN1CLK2 = 37, + PMLOG_SMART_POWERSHIFT_CPU = 38, + PMLOG_SMART_POWERSHIFT_DGPU = 39, + PMLOG_MAX_SENSORS_REAL + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/CfgMgr32.cs b/LibreHardwareMonitorLib/Interop/CfgMgr32.cs index 9013c35..43cf0ba 100644 --- a/LibreHardwareMonitorLib/Interop/CfgMgr32.cs +++ b/LibreHardwareMonitorLib/Interop/CfgMgr32.cs @@ -9,22 +9,21 @@ using System; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class CfgMgr32 { - internal static class CfgMgr32 - { - internal const uint CM_GET_DEVICE_INTERFACE_LIST_PRESENT = 0; - internal const int CR_SUCCESS = 0; + internal const uint CM_GET_DEVICE_INTERFACE_LIST_PRESENT = 0; + internal const int CR_SUCCESS = 0; - internal const string DllName = "CfgMgr32.dll"; - internal static Guid GUID_DISPLAY_DEVICE_ARRIVAL = new("1CA05180-A699-450A-9A0C-DE4FBE3DDD89"); + internal const string DllName = "CfgMgr32.dll"; + internal static Guid GUID_DISPLAY_DEVICE_ARRIVAL = new("1CA05180-A699-450A-9A0C-DE4FBE3DDD89"); - [DllImport(DllName, CharSet = CharSet.Unicode)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern uint CM_Get_Device_Interface_List_Size(out uint size, ref Guid interfaceClassGuid, string deviceID, uint flags); + [DllImport(DllName, CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern uint CM_Get_Device_Interface_List_Size(out uint size, ref Guid interfaceClassGuid, string deviceID, uint flags); - [DllImport(DllName, CharSet = CharSet.Unicode)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern uint CM_Get_Device_Interface_List(ref Guid interfaceClassGuid, string deviceID, char[] buffer, uint bufferLength, uint flags); - } -} + [DllImport(DllName, CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern uint CM_Get_Device_Interface_List(ref Guid interfaceClassGuid, string deviceID, char[] buffer, uint bufferLength, uint flags); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/D3dkmdt.cs b/LibreHardwareMonitorLib/Interop/D3dkmdt.cs index 2dc3744..c809a4e 100644 --- a/LibreHardwareMonitorLib/Interop/D3dkmdt.cs +++ b/LibreHardwareMonitorLib/Interop/D3dkmdt.cs @@ -8,41 +8,40 @@ using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class D3dkmdt { - internal static class D3dkmdt + internal enum DXGK_ENGINE_TYPE { - internal enum DXGK_ENGINE_TYPE - { - DXGK_ENGINE_TYPE_OTHER = 0, - DXGK_ENGINE_TYPE_3D = 1, - DXGK_ENGINE_TYPE_VIDEO_DECODE = 2, - DXGK_ENGINE_TYPE_VIDEO_ENCODE = 3, - DXGK_ENGINE_TYPE_VIDEO_PROCESSING = 4, - DXGK_ENGINE_TYPE_SCENE_ASSEMBLY = 5, - DXGK_ENGINE_TYPE_COPY = 6, - DXGK_ENGINE_TYPE_OVERLAY = 7, - DXGK_ENGINE_TYPE_CRYPTO, - DXGK_ENGINE_TYPE_MAX - } - - [StructLayout(LayoutKind.Sequential)] - internal struct DXGK_NODEMETADATA_FLAGS - { - public uint Value; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] - internal struct DXGK_NODEMETADATA - { - public DXGK_ENGINE_TYPE EngineType; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] - public string FriendlyName; - - public DXGK_NODEMETADATA_FLAGS Flags; - public byte GpuMmuSupported; - public byte IoMmuSupported; - } + DXGK_ENGINE_TYPE_OTHER = 0, + DXGK_ENGINE_TYPE_3D = 1, + DXGK_ENGINE_TYPE_VIDEO_DECODE = 2, + DXGK_ENGINE_TYPE_VIDEO_ENCODE = 3, + DXGK_ENGINE_TYPE_VIDEO_PROCESSING = 4, + DXGK_ENGINE_TYPE_SCENE_ASSEMBLY = 5, + DXGK_ENGINE_TYPE_COPY = 6, + DXGK_ENGINE_TYPE_OVERLAY = 7, + DXGK_ENGINE_TYPE_CRYPTO, + DXGK_ENGINE_TYPE_MAX } -} + + [StructLayout(LayoutKind.Sequential)] + internal struct DXGK_NODEMETADATA_FLAGS + { + public uint Value; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Unicode)] + internal struct DXGK_NODEMETADATA + { + public DXGK_ENGINE_TYPE EngineType; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] + public string FriendlyName; + + public DXGK_NODEMETADATA_FLAGS Flags; + public byte GpuMmuSupported; + public byte IoMmuSupported; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/D3dkmth.cs b/LibreHardwareMonitorLib/Interop/D3dkmth.cs index d82818f..3a906d6 100644 --- a/LibreHardwareMonitorLib/Interop/D3dkmth.cs +++ b/LibreHardwareMonitorLib/Interop/D3dkmth.cs @@ -9,555 +9,554 @@ using System; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class D3dkmth { - internal static class D3dkmth + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_CLOSEADAPTER { - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_CLOSEADAPTER - { - public uint hAdapter; - } + public uint hAdapter; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYADAPTERINFO - { - public uint hAdapter; - public KMTQUERYADAPTERINFOTYPE Type; - public IntPtr pPrivateDriverData; - public int PrivateDriverDataSize; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYADAPTERINFO + { + public uint hAdapter; + public KMTQUERYADAPTERINFOTYPE Type; + public IntPtr pPrivateDriverData; + public int PrivateDriverDataSize; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_OPENADAPTERFROMDEVICENAME - { - [MarshalAs(UnmanagedType.LPWStr)] - public string pDeviceName; + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_OPENADAPTERFROMDEVICENAME + { + [MarshalAs(UnmanagedType.LPWStr)] + public string pDeviceName; - public uint hAdapter; - public WinNt.LUID AdapterLuid; - } + public uint hAdapter; + public WinNt.LUID AdapterLuid; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_ADAPTERTYPE - { - public D3DKMT_ADAPTERTYPE_FLAGS Value; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_ADAPTERTYPE + { + public D3DKMT_ADAPTERTYPE_FLAGS Value; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT - { - public uint SegmentId; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT + { + public uint SegmentId; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_QUERY_NODE - { - public uint NodeId; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_NODE + { + public uint NodeId; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE - { - public uint VidPnSourceId; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE + { + public uint VidPnSourceId; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_REFERENCE_DMA_BUFFER - { - public uint NbCall; - public uint NbAllocationsReferenced; - public uint MaxNbAllocationsReferenced; - public uint NbNULLReference; - public uint NbWriteReference; - public uint NbRenamedAllocationsReferenced; - public uint NbIterationSearchingRenamedAllocation; - public uint NbLockedAllocationReferenced; - public uint NbAllocationWithValidPrepatchingInfoReferenced; - public uint NbAllocationWithInvalidPrepatchingInfoReferenced; - public uint NbDMABufferSuccessfullyPrePatched; - public uint NbPrimariesReferencesOverflow; - public uint NbAllocationWithNonPreferredResources; - public uint NbAllocationInsertedInMigrationTable; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_REFERENCE_DMA_BUFFER + { + public uint NbCall; + public uint NbAllocationsReferenced; + public uint MaxNbAllocationsReferenced; + public uint NbNULLReference; + public uint NbWriteReference; + public uint NbRenamedAllocationsReferenced; + public uint NbIterationSearchingRenamedAllocation; + public uint NbLockedAllocationReferenced; + public uint NbAllocationWithValidPrepatchingInfoReferenced; + public uint NbAllocationWithInvalidPrepatchingInfoReferenced; + public uint NbDMABufferSuccessfullyPrePatched; + public uint NbPrimariesReferencesOverflow; + public uint NbAllocationWithNonPreferredResources; + public uint NbAllocationInsertedInMigrationTable; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_SEGMENTSIZEINFO - { - public ulong DedicatedVideoMemorySize; - public ulong DedicatedSystemMemorySize; - public ulong SharedSystemMemorySize; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_SEGMENTSIZEINFO + { + public ulong DedicatedVideoMemorySize; + public ulong DedicatedSystemMemorySize; + public ulong SharedSystemMemorySize; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_RENAMING - { - public uint NbAllocationsRenamed; - public uint NbAllocationsShrinked; - public uint NbRenamedBuffer; - public uint MaxRenamingListLength; - public uint NbFailuresDueToRenamingLimit; - public uint NbFailuresDueToCreateAllocation; - public uint NbFailuresDueToOpenAllocation; - public uint NbFailuresDueToLowResource; - public uint NbFailuresDueToNonRetiredLimit; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_RENAMING + { + public uint NbAllocationsRenamed; + public uint NbAllocationsShrinked; + public uint NbRenamedBuffer; + public uint MaxRenamingListLength; + public uint NbFailuresDueToRenamingLimit; + public uint NbFailuresDueToCreateAllocation; + public uint NbFailuresDueToOpenAllocation; + public uint NbFailuresDueToLowResource; + public uint NbFailuresDueToNonRetiredLimit; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_COUNTER - { - public uint Count; - public ulong Bytes; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_COUNTER + { + public uint Count; + public ulong Bytes; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_PREPRATION - { - public uint BroadcastStall; - public uint NbDMAPrepared; - public uint NbDMAPreparedLongPath; - public uint ImmediateHighestPreparationPass; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsTrimmed; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PREPRATION + { + public uint BroadcastStall; + public uint NbDMAPrepared; + public uint NbDMAPreparedLongPath; + public uint ImmediateHighestPreparationPass; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsTrimmed; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_PAGING_FAULT - { - public D3DKMT_QUERYSTATISTICS_COUNTER Faults; - public D3DKMT_QUERYSTATISTICS_COUNTER FaultsFirstTimeAccess; - public D3DKMT_QUERYSTATISTICS_COUNTER FaultsReclaimed; - public D3DKMT_QUERYSTATISTICS_COUNTER FaultsMigration; - public D3DKMT_QUERYSTATISTICS_COUNTER FaultsIncorrectResource; - public D3DKMT_QUERYSTATISTICS_COUNTER FaultsLostContent; - public D3DKMT_QUERYSTATISTICS_COUNTER FaultsEvicted; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsMEM_RESET; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetSuccess; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetFail; + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PAGING_FAULT + { + public D3DKMT_QUERYSTATISTICS_COUNTER Faults; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsFirstTimeAccess; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsReclaimed; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsMigration; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsIncorrectResource; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsLostContent; + public D3DKMT_QUERYSTATISTICS_COUNTER FaultsEvicted; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsMEM_RESET; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetSuccess; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocationsUnresetFail; - public uint AllocationsUnresetSuccessRead; - public uint AllocationsUnresetFailRead; + public uint AllocationsUnresetSuccessRead; + public uint AllocationsUnresetFailRead; - public D3DKMT_QUERYSTATISTICS_COUNTER Evictions; - public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPreparation; - public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToLock; - public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToClose; - public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPurge; - public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToSuspendCPUAccess; - } + public D3DKMT_QUERYSTATISTICS_COUNTER Evictions; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPreparation; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToLock; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToClose; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToPurge; + public D3DKMT_QUERYSTATISTICS_COUNTER EvictionsDueToSuspendCPUAccess; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_PAGING_TRANSFER - { - public ulong BytesFilled; - public ulong BytesDiscarded; - public ulong BytesMappedIntoAperture; - public ulong BytesUnmappedFromAperture; - public ulong BytesTransferredFromMdlToMemory; - public ulong BytesTransferredFromMemoryToMdl; - public ulong BytesTransferredFromApertureToMemory; - public ulong BytesTransferredFromMemoryToAperture; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PAGING_TRANSFER + { + public ulong BytesFilled; + public ulong BytesDiscarded; + public ulong BytesMappedIntoAperture; + public ulong BytesUnmappedFromAperture; + public ulong BytesTransferredFromMdlToMemory; + public ulong BytesTransferredFromMemoryToMdl; + public ulong BytesTransferredFromApertureToMemory; + public ulong BytesTransferredFromMemoryToAperture; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_SWIZZLING_RANGE - { - public uint NbRangesAcquired; - public uint NbRangesReleased; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_SWIZZLING_RANGE + { + public uint NbRangesAcquired; + public uint NbRangesReleased; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_LOCKS - { - public uint NbLocks; - public uint NbLocksWaitFlag; - public uint NbLocksDiscardFlag; - public uint NbLocksNoOverwrite; - public uint NbLocksNoReadSync; - public uint NbLocksLinearization; - public uint NbComplexLocks; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_LOCKS + { + public uint NbLocks; + public uint NbLocksWaitFlag; + public uint NbLocksDiscardFlag; + public uint NbLocksNoOverwrite; + public uint NbLocksNoReadSync; + public uint NbLocksLinearization; + public uint NbComplexLocks; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_ALLOCATIONS - { - public D3DKMT_QUERYSTATISTICS_COUNTER Created; - public D3DKMT_QUERYSTATISTICS_COUNTER Destroyed; - public D3DKMT_QUERYSTATISTICS_COUNTER Opened; - public D3DKMT_QUERYSTATISTICS_COUNTER Closed; - public D3DKMT_QUERYSTATISTICS_COUNTER MigratedSuccess; - public D3DKMT_QUERYSTATISTICS_COUNTER MigratedFail; - public D3DKMT_QUERYSTATISTICS_COUNTER MigratedAbandoned; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_ALLOCATIONS + { + public D3DKMT_QUERYSTATISTICS_COUNTER Created; + public D3DKMT_QUERYSTATISTICS_COUNTER Destroyed; + public D3DKMT_QUERYSTATISTICS_COUNTER Opened; + public D3DKMT_QUERYSTATISTICS_COUNTER Closed; + public D3DKMT_QUERYSTATISTICS_COUNTER MigratedSuccess; + public D3DKMT_QUERYSTATISTICS_COUNTER MigratedFail; + public D3DKMT_QUERYSTATISTICS_COUNTER MigratedAbandoned; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_TERMINATIONS - { - public D3DKMT_QUERYSTATISTICS_COUNTER TerminatedShared; - public D3DKMT_QUERYSTATISTICS_COUNTER TerminatedNonShared; - public D3DKMT_QUERYSTATISTICS_COUNTER DestroyedShared; - public D3DKMT_QUERYSTATISTICS_COUNTER DestroyedNonShared; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_TERMINATIONS + { + public D3DKMT_QUERYSTATISTICS_COUNTER TerminatedShared; + public D3DKMT_QUERYSTATISTICS_COUNTER TerminatedNonShared; + public D3DKMT_QUERYSTATISTICS_COUNTER DestroyedShared; + public D3DKMT_QUERYSTATISTICS_COUNTER DestroyedNonShared; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION - { - public uint NbSegments; - public uint NodeCount; - public uint VidPnSourceCount; + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION + { + public uint NbSegments; + public uint NodeCount; + public uint VidPnSourceCount; - public uint VSyncEnabled; - public uint TdrDetectedCount; + public uint VSyncEnabled; + public uint TdrDetectedCount; - public long ZeroLengthDmaBuffers; - public ulong RestartedPeriod; + public long ZeroLengthDmaBuffers; + public ulong RestartedPeriod; - public D3DKMT_QUERYSTATISTICS_REFERENCE_DMA_BUFFER ReferenceDmaBuffer; - public D3DKMT_QUERYSTATISTICS_RENAMING Renaming; - public D3DKMT_QUERYSTATISTICS_PREPRATION Preparation; - public D3DKMT_QUERYSTATISTICS_PAGING_FAULT PagingFault; - public D3DKMT_QUERYSTATISTICS_PAGING_TRANSFER PagingTransfer; - public D3DKMT_QUERYSTATISTICS_SWIZZLING_RANGE SwizzlingRange; - public D3DKMT_QUERYSTATISTICS_LOCKS Locks; - public D3DKMT_QUERYSTATISTICS_ALLOCATIONS Allocations; - public D3DKMT_QUERYSTATISTICS_TERMINATIONS Terminations; + public D3DKMT_QUERYSTATISTICS_REFERENCE_DMA_BUFFER ReferenceDmaBuffer; + public D3DKMT_QUERYSTATISTICS_RENAMING Renaming; + public D3DKMT_QUERYSTATISTICS_PREPRATION Preparation; + public D3DKMT_QUERYSTATISTICS_PAGING_FAULT PagingFault; + public D3DKMT_QUERYSTATISTICS_PAGING_TRANSFER PagingTransfer; + public D3DKMT_QUERYSTATISTICS_SWIZZLING_RANGE SwizzlingRange; + public D3DKMT_QUERYSTATISTICS_LOCKS Locks; + public D3DKMT_QUERYSTATISTICS_ALLOCATIONS Allocations; + public D3DKMT_QUERYSTATISTICS_TERMINATIONS Terminations; - private readonly ulong Reserved; - private readonly ulong Reserved1; - private readonly ulong Reserved2; - private readonly ulong Reserved3; - private readonly ulong Reserved4; - private readonly ulong Reserved5; - private readonly ulong Reserved6; - private readonly ulong Reserved7; - } + private readonly ulong Reserved; + private readonly ulong Reserved1; + private readonly ulong Reserved2; + private readonly ulong Reserved3; + private readonly ulong Reserved4; + private readonly ulong Reserved5; + private readonly ulong Reserved6; + private readonly ulong Reserved7; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_MEMORY - { - public ulong TotalBytesEvicted; - public uint AllocsCommitted; - public uint AllocsResident; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_MEMORY + { + public ulong TotalBytesEvicted; + public uint AllocsCommitted; + public uint AllocsResident; + } - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION - { - public ulong CommitLimit; - public ulong BytesCommitted; - public ulong BytesResident; - public D3DKMT_QUERYSTATISTICS_MEMORY Memory; - public uint Aperture; // boolean - public fixed ulong TotalBytesEvictedByPriority[5]; // D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX - public ulong SystemMemoryEndAddress; - public D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_POWER_FLAGS PowerFlags; - public fixed ulong Reserved[6]; - } + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION + { + public ulong CommitLimit; + public ulong BytesCommitted; + public ulong BytesResident; + public D3DKMT_QUERYSTATISTICS_MEMORY Memory; + public uint Aperture; // boolean + public fixed ulong TotalBytesEvictedByPriority[5]; // D3DKMT_QUERYSTATISTICS_SEGMENT_PREFERENCE_MAX + public ulong SystemMemoryEndAddress; + public D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_POWER_FLAGS PowerFlags; + public fixed ulong Reserved[6]; + } - [StructLayout(LayoutKind.Explicit)] - internal struct D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_POWER_FLAGS - { - [FieldOffset(0)] - public ulong PreservedDuringStandby; + [StructLayout(LayoutKind.Explicit)] + internal struct D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_POWER_FLAGS + { + [FieldOffset(0)] + public ulong PreservedDuringStandby; - [FieldOffset(1)] - public ulong PreservedDuringHibernate; + [FieldOffset(1)] + public ulong PreservedDuringHibernate; - [FieldOffset(2)] - public ulong PartiallyPreservedDuringHibernate; + [FieldOffset(2)] + public ulong PartiallyPreservedDuringHibernate; - [FieldOffset(3)] - public ulong Reserved; - } + [FieldOffset(3)] + public ulong Reserved; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY - { - public uint AllocsCommitted; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn0; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn1; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn2; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn3; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn4; - public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInNonPreferred; - public ulong TotalBytesEvictedDueToPreparation; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY + { + public uint AllocsCommitted; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn0; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn1; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn2; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn3; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentIn4; + public D3DKMT_QUERYSTATISTICS_COUNTER AllocsResidentInNonPreferred; + public ulong TotalBytesEvictedDueToPreparation; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY - { - public ulong UseMRU; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY + { + public ulong UseMRU; + } - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION - { - public ulong BytesCommitted; - public ulong MaximumWorkingSet; - public ulong MinimumWorkingSet; + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION + { + public ulong BytesCommitted; + public ulong MaximumWorkingSet; + public ulong MinimumWorkingSet; - public uint NbReferencedAllocationEvictedInPeriod; + public uint NbReferencedAllocationEvictedInPeriod; - public D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY VideoMemory; - public D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY _Policy; + public D3DKMT_QUERYSTATISTICS_VIDEO_MEMORY VideoMemory; + public D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_POLICY _Policy; - public fixed ulong Reserved[8]; - } + public fixed ulong Reserved[8]; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION - { - public uint PreemptionCounter; - public uint PreemptionCounter1; - public uint PreemptionCounter2; - public uint PreemptionCounter3; - public uint PreemptionCounter4; - public uint PreemptionCounter5; - public uint PreemptionCounter6; - public uint PreemptionCounter7; - public uint PreemptionCounter8; - public uint PreemptionCounter9; - public uint PreemptionCounter10; - public uint PreemptionCounter11; - public uint PreemptionCounter12; - public uint PreemptionCounter13; - public uint PreemptionCounter14; - public uint PreemptionCounter15; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION + { + public uint PreemptionCounter; + public uint PreemptionCounter1; + public uint PreemptionCounter2; + public uint PreemptionCounter3; + public uint PreemptionCounter4; + public uint PreemptionCounter5; + public uint PreemptionCounter6; + public uint PreemptionCounter7; + public uint PreemptionCounter8; + public uint PreemptionCounter9; + public uint PreemptionCounter10; + public uint PreemptionCounter11; + public uint PreemptionCounter12; + public uint PreemptionCounter13; + public uint PreemptionCounter14; + public uint PreemptionCounter15; + } - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION - { - public WinNt.LARGE_INTEGER RunningTime; // 100ns - public uint ContextSwitch; - private readonly D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION PreemptionStatistics; - private readonly D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION PacketStatistics; - private fixed ulong Reserved[8]; - } + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION + { + public WinNt.LARGE_INTEGER RunningTime; // 100ns + public uint ContextSwitch; + private readonly D3DKMT_QUERYSTATISTICS_PREEMPTION_INFORMATION PreemptionStatistics; + private readonly D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION PacketStatistics; + private fixed ulong Reserved[8]; + } - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct D3DKMT_QUERYSTATISTICS_NODE_INFORMATION - { - public D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // global + [StructLayout(LayoutKind.Sequential)] + internal unsafe struct D3DKMT_QUERYSTATISTICS_NODE_INFORMATION + { + public D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION GlobalInformation; // global - public D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // system thread + public D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION SystemInformation; // system thread - //public UInt32 NodeId; // Win10 - public fixed ulong Reserved[8]; - } + //public UInt32 NodeId; // Win10 + public fixed ulong Reserved[8]; + } - internal struct D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION - { - public uint PacketSubmitted; - public uint PacketCompleted; - public uint PacketPreempted; - public uint PacketFaulted; - } + internal struct D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION + { + public uint PacketSubmitted; + public uint PacketCompleted; + public uint PacketPreempted; + public uint PacketFaulted; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION - { - public uint PacketSubmited; - public uint PacketCompleted; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION + { + public uint PacketSubmited; + public uint PacketCompleted; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION - { - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket; - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket1; - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket2; - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket3; - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket4; - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket5; - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket6; - public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket7; + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS_PACKET_INFORMATION + { + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket1; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket2; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket3; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket4; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket5; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket6; + public D3DKMT_QUERYSTATISTICS_QUEUE_PACKET_TYPE_INFORMATION QueuePacket7; - public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket; - public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket1; - public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket2; - public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket3; - } + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket; + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket1; + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket2; + public D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE_INFORMATION DmaPacket3; + } - [StructLayout(LayoutKind.Explicit)] - internal struct D3DKMT_QUERYSTATISTICS_RESULT - { - [FieldOffset(8)] - public D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION AdapterInformation; + [StructLayout(LayoutKind.Explicit)] + internal struct D3DKMT_QUERYSTATISTICS_RESULT + { + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_ADAPTER_INFORMATION AdapterInformation; - [FieldOffset(8)] - public D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION SegmentInformation; + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION SegmentInformation; - [FieldOffset(8)] - public D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION ProcessSegmentInformation; + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_INFORMATION ProcessSegmentInformation; - [FieldOffset(8)] - public D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; + [FieldOffset(8)] + public D3DKMT_QUERYSTATISTICS_NODE_INFORMATION NodeInformation; - // D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION ProcessInformation; - // D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION ProcessNodeInformation; - // D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation; - // D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 SegmentInformationV1; // WIN7 - // D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION VidPnSourceInformation; - // D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION ProcessAdapterInformation; - // D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION ProcessVidPnSourceInformation; - // D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP_INFORMATION ProcessSegmentGroupInformation; - } + // D3DKMT_QUERYSTATISTICS_PROCESS_INFORMATION ProcessInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_NODE_INFORMATION ProcessNodeInformation; + // D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER_INFORMATION PhysAdapterInformation; + // D3DKMT_QUERYSTATISTICS_SEGMENT_INFORMATION_V1 SegmentInformationV1; // WIN7 + // D3DKMT_QUERYSTATISTICS_VIDPNSOURCE_INFORMATION VidPnSourceInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER_INFORMATION ProcessAdapterInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE_INFORMATION ProcessVidPnSourceInformation; + // D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP_INFORMATION ProcessSegmentGroupInformation; + } - [StructLayout(LayoutKind.Explicit)] - internal struct D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT - { - [FieldOffset(0)] - public D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QuerySegment; + [StructLayout(LayoutKind.Explicit)] + internal struct D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT + { + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QuerySegment; - [FieldOffset(0)] - public D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QueryProcessSegment; + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_SEGMENT QueryProcessSegment; - [FieldOffset(0)] - public D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryNode; + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryNode; - [FieldOffset(0)] - public D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryProcessNode; + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_NODE QueryProcessNode; - [FieldOffset(0)] - public D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryVidPnSource; + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryVidPnSource; - [FieldOffset(0)] - public D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryProcessVidPnSource; - } + [FieldOffset(0)] + public D3DKMT_QUERYSTATISTICS_QUERY_VIDPNSOURCE QueryProcessVidPnSource; + } - [StructLayout(LayoutKind.Sequential)] - internal struct D3DKMT_QUERYSTATISTICS - { - public D3DKMT_QUERYSTATISTICS_TYPE Type; - public WinNt.LUID AdapterLuid; - public uint ProcessHandle; - public D3DKMT_QUERYSTATISTICS_RESULT QueryResult; - public D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT QueryElement; - } + [StructLayout(LayoutKind.Sequential)] + internal struct D3DKMT_QUERYSTATISTICS + { + public D3DKMT_QUERYSTATISTICS_TYPE Type; + public WinNt.LUID AdapterLuid; + public uint ProcessHandle; + public D3DKMT_QUERYSTATISTICS_RESULT QueryResult; + public D3DKMT_QUERYSTATISTICS_QUERY_ELEMENT QueryElement; + } - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct D3DKMT_NODEMETADATA - { - public uint NodeOrdinalAndAdapterIndex; - public D3dkmdt.DXGK_NODEMETADATA NodeData; - } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct D3DKMT_NODEMETADATA + { + public uint NodeOrdinalAndAdapterIndex; + public D3dkmdt.DXGK_NODEMETADATA NodeData; + } - [Flags] - internal enum D3DKMT_ADAPTERTYPE_FLAGS : uint - { - RenderSupported = 0, - DisplaySupported = 1, - SoftwareDevice = 2, - PostDevice = 4, - HybridDiscrete = 8, - HybridIntegrated = 16, - IndirectDisplayDevice = 32, - Paravirtualized = 64, - ACGSupported = 128, - SupportSetTimingsFromVidPn = 256, - Detachable = 512, - ComputeOnly = 1024, - Prototype = 2045 - } + [Flags] + internal enum D3DKMT_ADAPTERTYPE_FLAGS : uint + { + RenderSupported = 0, + DisplaySupported = 1, + SoftwareDevice = 2, + PostDevice = 4, + HybridDiscrete = 8, + HybridIntegrated = 16, + IndirectDisplayDevice = 32, + Paravirtualized = 64, + ACGSupported = 128, + SupportSetTimingsFromVidPn = 256, + Detachable = 512, + ComputeOnly = 1024, + Prototype = 2045 + } - internal enum D3DKMT_QUERYSTATISTICS_TYPE - { - D3DKMT_QUERYSTATISTICS_ADAPTER, - D3DKMT_QUERYSTATISTICS_PROCESS, - D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER, - D3DKMT_QUERYSTATISTICS_SEGMENT, - D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT, - D3DKMT_QUERYSTATISTICS_NODE, - D3DKMT_QUERYSTATISTICS_PROCESS_NODE, - D3DKMT_QUERYSTATISTICS_VIDPNSOURCE, - D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE, - D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP, - D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER - } + internal enum D3DKMT_QUERYSTATISTICS_TYPE + { + D3DKMT_QUERYSTATISTICS_ADAPTER, + D3DKMT_QUERYSTATISTICS_PROCESS, + D3DKMT_QUERYSTATISTICS_PROCESS_ADAPTER, + D3DKMT_QUERYSTATISTICS_SEGMENT, + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT, + D3DKMT_QUERYSTATISTICS_NODE, + D3DKMT_QUERYSTATISTICS_PROCESS_NODE, + D3DKMT_QUERYSTATISTICS_VIDPNSOURCE, + D3DKMT_QUERYSTATISTICS_PROCESS_VIDPNSOURCE, + D3DKMT_QUERYSTATISTICS_PROCESS_SEGMENT_GROUP, + D3DKMT_QUERYSTATISTICS_PHYSICAL_ADAPTER + } - internal enum D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE - { - D3DKMT_ClientRenderBuffer = 0, - D3DKMT_ClientPagingBuffer = 1, - D3DKMT_SystemPagingBuffer = 2, - D3DKMT_SystemPreemptionBuffer = 3, - D3DKMT_DmaPacketTypeMax - } + internal enum D3DKMT_QUERYSTATISTICS_DMA_PACKET_TYPE + { + D3DKMT_ClientRenderBuffer = 0, + D3DKMT_ClientPagingBuffer = 1, + D3DKMT_SystemPagingBuffer = 2, + D3DKMT_SystemPreemptionBuffer = 3, + D3DKMT_DmaPacketTypeMax + } - internal enum KMTQUERYADAPTERINFOTYPE - { - KMTQAITYPE_UMDRIVERPRIVATE = 0, - KMTQAITYPE_UMDRIVERNAME = 1, - KMTQAITYPE_UMOPENGLINFO = 2, - KMTQAITYPE_GETSEGMENTSIZE = 3, - KMTQAITYPE_ADAPTERGUID = 4, - KMTQAITYPE_FLIPQUEUEINFO = 5, - KMTQAITYPE_ADAPTERADDRESS = 6, - KMTQAITYPE_SETWORKINGSETINFO = 7, - KMTQAITYPE_ADAPTERREGISTRYINFO = 8, - KMTQAITYPE_CURRENTDISPLAYMODE = 9, - KMTQAITYPE_MODELIST = 10, - KMTQAITYPE_CHECKDRIVERUPDATESTATUS = 11, - KMTQAITYPE_VIRTUALADDRESSINFO = 12, - KMTQAITYPE_DRIVERVERSION = 13, - KMTQAITYPE_ADAPTERTYPE = 15, - KMTQAITYPE_OUTPUTDUPLCONTEXTSCOUNT = 16, - KMTQAITYPE_WDDM_1_2_CAPS = 17, - KMTQAITYPE_UMD_DRIVER_VERSION = 18, - KMTQAITYPE_DIRECTFLIP_SUPPORT = 19, - KMTQAITYPE_MULTIPLANEOVERLAY_SUPPORT = 20, - KMTQAITYPE_DLIST_DRIVER_NAME = 21, - KMTQAITYPE_WDDM_1_3_CAPS = 22, - KMTQAITYPE_MULTIPLANEOVERLAY_HUD_SUPPORT = 23, - KMTQAITYPE_WDDM_2_0_CAPS = 24, - KMTQAITYPE_NODEMETADATA = 25, - KMTQAITYPE_CPDRIVERNAME = 26, - KMTQAITYPE_XBOX = 27, - KMTQAITYPE_INDEPENDENTFLIP_SUPPORT = 28, - KMTQAITYPE_MIRACASTCOMPANIONDRIVERNAME = 29, - KMTQAITYPE_PHYSICALADAPTERCOUNT = 30, - KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, - KMTQAITYPE_DRIVERCAPS_EXT = 32, - KMTQAITYPE_QUERY_MIRACAST_DRIVER_TYPE = 33, - KMTQAITYPE_QUERY_GPUMMU_CAPS = 34, - KMTQAITYPE_QUERY_MULTIPLANEOVERLAY_DECODE_SUPPORT = 35, - KMTQAITYPE_QUERY_HW_PROTECTION_TEARDOWN_COUNT = 36, - KMTQAITYPE_QUERY_ISBADDRIVERFORHWPROTECTIONDISABLED = 37, - KMTQAITYPE_MULTIPLANEOVERLAY_SECONDARY_SUPPORT = 38, - KMTQAITYPE_INDEPENDENTFLIP_SECONDARY_SUPPORT = 39, - KMTQAITYPE_PANELFITTER_SUPPORT = 40, - KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, - KMTQAITYPE_GETSEGMENTGROUPSIZE = 42, - KMTQAITYPE_MPO3DDI_SUPPORT = 43, - KMTQAITYPE_HWDRM_SUPPORT = 44, - KMTQAITYPE_MPOKERNELCAPS_SUPPORT = 45, - KMTQAITYPE_MULTIPLANEOVERLAY_STRETCH_SUPPORT = 46, - KMTQAITYPE_GET_DEVICE_VIDPN_OWNERSHIP_INFO = 47, - KMTQAITYPE_QUERYREGISTRY = 48, - KMTQAITYPE_KMD_DRIVER_VERSION = 49, - KMTQAITYPE_BLOCKLIST_KERNEL = 50, - KMTQAITYPE_BLOCKLIST_RUNTIME = 51, - KMTQAITYPE_ADAPTERGUID_RENDER = 52, - KMTQAITYPE_ADAPTERADDRESS_RENDER = 53, - KMTQAITYPE_ADAPTERREGISTRYINFO_RENDER = 54, - KMTQAITYPE_CHECKDRIVERUPDATESTATUS_RENDER = 55, - KMTQAITYPE_DRIVERVERSION_RENDER = 56, - KMTQAITYPE_ADAPTERTYPE_RENDER = 57, - KMTQAITYPE_WDDM_1_2_CAPS_RENDER = 58, - KMTQAITYPE_WDDM_1_3_CAPS_RENDER = 59, - KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, - KMTQAITYPE_NODEPERFDATA = 61, - KMTQAITYPE_ADAPTERPERFDATA = 62, - KMTQAITYPE_ADAPTERPERFDATA_CAPS = 63, - KMTQUITYPE_GPUVERSION = 64, - KMTQAITYPE_DRIVER_DESCRIPTION = 65, - KMTQAITYPE_DRIVER_DESCRIPTION_RENDER = 66, - KMTQAITYPE_SCANOUT_CAPS = 67, - KMTQAITYPE_DISPLAY_UMDRIVERNAME = 71, - KMTQAITYPE_PARAVIRTUALIZATION_RENDER = 68, - KMTQAITYPE_SERVICENAME = 69, - KMTQAITYPE_WDDM_2_7_CAPS = 70, - KMTQAITYPE_TRACKEDWORKLOAD_SUPPORT = 72 - } + internal enum KMTQUERYADAPTERINFOTYPE + { + KMTQAITYPE_UMDRIVERPRIVATE = 0, + KMTQAITYPE_UMDRIVERNAME = 1, + KMTQAITYPE_UMOPENGLINFO = 2, + KMTQAITYPE_GETSEGMENTSIZE = 3, + KMTQAITYPE_ADAPTERGUID = 4, + KMTQAITYPE_FLIPQUEUEINFO = 5, + KMTQAITYPE_ADAPTERADDRESS = 6, + KMTQAITYPE_SETWORKINGSETINFO = 7, + KMTQAITYPE_ADAPTERREGISTRYINFO = 8, + KMTQAITYPE_CURRENTDISPLAYMODE = 9, + KMTQAITYPE_MODELIST = 10, + KMTQAITYPE_CHECKDRIVERUPDATESTATUS = 11, + KMTQAITYPE_VIRTUALADDRESSINFO = 12, + KMTQAITYPE_DRIVERVERSION = 13, + KMTQAITYPE_ADAPTERTYPE = 15, + KMTQAITYPE_OUTPUTDUPLCONTEXTSCOUNT = 16, + KMTQAITYPE_WDDM_1_2_CAPS = 17, + KMTQAITYPE_UMD_DRIVER_VERSION = 18, + KMTQAITYPE_DIRECTFLIP_SUPPORT = 19, + KMTQAITYPE_MULTIPLANEOVERLAY_SUPPORT = 20, + KMTQAITYPE_DLIST_DRIVER_NAME = 21, + KMTQAITYPE_WDDM_1_3_CAPS = 22, + KMTQAITYPE_MULTIPLANEOVERLAY_HUD_SUPPORT = 23, + KMTQAITYPE_WDDM_2_0_CAPS = 24, + KMTQAITYPE_NODEMETADATA = 25, + KMTQAITYPE_CPDRIVERNAME = 26, + KMTQAITYPE_XBOX = 27, + KMTQAITYPE_INDEPENDENTFLIP_SUPPORT = 28, + KMTQAITYPE_MIRACASTCOMPANIONDRIVERNAME = 29, + KMTQAITYPE_PHYSICALADAPTERCOUNT = 30, + KMTQAITYPE_PHYSICALADAPTERDEVICEIDS = 31, + KMTQAITYPE_DRIVERCAPS_EXT = 32, + KMTQAITYPE_QUERY_MIRACAST_DRIVER_TYPE = 33, + KMTQAITYPE_QUERY_GPUMMU_CAPS = 34, + KMTQAITYPE_QUERY_MULTIPLANEOVERLAY_DECODE_SUPPORT = 35, + KMTQAITYPE_QUERY_HW_PROTECTION_TEARDOWN_COUNT = 36, + KMTQAITYPE_QUERY_ISBADDRIVERFORHWPROTECTIONDISABLED = 37, + KMTQAITYPE_MULTIPLANEOVERLAY_SECONDARY_SUPPORT = 38, + KMTQAITYPE_INDEPENDENTFLIP_SECONDARY_SUPPORT = 39, + KMTQAITYPE_PANELFITTER_SUPPORT = 40, + KMTQAITYPE_PHYSICALADAPTERPNPKEY = 41, + KMTQAITYPE_GETSEGMENTGROUPSIZE = 42, + KMTQAITYPE_MPO3DDI_SUPPORT = 43, + KMTQAITYPE_HWDRM_SUPPORT = 44, + KMTQAITYPE_MPOKERNELCAPS_SUPPORT = 45, + KMTQAITYPE_MULTIPLANEOVERLAY_STRETCH_SUPPORT = 46, + KMTQAITYPE_GET_DEVICE_VIDPN_OWNERSHIP_INFO = 47, + KMTQAITYPE_QUERYREGISTRY = 48, + KMTQAITYPE_KMD_DRIVER_VERSION = 49, + KMTQAITYPE_BLOCKLIST_KERNEL = 50, + KMTQAITYPE_BLOCKLIST_RUNTIME = 51, + KMTQAITYPE_ADAPTERGUID_RENDER = 52, + KMTQAITYPE_ADAPTERADDRESS_RENDER = 53, + KMTQAITYPE_ADAPTERREGISTRYINFO_RENDER = 54, + KMTQAITYPE_CHECKDRIVERUPDATESTATUS_RENDER = 55, + KMTQAITYPE_DRIVERVERSION_RENDER = 56, + KMTQAITYPE_ADAPTERTYPE_RENDER = 57, + KMTQAITYPE_WDDM_1_2_CAPS_RENDER = 58, + KMTQAITYPE_WDDM_1_3_CAPS_RENDER = 59, + KMTQAITYPE_QUERY_ADAPTER_UNIQUE_GUID = 60, + KMTQAITYPE_NODEPERFDATA = 61, + KMTQAITYPE_ADAPTERPERFDATA = 62, + KMTQAITYPE_ADAPTERPERFDATA_CAPS = 63, + KMTQUITYPE_GPUVERSION = 64, + KMTQAITYPE_DRIVER_DESCRIPTION = 65, + KMTQAITYPE_DRIVER_DESCRIPTION_RENDER = 66, + KMTQAITYPE_SCANOUT_CAPS = 67, + KMTQAITYPE_DISPLAY_UMDRIVERNAME = 71, + KMTQAITYPE_PARAVIRTUALIZATION_RENDER = 68, + KMTQAITYPE_SERVICENAME = 69, + KMTQAITYPE_WDDM_2_7_CAPS = 70, + KMTQAITYPE_TRACKEDWORKLOAD_SUPPORT = 72 } } diff --git a/LibreHardwareMonitorLib/Interop/Ftd2xx.cs b/LibreHardwareMonitorLib/Interop/Ftd2xx.cs index f91ba8f..e3c3bed 100644 --- a/LibreHardwareMonitorLib/Interop/Ftd2xx.cs +++ b/LibreHardwareMonitorLib/Interop/Ftd2xx.cs @@ -8,177 +8,176 @@ using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class Ftd2xx { - internal static class Ftd2xx + private const string DllName = "Ftd2xx.dll"; + + public static bool DllExists() { - private const string DllName = "Ftd2xx.dll"; + IntPtr module = Kernel32.LoadLibrary(DllName); + if (module == IntPtr.Zero) + return false; - public static bool DllExists() - { - IntPtr module = Kernel32.LoadLibrary(DllName); - if (module == IntPtr.Zero) - return false; - - Kernel32.FreeLibrary(module); - return true; - } - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_CreateDeviceInfoList(out uint numDevices); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_GetDeviceInfoList([Out] FT_DEVICE_INFO_NODE[] deviceInfoNodes, ref uint length); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_Open(int device, out FT_HANDLE handle); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_Close(FT_HANDLE handle); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_SetBaudRate(FT_HANDLE handle, uint baudRate); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_SetDataCharacteristics(FT_HANDLE handle, byte wordLength, byte stopBits, byte parity); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_SetFlowControl(FT_HANDLE handle, FT_FLOW_CONTROL flowControl, byte xon, byte xoff); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_SetTimeouts(FT_HANDLE handle, uint readTimeout, uint writeTimeout); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_Write(FT_HANDLE handle, byte[] buffer, uint bytesToWrite, out uint bytesWritten); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_Purge(FT_HANDLE handle, FT_PURGE mask); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_GetStatus(FT_HANDLE handle, out uint amountInRxQueue, out uint amountInTxQueue, out uint eventStatus); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_Read(FT_HANDLE handle, [Out] byte[] buffer, uint bytesToRead, out uint bytesReturned); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - public static extern FT_STATUS FT_ReadByte(FT_HANDLE handle, out byte buffer, uint bytesToRead, out uint bytesReturned); - - public static FT_STATUS Write(FT_HANDLE handle, byte[] buffer) - { - FT_STATUS status = FT_Write(handle, buffer, (uint)buffer.Length, out uint bytesWritten); - if (bytesWritten != buffer.Length) - return FT_STATUS.FT_FAILED_TO_WRITE_DEVICE; - - return status; - } - - public static int BytesToRead(FT_HANDLE handle) - { - if (FT_GetStatus(handle, out uint amountInRxQueue, out uint _, out uint _) == FT_STATUS.FT_OK) - return (int)amountInRxQueue; - - return 0; - } - - public static byte ReadByte(FT_HANDLE handle) - { - FT_STATUS status = FT_ReadByte(handle, out byte buffer, 1, out uint bytesReturned); - if (status != FT_STATUS.FT_OK || bytesReturned != 1) - throw new InvalidOperationException(); - - return buffer; - } - - public static void Read(FT_HANDLE handle, byte[] buffer) - { - FT_STATUS status = FT_Read(handle, buffer, (uint)buffer.Length, out uint bytesReturned); - if (status != FT_STATUS.FT_OK || bytesReturned != buffer.Length) - throw new InvalidOperationException(); - } - - internal enum FT_DEVICE : uint - { - FT_DEVICE_232BM, - FT_DEVICE_232AM, - FT_DEVICE_100AX, - FT_DEVICE_UNKNOWN, - FT_DEVICE_2232C, - FT_DEVICE_232R, - FT_DEVICE_2232H, - FT_DEVICE_4232H - } - - internal enum FT_STATUS - { - FT_OK, - FT_INVALID_HANDLE, - FT_DEVICE_NOT_FOUND, - FT_DEVICE_NOT_OPENED, - FT_IO_ERROR, - FT_INSUFFICIENT_RESOURCES, - FT_INVALID_PARAMETER, - FT_INVALID_BAUD_RATE, - FT_DEVICE_NOT_OPENED_FOR_ERASE, - FT_DEVICE_NOT_OPENED_FOR_WRITE, - FT_FAILED_TO_WRITE_DEVICE, - FT_EEPROM_READ_FAILED, - FT_EEPROM_WRITE_FAILED, - FT_EEPROM_ERASE_FAILED, - FT_EEPROM_NOT_PRESENT, - FT_EEPROM_NOT_PROGRAMMED, - FT_INVALID_ARGS, - FT_OTHER_ERROR - } - - internal enum FT_FLOW_CONTROL : ushort - { - FT_FLOW_DTR_DSR = 512, - FT_FLOW_NONE = 0, - FT_FLOW_RTS_CTS = 256, - FT_FLOW_XON_XOFF = 1024 - } - - internal enum FT_PURGE : uint - { - FT_PURGE_RX = 1, - FT_PURGE_TX = 2, - FT_PURGE_ALL = 3 - } - - [StructLayout(LayoutKind.Sequential)] - internal struct FT_HANDLE - { - private readonly uint _handle; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct FT_DEVICE_INFO_NODE - { - public uint Flags; - public FT_DEVICE Type; - public uint ID; - public uint LocId; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] - public string SerialNumber; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] - public string Description; - - public FT_HANDLE Handle; - } + Kernel32.FreeLibrary(module); + return true; } -} + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_CreateDeviceInfoList(out uint numDevices); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_GetDeviceInfoList([Out] FT_DEVICE_INFO_NODE[] deviceInfoNodes, ref uint length); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_Open(int device, out FT_HANDLE handle); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_Close(FT_HANDLE handle); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_SetBaudRate(FT_HANDLE handle, uint baudRate); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_SetDataCharacteristics(FT_HANDLE handle, byte wordLength, byte stopBits, byte parity); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_SetFlowControl(FT_HANDLE handle, FT_FLOW_CONTROL flowControl, byte xon, byte xoff); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_SetTimeouts(FT_HANDLE handle, uint readTimeout, uint writeTimeout); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_Write(FT_HANDLE handle, byte[] buffer, uint bytesToWrite, out uint bytesWritten); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_Purge(FT_HANDLE handle, FT_PURGE mask); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_GetStatus(FT_HANDLE handle, out uint amountInRxQueue, out uint amountInTxQueue, out uint eventStatus); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_Read(FT_HANDLE handle, [Out] byte[] buffer, uint bytesToRead, out uint bytesReturned); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + public static extern FT_STATUS FT_ReadByte(FT_HANDLE handle, out byte buffer, uint bytesToRead, out uint bytesReturned); + + public static FT_STATUS Write(FT_HANDLE handle, byte[] buffer) + { + FT_STATUS status = FT_Write(handle, buffer, (uint)buffer.Length, out uint bytesWritten); + if (bytesWritten != buffer.Length) + return FT_STATUS.FT_FAILED_TO_WRITE_DEVICE; + + return status; + } + + public static int BytesToRead(FT_HANDLE handle) + { + if (FT_GetStatus(handle, out uint amountInRxQueue, out uint _, out uint _) == FT_STATUS.FT_OK) + return (int)amountInRxQueue; + + return 0; + } + + public static byte ReadByte(FT_HANDLE handle) + { + FT_STATUS status = FT_ReadByte(handle, out byte buffer, 1, out uint bytesReturned); + if (status != FT_STATUS.FT_OK || bytesReturned != 1) + throw new InvalidOperationException(); + + return buffer; + } + + public static void Read(FT_HANDLE handle, byte[] buffer) + { + FT_STATUS status = FT_Read(handle, buffer, (uint)buffer.Length, out uint bytesReturned); + if (status != FT_STATUS.FT_OK || bytesReturned != buffer.Length) + throw new InvalidOperationException(); + } + + internal enum FT_DEVICE : uint + { + FT_DEVICE_232BM, + FT_DEVICE_232AM, + FT_DEVICE_100AX, + FT_DEVICE_UNKNOWN, + FT_DEVICE_2232C, + FT_DEVICE_232R, + FT_DEVICE_2232H, + FT_DEVICE_4232H + } + + internal enum FT_STATUS + { + FT_OK, + FT_INVALID_HANDLE, + FT_DEVICE_NOT_FOUND, + FT_DEVICE_NOT_OPENED, + FT_IO_ERROR, + FT_INSUFFICIENT_RESOURCES, + FT_INVALID_PARAMETER, + FT_INVALID_BAUD_RATE, + FT_DEVICE_NOT_OPENED_FOR_ERASE, + FT_DEVICE_NOT_OPENED_FOR_WRITE, + FT_FAILED_TO_WRITE_DEVICE, + FT_EEPROM_READ_FAILED, + FT_EEPROM_WRITE_FAILED, + FT_EEPROM_ERASE_FAILED, + FT_EEPROM_NOT_PRESENT, + FT_EEPROM_NOT_PROGRAMMED, + FT_INVALID_ARGS, + FT_OTHER_ERROR + } + + internal enum FT_FLOW_CONTROL : ushort + { + FT_FLOW_DTR_DSR = 512, + FT_FLOW_NONE = 0, + FT_FLOW_RTS_CTS = 256, + FT_FLOW_XON_XOFF = 1024 + } + + internal enum FT_PURGE : uint + { + FT_PURGE_RX = 1, + FT_PURGE_TX = 2, + FT_PURGE_ALL = 3 + } + + [StructLayout(LayoutKind.Sequential)] + internal struct FT_HANDLE + { + private readonly uint _handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct FT_DEVICE_INFO_NODE + { + public uint Flags; + public FT_DEVICE Type; + public uint ID; + public uint LocId; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] + public string SerialNumber; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] + public string Description; + + public FT_HANDLE Handle; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/Gdi32.cs b/LibreHardwareMonitorLib/Interop/Gdi32.cs index 8fab398..d363b9c 100644 --- a/LibreHardwareMonitorLib/Interop/Gdi32.cs +++ b/LibreHardwareMonitorLib/Interop/Gdi32.cs @@ -8,26 +8,25 @@ using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class Gdi32 { - internal static class Gdi32 - { - internal const string DllName = "Gdi32.dll"; + internal const string DllName = "Gdi32.dll"; - [DllImport(DllName, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern uint D3DKMTCloseAdapter(ref D3dkmth.D3DKMT_CLOSEADAPTER closeAdapter); + [DllImport(DllName, ExactSpelling = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern uint D3DKMTCloseAdapter(ref D3dkmth.D3DKMT_CLOSEADAPTER closeAdapter); - [DllImport(DllName, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern uint D3DKMTOpenAdapterFromDeviceName(ref D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName); + [DllImport(DllName, ExactSpelling = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern uint D3DKMTOpenAdapterFromDeviceName(ref D3dkmth.D3DKMT_OPENADAPTERFROMDEVICENAME openAdapterFromDeviceName); - [DllImport(DllName, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern uint D3DKMTQueryAdapterInfo(ref D3dkmth.D3DKMT_QUERYADAPTERINFO queryAdapterInfo); + [DllImport(DllName, ExactSpelling = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern uint D3DKMTQueryAdapterInfo(ref D3dkmth.D3DKMT_QUERYADAPTERINFO queryAdapterInfo); - [DllImport(DllName, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern uint D3DKMTQueryStatistics(ref D3dkmth.D3DKMT_QUERYSTATISTICS queryStatistics); - } -} + [DllImport(DllName, ExactSpelling = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern uint D3DKMTQueryStatistics(ref D3dkmth.D3DKMT_QUERYSTATISTICS queryStatistics); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/InpOut.cs b/LibreHardwareMonitorLib/Interop/InpOut.cs index b9a094c..1e5a216 100644 --- a/LibreHardwareMonitorLib/Interop/InpOut.cs +++ b/LibreHardwareMonitorLib/Interop/InpOut.cs @@ -1,19 +1,18 @@ using System; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal class InpOut { - internal class InpOut - { - public delegate IntPtr MapPhysToLinDelegate(IntPtr pbPhysAddr, uint dwPhysSize, out IntPtr pPhysicalMemoryHandle); + public delegate IntPtr MapPhysToLinDelegate(IntPtr pbPhysAddr, uint dwPhysSize, out IntPtr pPhysicalMemoryHandle); - public delegate bool UnmapPhysicalMemoryDelegate(IntPtr PhysicalMemoryHandle, IntPtr pbLinAddr); + public delegate bool UnmapPhysicalMemoryDelegate(IntPtr PhysicalMemoryHandle, IntPtr pbLinAddr); - [DllImport("inpout.dll", EntryPoint = "MapPhysToLin", CallingConvention = CallingConvention.StdCall)] - public static extern IntPtr MapPhysToLin(IntPtr pbPhysAddr, uint dwPhysSize, out IntPtr pPhysicalMemoryHandle); + [DllImport("inpout.dll", EntryPoint = "MapPhysToLin", CallingConvention = CallingConvention.StdCall)] + public static extern IntPtr MapPhysToLin(IntPtr pbPhysAddr, uint dwPhysSize, out IntPtr pPhysicalMemoryHandle); - [DllImport("inpout.dll", EntryPoint = "UnmapPhysicalMemory", CallingConvention = CallingConvention.StdCall)] - [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle, IntPtr pbLinAddr); - } -} + [DllImport("inpout.dll", EntryPoint = "UnmapPhysicalMemory", CallingConvention = CallingConvention.StdCall)] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool UnmapPhysicalMemory(IntPtr PhysicalMemoryHandle, IntPtr pbLinAddr); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/Kernel32.cs b/LibreHardwareMonitorLib/Interop/Kernel32.cs index 8bf94a5..64d2c38 100644 --- a/LibreHardwareMonitorLib/Interop/Kernel32.cs +++ b/LibreHardwareMonitorLib/Interop/Kernel32.cs @@ -10,1553 +10,1552 @@ using Microsoft.Win32.SafeHandles; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +public class Kernel32 { - public class Kernel32 + public const int ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420); + + public const int ERROR_SERVICE_EXISTS = unchecked((int)0x80070431); + + internal const uint BATTERY_UNKNOWN_TIME = 0xFFFFFFFF; + internal const string IntelNVMeMiniPortSignature1 = "NvmeMini"; + internal const string IntelNVMeMiniPortSignature2 = "IntelNvm"; + + internal const uint LPTR = 0x0000 | 0x0040; + + internal const int MAX_DRIVE_ATTRIBUTES = 512; + internal const uint NVME_PASS_THROUGH_SRB_IO_CODE = 0xe0002000; + internal const byte SMART_LBA_HI = 0xC2; + internal const byte SMART_LBA_HI_EXCEEDED = 0x2C; + internal const byte SMART_LBA_MID = 0x4F; + internal const byte SMART_LBA_MID_EXCEEDED = 0xF4; + + private const string DllName = "kernel32.dll"; + + [Flags] + public enum NVME_CRITICAL_WARNING { - public const int ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420); - - public const int ERROR_SERVICE_EXISTS = unchecked((int)0x80070431); - - internal const uint BATTERY_UNKNOWN_TIME = 0xFFFFFFFF; - internal const string IntelNVMeMiniPortSignature1 = "NvmeMini"; - internal const string IntelNVMeMiniPortSignature2 = "IntelNvm"; - - internal const uint LPTR = 0x0000 | 0x0040; - - internal const int MAX_DRIVE_ATTRIBUTES = 512; - internal const uint NVME_PASS_THROUGH_SRB_IO_CODE = 0xe0002000; - internal const byte SMART_LBA_HI = 0xC2; - internal const byte SMART_LBA_HI_EXCEEDED = 0x2C; - internal const byte SMART_LBA_MID = 0x4F; - internal const byte SMART_LBA_MID_EXCEEDED = 0xF4; - - private const string DllName = "kernel32.dll"; - - [Flags] - public enum NVME_CRITICAL_WARNING - { - None = 0x00, - - /// - /// If set to 1, then the available spare space has fallen below the threshold. - /// - AvailableSpaceLow = 0x01, - - /// - /// If set to 1, then a temperature is above an over temperature threshold or below an under temperature threshold. - /// - TemperatureThreshold = 0x02, - - /// - /// If set to 1, then the device reliability has been degraded due to significant media related errors or any internal error that degrades device reliability. - /// - ReliabilityDegraded = 0x04, - - /// - /// If set to 1, then the media has been placed in read only mode - /// - ReadOnly = 0x08, - - /// - /// If set to 1, then the volatile memory backup device has failed. This field is only valid if the controller has a volatile memory backup solution. - /// - VolatileMemoryBackupDeviceFailed = 0x10 - } + None = 0x00, /// - /// Create a instance from a struct with zero initialized memory arrays - /// no need to init every inner array with the correct sizes + /// If set to 1, then the available spare space has fallen below the threshold. /// - /// type of struct that is needed - /// - internal static T CreateStruct() + AvailableSpaceLow = 0x01, + + /// + /// If set to 1, then a temperature is above an over temperature threshold or below an under temperature threshold. + /// + TemperatureThreshold = 0x02, + + /// + /// If set to 1, then the device reliability has been degraded due to significant media related errors or any internal error that degrades device reliability. + /// + ReliabilityDegraded = 0x04, + + /// + /// If set to 1, then the media has been placed in read only mode + /// + ReadOnly = 0x08, + + /// + /// If set to 1, then the volatile memory backup device has failed. This field is only valid if the controller has a volatile memory backup solution. + /// + VolatileMemoryBackupDeviceFailed = 0x10 + } + + /// + /// Create a instance from a struct with zero initialized memory arrays + /// no need to init every inner array with the correct sizes + /// + /// type of struct that is needed + /// + internal static T CreateStruct() + { + int size = Marshal.SizeOf(); + IntPtr ptr = Marshal.AllocHGlobal(size); + RtlZeroMemory(ptr, size); + T result = Marshal.PtrToStructure(ptr); + Marshal.FreeHGlobal(ptr); + return result; + } + + internal static SafeHandle OpenDevice(string devicePath) + { + SafeHandle hDevice = CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); + if (hDevice.IsInvalid || hDevice.IsClosed) + hDevice = null; + + return hDevice; + } + + [DllImport(DllName, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern SafeFileHandle CreateFile + ( + [MarshalAs(UnmanagedType.LPTStr)] string lpFileName, + [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, + [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, + IntPtr lpSecurityAttributes, + [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, + [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, + IntPtr hTemplateFile); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + DFP dwIoControlCode, + ref SENDCMDINPARAMS lpInBuffer, + int nInBufferSize, + out ATTRIBUTECMDOUTPARAMS lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + DFP dwIoControlCode, + ref SENDCMDINPARAMS lpInBuffer, + int nInBufferSize, + out THRESHOLDCMDOUTPARAMS lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + DFP dwIoControlCode, + ref SENDCMDINPARAMS lpInBuffer, + int nInBufferSize, + out SENDCMDOUTPARAMS lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + DFP dwIoControlCode, + ref SENDCMDINPARAMS lpInBuffer, + int nInBufferSize, + out IDENTIFYCMDOUTPARAMS lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + DFP dwIoControlCode, + ref SENDCMDINPARAMS lpInBuffer, + int nInBufferSize, + out STATUSCMDOUTPARAMS lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + IOCTL dwIoControlCode, + ref STORAGE_PROPERTY_QUERY lpInBuffer, + int nInBufferSize, + out STORAGE_DEVICE_DESCRIPTOR_HEADER lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + IOCTL dwIoControlCode, + ref STORAGE_PROPERTY_QUERY lpInBuffer, + int nInBufferSize, + IntPtr lpOutBuffer, + uint nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeHandle hDevice, + IOCTL dwIoControlCode, + IntPtr lpInBuffer, + int nInBufferSize, + IntPtr lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeFileHandle hDevice, + IOCTL dwIoControlCode, + ref BATTERY_QUERY_INFORMATION lpInBuffer, + int nInBufferSize, + ref BATTERY_INFORMATION lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeFileHandle hDevice, + IOCTL dwIoControlCode, + ref uint lpInBuffer, + int nInBufferSize, + ref uint lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeFileHandle hDevice, + IOCTL dwIoControlCode, + ref BATTERY_WAIT_STATUS lpInBuffer, + int nInBufferSize, + ref BATTERY_STATUS lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeFileHandle hDevice, + IOCTL dwIoControlCode, + ref BATTERY_QUERY_INFORMATION lpInBuffer, + int nInBufferSize, + IntPtr lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool DeviceIoControl + ( + SafeFileHandle hDevice, + IOCTL dwIoControlCode, + ref BATTERY_QUERY_INFORMATION lpInBuffer, + int nInBufferSize, + ref uint lpOutBuffer, + int nOutBufferSize, + out uint lpBytesReturned, + IntPtr lpOverlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr LocalAlloc(uint uFlags, ulong uBytes); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr LocalFree(IntPtr hMem); + + [DllImport(DllName, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern void RtlZeroMemory(IntPtr Destination, int Length); + + [DllImport(DllName, SetLastError = false)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern void RtlCopyMemory(IntPtr Destination, IntPtr Source, uint Length); + + [DllImport(DllName, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr LoadLibrary(string lpFileName); + + [DllImport(DllName, ExactSpelling = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr GetProcAddress(IntPtr module, string methodName); + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool FreeLibrary(IntPtr module); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern UIntPtr SetThreadAffinityMask(IntPtr handle, UIntPtr mask); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr GetCurrentThread(); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern ushort GetActiveProcessorGroupCount(); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern bool SetThreadGroupAffinity(IntPtr thread, ref GROUP_AFFINITY groupAffinity, out GROUP_AFFINITY previousGroupAffinity); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, MEM flAllocationType, PAGE flProtect); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize, MEM dwFreeType); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern bool DeviceIoControl + ( + SafeFileHandle device, + IOControlCode ioControlCode, + [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, + uint inBufferSize, + [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer, + uint nOutBufferSize, + out uint bytesReturned, + IntPtr overlapped); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr CreateFile + ( + string lpFileName, + uint dwDesiredAccess, + FileShare dwShareMode, + IntPtr lpSecurityAttributes, + FileMode dwCreationDisposition, + FileAttributes dwFlagsAndAttributes, + IntPtr hTemplateFile); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern int EnumSystemFirmwareTables(Provider firmwareTableProviderSignature, IntPtr firmwareTableBuffer, int bufferSize); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern int GetSystemFirmwareTable(Provider firmwareTableProviderSignature, int firmwareTableID, IntPtr firmwareTableBuffer, int bufferSize); + + [StructLayout(LayoutKind.Sequential, Pack = 4)] + public struct GROUP_AFFINITY + { + public UIntPtr Mask; + + [MarshalAs(UnmanagedType.U2)] + public ushort Group; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U2)] + public ushort[] Reserved; + } + + internal enum DFP : uint + { + DFP_GET_VERSION = 0x00074080, + DFP_SEND_DRIVE_COMMAND = 0x0007c084, + DFP_RECEIVE_DRIVE_DATA = 0x0007c088 + } + + internal enum IOCTL : uint + { + IOCTL_SCSI_PASS_THROUGH = 0x04d004, + IOCTL_SCSI_MINIPORT = 0x04d008, + IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x04d014, + IOCTL_SCSI_GET_ADDRESS = 0x41018, + IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400, + IOCTL_BATTERY_QUERY_TAG = 0x294040, + IOCTL_BATTERY_QUERY_INFORMATION = 0x294044, + IOCTL_BATTERY_QUERY_STATUS = 0x29404C + } + + [Flags] + internal enum BatteryCapabilities : uint + { + BATTERY_CAPACITY_RELATIVE = 0x40000000, + BATTERY_IS_SHORT_TERM = 0x20000000, + BATTERY_SET_CHARGE_SUPPORTED = 0x00000001, + BATTERY_SET_DISCHARGE_SUPPORTED = 0x00000002, + BATTERY_SYSTEM_BATTERY = 0x80000000 + } + + internal enum BATTERY_QUERY_INFORMATION_LEVEL + { + BatteryInformation, + BatteryGranularityInformation, + BatteryTemperature, + BatteryEstimatedTime, + BatteryDeviceName, + BatteryManufactureDate, + BatteryManufactureName, + BatteryUniqueID, + BatterySerialNumber + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BATTERY_QUERY_INFORMATION + { + public uint BatteryTag; + public BATTERY_QUERY_INFORMATION_LEVEL InformationLevel; + public uint AtRate; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BATTERY_INFORMATION + { + public BatteryCapabilities Capabilities; + public byte Technology; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] Reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public char[] Chemistry; + + public uint DesignedCapacity; + public uint FullChargedCapacity; + public uint DefaultAlert1; + public uint DefaultAlert2; + public uint CriticalBias; + public uint CycleCount; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BATTERY_WAIT_STATUS + { + public uint BatteryTag; + public uint Timeout; + public uint PowerState; + public uint LowCapacity; + public uint HighCapacity; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct BATTERY_STATUS + { + public uint PowerState; + public uint Capacity; + public uint Voltage; + public int Rate; + } + + [Flags] + internal enum NVME_DIRECTION : uint + { + NVME_FROM_HOST_TO_DEV = 1, + NVME_FROM_DEV_TO_HOST = 2, + NVME_BI_DIRECTION = NVME_FROM_DEV_TO_HOST | NVME_FROM_HOST_TO_DEV + } + + internal enum NVME_LOG_PAGES + { + NVME_LOG_PAGE_ERROR_INFO = 0x01, + NVME_LOG_PAGE_HEALTH_INFO = 0x02, + NVME_LOG_PAGE_FIRMWARE_SLOT_INFO = 0x03, + NVME_LOG_PAGE_CHANGED_NAMESPACE_LIST = 0x04, + NVME_LOG_PAGE_COMMAND_EFFECTS = 0x05, + NVME_LOG_PAGE_DEVICE_SELF_TEST = 0x06, + NVME_LOG_PAGE_TELEMETRY_HOST_INITIATED = 0x07, + NVME_LOG_PAGE_TELEMETRY_CTLR_INITIATED = 0x08, + NVME_LOG_PAGE_RESERVATION_NOTIFICATION = 0x80, + NVME_LOG_PAGE_SANITIZE_STATUS = 0x81 + } + + internal enum ATA_COMMAND : byte + { + /// + /// SMART data requested. + /// + ATA_SMART = 0xB0, + + /// + /// Identify data is requested. + /// + ATA_IDENTIFY_DEVICE = 0xEC + } + + internal enum SCSI_IOCTL_DATA + { + SCSI_IOCTL_DATA_OUT = 0, + SCSI_IOCTL_DATA_IN = 1, + SCSI_IOCTL_DATA_UNSPECIFIED = 2 + } + + internal enum SMART_FEATURES : byte + { + /// + /// Read SMART data. + /// + SMART_READ_DATA = 0xD0, + + /// + /// Read SMART thresholds. + /// obsolete + /// + READ_THRESHOLDS = 0xD1, + + /// + /// Autosave SMART data. + /// + ENABLE_DISABLE_AUTOSAVE = 0xD2, + + /// + /// Save SMART attributes. + /// + SAVE_ATTRIBUTE_VALUES = 0xD3, + + /// + /// Set SMART to offline immediately. + /// + EXECUTE_OFFLINE_DIAGS = 0xD4, + + /// + /// Read SMART log. + /// + SMART_READ_LOG = 0xD5, + + /// + /// Write SMART log. + /// + SMART_WRITE_LOG = 0xD6, + + /// + /// Write SMART thresholds. + /// obsolete + /// + WRITE_THRESHOLDS = 0xD7, + + /// + /// Enable SMART. + /// + ENABLE_SMART = 0xD8, + + /// + /// Disable SMART. + /// + DISABLE_SMART = 0xD9, + + /// + /// Get SMART status. + /// + RETURN_SMART_STATUS = 0xDA, + + /// + /// Set SMART to offline automatically. + /// + ENABLE_DISABLE_AUTO_OFFLINE = 0xDB /* obsolete */ + } + + internal enum STORAGE_BUS_TYPE + { + BusTypeUnknown = 0x00, + BusTypeScsi, + BusTypeAtapi, + BusTypeAta, + BusType1394, + BusTypeSsa, + BusTypeFibre, + BusTypeUsb, + BusTypeRAID, + BusTypeiScsi, + BusTypeSas, + BusTypeSata, + BusTypeSd, + BusTypeMmc, + BusTypeVirtual, + BusTypeFileBackedVirtual, + BusTypeSpaces, + BusTypeNvme, + BusTypeSCM, + BusTypeMax, + BusTypeMaxReserved = 0x7F + } + + internal enum STORAGE_PROPERTY_ID + { + StorageDeviceProperty = 0, + StorageAdapterProperty, + StorageDeviceIdProperty, + StorageDeviceUniqueIdProperty, + StorageDeviceWriteCacheProperty, + StorageMiniportProperty, + StorageAccessAlignmentProperty, + StorageDeviceSeekPenaltyProperty, + StorageDeviceTrimProperty, + StorageDeviceWriteAggregationProperty, + StorageDeviceDeviceTelemetryProperty, + StorageDeviceLBProvisioningProperty, + StorageDevicePowerProperty, + StorageDeviceCopyOffloadProperty, + StorageDeviceResiliencyProperty, + StorageDeviceMediumProductType, + StorageAdapterRpmbProperty, + StorageDeviceIoCapabilityProperty = 48, + StorageAdapterProtocolSpecificProperty, + StorageDeviceProtocolSpecificProperty, + StorageAdapterTemperatureProperty, + StorageDeviceTemperatureProperty, + StorageAdapterPhysicalTopologyProperty, + StorageDevicePhysicalTopologyProperty, + StorageDeviceAttributesProperty, + StorageDeviceManagementStatus, + StorageAdapterSerialNumberProperty, + StorageDeviceLocationProperty + } + + internal enum STORAGE_PROTOCOL_NVME_DATA_TYPE + { + NVMeDataTypeUnknown = 0, + NVMeDataTypeIdentify, + NVMeDataTypeLogPage, + NVMeDataTypeFeature + } + + internal enum STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE + { + NVMeIdentifyCnsSpecificNamespace = 0, + NVMeIdentifyCnsController = 1, + NVMeIdentifyCnsActiveNamespaces = 2 + } + + internal enum STORAGE_PROTOCOL_TYPE + { + ProtocolTypeUnknown = 0x00, + ProtocolTypeScsi, + ProtocolTypeAta, + ProtocolTypeNvme, + ProtocolTypeSd, + ProtocolTypeProprietary = 0x7E, + ProtocolTypeMaxReserved = 0x7F + } + + internal enum STORAGE_QUERY_TYPE + { + PropertyStandardQuery = 0, + PropertyExistsQuery, + PropertyMaskQuery, + PropertyQueryMaxDefined + } + + [StructLayout(LayoutKind.Sequential)] + internal struct MEMORYSTATUSEX + { + public uint dwLength; + public uint dwMemoryLoad; + public ulong ullTotalPhys; + public ulong ullAvailPhys; + public ulong ullTotalPageFile; + public ulong ullAvailPageFile; + public ulong ullTotalVirtual; + public ulong ullAvailVirtual; + public ulong ullAvailExtendedVirtual; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SMART_ATTRIBUTE + { + public byte Id; + public short Flags; + public byte CurrentValue; + public byte WorstValue; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public byte[] RawValue; + + public byte Reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct SMART_THRESHOLD + { + public byte Id; + public byte Threshold; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] Reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct SENDCMDINPARAMS + { + public uint cBufferSize; + public IDEREGS irDriveRegs; + public byte bDriveNumber; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] bReserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public uint[] dwReserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public byte[] bBuffer; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct IDEREGS + { + public SMART_FEATURES bFeaturesReg; + public byte bSectorCountReg; + public byte bSectorNumberReg; + public byte bCylLowReg; + public byte bCylHighReg; + public byte bDriveHeadReg; + public ATA_COMMAND bCommandReg; + public byte bReserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct DRIVERSTATUS + { + public byte bDriverError; + public byte bIDEError; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] + public byte[] Reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct SENDCMDOUTPARAMS + { + public uint cBufferSize; + public DRIVERSTATUS DriverStatus; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public byte[] bBuffer; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct ATTRIBUTECMDOUTPARAMS + { + public uint cBufferSize; + public DRIVERSTATUS DriverStatus; + public byte Version; + public byte Reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)] + public SMART_ATTRIBUTE[] Attributes; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct THRESHOLDCMDOUTPARAMS + { + public uint cBufferSize; + public DRIVERSTATUS DriverStatus; + public byte Version; + public byte Reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)] + public SMART_THRESHOLD[] Thresholds; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct STATUSCMDOUTPARAMS + { + public uint cBufferSize; + public DRIVERSTATUS DriverStatus; + public IDEREGS irDriveRegs; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct IDENTIFY_DATA + { + public ushort GeneralConfiguration; + public ushort NumberOfCylinders; + public ushort Reserved1; + public ushort NumberOfHeads; + public ushort UnformattedBytesPerTrack; + public ushort UnformattedBytesPerSector; + public ushort SectorsPerTrack; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public ushort[] VendorUnique; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public byte[] SerialNumber; + + public ushort BufferType; + public ushort BufferSectorSize; + public ushort NumberOfEccBytes; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] FirmwareRevision; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] + public byte[] ModelNumber; + + public byte MaximumBlockTransfer; + public byte VendorUnique2; + public ushort DoubleWordIo; + public ushort Capabilities; + public ushort Reserved2; + public byte VendorUnique3; + public byte PioCycleTimingMode; + public byte VendorUnique4; + public byte DmaCycleTimingMode; + public ushort TranslationFieldsValid; + public ushort NumberOfCurrentCylinders; + public ushort NumberOfCurrentHeads; + public ushort CurrentSectorsPerTrack; + public uint CurrentSectorCapacity; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 197)] + public ushort[] Reserved3; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct IDENTIFYCMDOUTPARAMS + { + public uint cBufferSize; + public DRIVERSTATUS DriverStatus; + public IDENTIFY_DATA Identify; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct STORAGE_PROPERTY_QUERY + { + public STORAGE_PROPERTY_ID PropertyId; + public STORAGE_QUERY_TYPE QueryType; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public byte[] AdditionalParameters; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct STORAGE_DEVICE_DESCRIPTOR_HEADER + { + public uint Version; + public uint Size; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct STORAGE_DEVICE_DESCRIPTOR + { + public uint Version; + public uint Size; + public byte DeviceType; + public byte DeviceTypeModifier; + + [MarshalAs(UnmanagedType.U1)] + public bool RemovableMedia; + + [MarshalAs(UnmanagedType.U1)] + public bool CommandQueueing; + + public uint VendorIdOffset; + public uint ProductIdOffset; + public uint ProductRevisionOffset; + public uint SerialNumberOffset; + public STORAGE_BUS_TYPE BusType; + public uint RawPropertiesLength; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SRB_IO_CONTROL + { + public uint HeaderLenght; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] Signature; + + public uint Timeout; + public uint ControlCode; + public uint ReturnCode; + public uint Length; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NVME_PASS_THROUGH_IOCTL + { + public SRB_IO_CONTROL srb; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] + public uint[] VendorSpecific; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public uint[] NVMeCmd; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] + public uint[] CplEntry; + + public NVME_DIRECTION Direction; + public uint QueueId; + public uint DataBufferLen; + public uint MetaDataLen; + public uint ReturnBufferLen; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] + public byte[] DataBuffer; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SCSI_PASS_THROUGH + { + [MarshalAs(UnmanagedType.U2)] + public ushort Length; + + public byte ScsiStatus; + public byte PathId; + public byte TargetId; + public byte Lun; + public byte CdbLength; + public byte SenseInfoLength; + public byte DataIn; + public uint DataTransferLength; + public uint TimeOutValue; + public IntPtr DataBufferOffset; + public uint SenseInfoOffset; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] Cdb; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct SCSI_PASS_THROUGH_WITH_BUFFERS + { + public SCSI_PASS_THROUGH Spt; + + public uint Filler; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public byte[] SenseBuf; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] + public byte[] DataBuf; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NVME_POWER_STATE_DESC + { + /// + /// bit 0:15 Maximum Power (MP) in centiwatts + /// + public ushort MP; + + /// + /// bit 16:23 + /// + public byte Reserved0; + + /// + /// bit 24 Max Power Scale (MPS), bit 25 Non-Operational State (NOPS) + /// + public byte MPS_NOPS; + + /// + /// bit 32:63 Entry Latency (ENLAT) in microseconds + /// + public uint ENLAT; + + /// + /// bit 64:95 Exit Latency (EXLAT) in microseconds + /// + public uint EXLAT; + + /// + /// bit 96:100 Relative Read Throughput (RRT) + /// + public byte RRT; + + /// + /// bit 104:108 Relative Read Latency (RRL) + /// + public byte RRL; + + /// + /// bit 112:116 Relative Write Throughput (RWT) + /// + public byte RWT; + + /// + /// bit 120:124 Relative Write Latency (RWL) + /// + public byte RWL; + + /// + /// bit 128:143 Idle Power (IDLP) + /// + public ushort IDLP; + + /// + /// bit 150:151 Idle Power Scale (IPS) + /// + public byte IPS; + + /// + /// bit 152:159 + /// + public byte Reserved7; + + /// + /// bit 160:175 Active Power (ACTP) + /// + public ushort ACTP; + + /// + /// bit 176:178 Active Power Workload (APW), bit 182:183 Active Power Scale (APS) + /// + public byte APW_APS; + + /// + /// bit 184:255. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] + public byte[] Reserved9; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NVME_IDENTIFY_CONTROLLER_DATA + { + /// + /// byte 0:1 M - PCI Vendor ID (VID) + /// + public ushort VID; + + /// + /// byte 2:3 M - PCI Subsystem Vendor ID (SSVID) + /// + public ushort SSVID; + + /// + /// byte 4: 23 M - Serial Number (SN) + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] + public byte[] SN; + + /// + /// byte 24:63 M - Model Number (MN) + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] + public byte[] MN; + + /// + /// byte 64:71 M - Firmware Revision (FR) + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] FR; + + /// + /// byte 72 M - Recommended Arbitration Burst (RAB) + /// + public byte RAB; + + /// + /// byte 73:75 M - IEEE OUI Identifier (IEEE). Controller Vendor code. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] IEEE; + + /// + /// byte 76 O - Controller Multi-Path I/O and Namespace Sharing Capabilities (CMIC) + /// + public byte CMIC; + + /// + /// byte 77 M - Maximum Data Transfer Size (MDTS) + /// + public byte MDTS; + + /// + /// byte 78:79 M - Controller ID (CNTLID) + /// + public ushort CNTLID; + + /// + /// byte 80:83 M - Version (VER) + /// + public uint VER; + + /// + /// byte 84:87 M - RTD3 Resume Latency (RTD3R) + /// + public uint RTD3R; + + /// + /// byte 88:91 M - RTD3 Entry Latency (RTD3E) + /// + public uint RTD3E; + + /// + /// byte 92:95 M - Optional Asynchronous Events Supported (OAES) + /// + public uint OAES; + + /// + /// byte 96:239. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 144)] + public byte[] Reserved0; + + /// + /// byte 240:255. Refer to the NVMe Management Interface Specification for definition. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] ReservedForManagement; + + /// + /// byte 256:257 M - Optional Admin Command Support (OACS) + /// + public ushort OACS; + + /// + /// byte 258 M - Abort Command Limit (ACL) + /// + public byte ACL; + + /// + /// byte 259 M - Asynchronous Event Request Limit (AERL) + /// + public byte AERL; + + /// + /// byte 260 M - Firmware Updates (FRMW) + /// + public byte FRMW; + + /// + /// byte 261 M - Log Page Attributes (LPA) + /// + public byte LPA; + + /// + /// byte 262 M - Error Log Page Entries (ELPE) + /// + public byte ELPE; + + /// + /// byte 263 M - Number of Power States Support (NPSS) + /// + public byte NPSS; + + /// + /// byte 264 M - Admin Vendor Specific Command Configuration (AVSCC) + /// + public byte AVSCC; + + /// + /// byte 265 O - Autonomous Power State Transition Attributes (APSTA) + /// + public byte APSTA; + + /// + /// byte 266:267 M - Warning Composite Temperature Threshold (WCTEMP) + /// + public ushort WCTEMP; + + /// + /// byte 268:269 M - Critical Composite Temperature Threshold (CCTEMP) + /// + public ushort CCTEMP; + + /// + /// byte 270:271 O - Maximum Time for Firmware Activation (MTFA) + /// + public ushort MTFA; + + /// + /// byte 272:275 O - Host Memory Buffer Preferred Size (HMPRE) + /// + public uint HMPRE; + + /// + /// byte 276:279 O - Host Memory Buffer Minimum Size (HMMIN) + /// + public uint HMMIN; + + /// + /// byte 280:295 O - Total NVM Capacity (TNVMCAP) + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] TNVMCAP; + + /// + /// byte 296:311 O - Unallocated NVM Capacity (UNVMCAP) + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] UNVMCAP; + + /// + /// byte 312:315 O - Replay Protected Memory Block Support (RPMBS) + /// + public uint RPMBS; + + /// + /// byte 316:511 + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 196)] + public byte[] Reserved1; + + /// + /// byte 512 M - Submission Queue Entry Size (SQES) + /// + public byte SQES; + + /// + /// byte 513 M - Completion Queue Entry Size (CQES) + /// + public byte CQES; + + /// + /// byte 514:515 + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] Reserved2; + + /// + /// byte 516:519 M - Number of Namespaces (NN) + /// + public uint NN; + + /// + /// byte 520:521 M - Optional NVM Command Support (ONCS) + /// + public ushort ONCS; + + /// + /// byte 522:523 M - Fused Operation Support (FUSES) + /// + public ushort FUSES; + + /// + /// byte 524 M - Format NVM Attributes (FNA) + /// + public byte FNA; + + /// + /// byte 525 M - Volatile Write Cache (VWC) + /// + public byte VWC; + + /// + /// byte 526:527 M - Atomic Write Unit Normal (AWUN) + /// + public ushort AWUN; + + /// + /// byte 528:529 M - Atomic Write Unit Power Fail (AWUPF) + /// + public ushort AWUPF; + + /// + /// byte 530 M - NVM Vendor Specific Command Configuration (NVSCC) + /// + public byte NVSCC; + + /// + /// byte 531 + /// + public byte Reserved3; + + /// + /// byte 532:533 O - Atomic Compare and Write Unit (ACWU) + /// + public ushort ACWU; + + /// + /// byte 534:535 + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] Reserved4; + + /// + /// byte 536:539 O - SGL Support (SGLS) + /// + public uint SGLS; + + /// + /// byte 540:703 + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 164)] + public byte[] Reserved5; + + /// + /// byte 704:2047 + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1344)] + public byte[] Reserved6; + + /// + /// byte 2048:3071 Power State Descriptors + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] + public NVME_POWER_STATE_DESC[] PDS; + + /// + /// byte 3072:4095 Vendor Specific + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] + public byte[] VS; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NVME_HEALTH_INFO_LOG + { + /// + /// This field indicates critical warnings for the state of the controller. + /// Each bit corresponds to a critical warning type; multiple bits may be set. + /// + public byte CriticalWarning; + + /// + /// Composite Temperature: Contains the temperature of the overall device (controller and NVM included) in units of Kelvin. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public byte[] CompositeTemp; + + /// + /// Available Spare: Contains a normalized percentage (0 to 100%) of the remaining spare capacity available + /// + public byte AvailableSpare; + + /// + /// Available Spare Threshold: When the Available Spare falls below the threshold indicated in this field, + /// an asynchronous event completion may occur. The value is indicated as a normalized percentage (0 to 100%). + /// + public byte AvailableSpareThreshold; + + /// + /// Percentage Used: Contains a vendor specific estimate of the percentage of NVM subsystem life used based on + /// the actual usage and the manufacturer’s prediction of NVM life. A value of 100 indicates that the estimated endurance of + /// the NVM in the NVM subsystem has been consumed, but may not indicate an NVM subsystem failure. The value is allowed to exceed 100. + /// + public byte PercentageUsed; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] + public byte[] Reserved1; + + /// + /// Data Units Read: Contains the number of 512 byte data units the host has read from the controller; + /// this value does not include metadata. This value is reported in thousands + /// (i.e., a value of 1 corresponds to 1000 units of 512 bytes read) and is rounded up. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] DataUnitRead; + + /// + /// Data Units Written: Contains the number of 512 byte data units the host has written to the controller; + /// this value does not include metadata. This value is reported in thousands + /// (i.e., a value of 1 corresponds to 1000 units of 512 bytes written) and is rounded up. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] DataUnitWritten; + + /// + /// Host Read Commands: Contains the number of read commands completed by the controller. + /// For the NVM command set, this is the number of Compare and Read commands. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] HostReadCommands; + + /// + /// Host Write Commands: Contains the number of write commands completed by the controller. + /// For the NVM command set, this is the number of Write commands. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] HostWriteCommands; + + /// + /// Controller Busy Time: Contains the amount of time the controller is busy with I/O commands. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] ControllerBusyTime; + + /// + /// Power Cycles: Contains the number of power cycles. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] PowerCycles; + + /// + /// Power On Hours: Contains the number of power-on hours. + /// This does not include time that the controller was powered and in a low power state condition. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] PowerOnHours; + + /// + /// Unsafe Shutdowns: Contains the number of unsafe shutdowns. + /// This count is incremented when a shutdown notification is not received prior to loss of power. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] UnsafeShutdowns; + + /// + /// Media Errors: Contains the number of occurrences where the controller detected an unrecoverable data integrity error. + /// Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] MediaAndDataIntegrityErrors; + + /// + /// Number of Error Information Log Entries: Contains the number of Error Information log entries over the life of the controller + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] + public byte[] NumberErrorInformationLogEntries; + + /// + /// Warning Composite Temperature Time: Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than or equal to the Warning Composite + /// Temperature Threshold. + /// + public uint WarningCompositeTemperatureTime; + + /// + /// Critical Composite Temperature Time: Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than the Critical Composite Temperature + /// Threshold. + /// + public uint CriticalCompositeTemperatureTime; + + /// + /// Contains the current temperature reported by temperature sensor 1-8. + /// + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public ushort[] TemperatureSensor; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 296)] + internal byte[] Reserved2; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct STORAGE_PROTOCOL_SPECIFIC_DATA + { + public STORAGE_PROTOCOL_TYPE ProtocolType; + public uint DataType; + public uint ProtocolDataRequestValue; + public uint ProtocolDataRequestSubValue; + public uint ProtocolDataOffset; + public uint ProtocolDataLength; + public uint FixedProtocolReturnData; + public uint ProtocolDataRequestSubValue2; + public uint ProtocolDataRequestSubValue3; + public uint Reserved; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct STORAGE_QUERY_BUFFER + { + public STORAGE_PROPERTY_ID PropertyId; + public STORAGE_QUERY_TYPE QueryType; + public STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecific; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] + internal byte[] Buffer; + } + + [Flags] + internal enum MEM : uint + { + MEM_COMMIT = 0x1000, + MEM_RESERVE = 0x2000, + MEM_DECOMMIT = 0x4000, + MEM_RELEASE = 0x8000, + MEM_RESET = 0x80000, + MEM_LARGE_PAGES = 0x20000000, + MEM_PHYSICAL = 0x400000, + MEM_TOP_DOWN = 0x100000, + MEM_WRITE_WATCH = 0x200000 + } + + [Flags] + internal enum PAGE : uint + { + PAGE_EXECUTE = 0x10, + PAGE_EXECUTE_READ = 0x20, + PAGE_EXECUTE_READWRITE = 0x40, + PAGE_EXECUTE_WRITECOPY = 0x80, + PAGE_NOACCESS = 0x01, + PAGE_READONLY = 0x02, + PAGE_READWRITE = 0x04, + PAGE_WRITECOPY = 0x08, + PAGE_GUARD = 0x100, + PAGE_NOCACHE = 0x200, + PAGE_WRITECOMBINE = 0x400 + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + internal struct IOControlCode + { + /// + /// Gets the resulting IO control code. + /// + public uint Code { get; } + + /// + /// Initializes a new instance of the struct. + /// + /// Type of the device. + /// The function. + /// The access. + public IOControlCode(uint deviceType, uint function, Access access) : this(deviceType, function, Method.Buffered, access) + { } + + /// + /// Initializes a new instance of the struct. + /// + /// Type of the device. + /// The function. + /// The method. + /// The access. + public IOControlCode(uint deviceType, uint function, Method method, Access access) { - int size = Marshal.SizeOf(); - IntPtr ptr = Marshal.AllocHGlobal(size); - RtlZeroMemory(ptr, size); - T result = Marshal.PtrToStructure(ptr); - Marshal.FreeHGlobal(ptr); - return result; + Code = (deviceType << 16) | ((uint)access << 14) | (function << 2) | (uint)method; } - internal static SafeHandle OpenDevice(string devicePath) + public enum Method : uint { - SafeHandle hDevice = CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero); - if (hDevice.IsInvalid || hDevice.IsClosed) - hDevice = null; - - return hDevice; + Buffered = 0, + InDirect = 1, + OutDirect = 2, + Neither = 3 } - [DllImport(DllName, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool GlobalMemoryStatusEx(ref MEMORYSTATUSEX lpBuffer); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern SafeFileHandle CreateFile - ( - [MarshalAs(UnmanagedType.LPTStr)] string lpFileName, - [MarshalAs(UnmanagedType.U4)] FileAccess dwDesiredAccess, - [MarshalAs(UnmanagedType.U4)] FileShare dwShareMode, - IntPtr lpSecurityAttributes, - [MarshalAs(UnmanagedType.U4)] FileMode dwCreationDisposition, - [MarshalAs(UnmanagedType.U4)] FileAttributes dwFlagsAndAttributes, - IntPtr hTemplateFile); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out ATTRIBUTECMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out THRESHOLDCMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out SENDCMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out IDENTIFYCMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - DFP dwIoControlCode, - ref SENDCMDINPARAMS lpInBuffer, - int nInBufferSize, - out STATUSCMDOUTPARAMS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - IOCTL dwIoControlCode, - ref STORAGE_PROPERTY_QUERY lpInBuffer, - int nInBufferSize, - out STORAGE_DEVICE_DESCRIPTOR_HEADER lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - IOCTL dwIoControlCode, - ref STORAGE_PROPERTY_QUERY lpInBuffer, - int nInBufferSize, - IntPtr lpOutBuffer, - uint nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeHandle hDevice, - IOCTL dwIoControlCode, - IntPtr lpInBuffer, - int nInBufferSize, - IntPtr lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeFileHandle hDevice, - IOCTL dwIoControlCode, - ref BATTERY_QUERY_INFORMATION lpInBuffer, - int nInBufferSize, - ref BATTERY_INFORMATION lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeFileHandle hDevice, - IOCTL dwIoControlCode, - ref uint lpInBuffer, - int nInBufferSize, - ref uint lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeFileHandle hDevice, - IOCTL dwIoControlCode, - ref BATTERY_WAIT_STATUS lpInBuffer, - int nInBufferSize, - ref BATTERY_STATUS lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeFileHandle hDevice, - IOCTL dwIoControlCode, - ref BATTERY_QUERY_INFORMATION lpInBuffer, - int nInBufferSize, - IntPtr lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool DeviceIoControl - ( - SafeFileHandle hDevice, - IOCTL dwIoControlCode, - ref BATTERY_QUERY_INFORMATION lpInBuffer, - int nInBufferSize, - ref uint lpOutBuffer, - int nOutBufferSize, - out uint lpBytesReturned, - IntPtr lpOverlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr LocalAlloc(uint uFlags, ulong uBytes); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr LocalFree(IntPtr hMem); - - [DllImport(DllName, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern void RtlZeroMemory(IntPtr Destination, int Length); - - [DllImport(DllName, SetLastError = false)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern void RtlCopyMemory(IntPtr Destination, IntPtr Source, uint Length); - - [DllImport(DllName, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr LoadLibrary(string lpFileName); - - [DllImport(DllName, ExactSpelling = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr GetProcAddress(IntPtr module, string methodName); - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool FreeLibrary(IntPtr module); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern UIntPtr SetThreadAffinityMask(IntPtr handle, UIntPtr mask); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr GetCurrentThread(); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern ushort GetActiveProcessorGroupCount(); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern bool SetThreadGroupAffinity(IntPtr thread, ref GROUP_AFFINITY groupAffinity, out GROUP_AFFINITY previousGroupAffinity); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr VirtualAlloc(IntPtr lpAddress, UIntPtr dwSize, MEM flAllocationType, PAGE flProtect); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern bool VirtualFree(IntPtr lpAddress, UIntPtr dwSize, MEM dwFreeType); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern bool DeviceIoControl - ( - SafeFileHandle device, - IOControlCode ioControlCode, - [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, - uint inBufferSize, - [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer, - uint nOutBufferSize, - out uint bytesReturned, - IntPtr overlapped); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr CreateFile - ( - string lpFileName, - uint dwDesiredAccess, - FileShare dwShareMode, - IntPtr lpSecurityAttributes, - FileMode dwCreationDisposition, - FileAttributes dwFlagsAndAttributes, - IntPtr hTemplateFile); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern int EnumSystemFirmwareTables(Provider firmwareTableProviderSignature, IntPtr firmwareTableBuffer, int bufferSize); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern int GetSystemFirmwareTable(Provider firmwareTableProviderSignature, int firmwareTableID, IntPtr firmwareTableBuffer, int bufferSize); - - [StructLayout(LayoutKind.Sequential, Pack = 4)] - public struct GROUP_AFFINITY + public enum Access : uint { - public UIntPtr Mask; - - [MarshalAs(UnmanagedType.U2)] - public ushort Group; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3, ArraySubType = UnmanagedType.U2)] - public ushort[] Reserved; - } - - internal enum DFP : uint - { - DFP_GET_VERSION = 0x00074080, - DFP_SEND_DRIVE_COMMAND = 0x0007c084, - DFP_RECEIVE_DRIVE_DATA = 0x0007c088 - } - - internal enum IOCTL : uint - { - IOCTL_SCSI_PASS_THROUGH = 0x04d004, - IOCTL_SCSI_MINIPORT = 0x04d008, - IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x04d014, - IOCTL_SCSI_GET_ADDRESS = 0x41018, - IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400, - IOCTL_BATTERY_QUERY_TAG = 0x294040, - IOCTL_BATTERY_QUERY_INFORMATION = 0x294044, - IOCTL_BATTERY_QUERY_STATUS = 0x29404C - } - - [Flags] - internal enum BatteryCapabilities : uint - { - BATTERY_CAPACITY_RELATIVE = 0x40000000, - BATTERY_IS_SHORT_TERM = 0x20000000, - BATTERY_SET_CHARGE_SUPPORTED = 0x00000001, - BATTERY_SET_DISCHARGE_SUPPORTED = 0x00000002, - BATTERY_SYSTEM_BATTERY = 0x80000000 - } - - internal enum BATTERY_QUERY_INFORMATION_LEVEL - { - BatteryInformation, - BatteryGranularityInformation, - BatteryTemperature, - BatteryEstimatedTime, - BatteryDeviceName, - BatteryManufactureDate, - BatteryManufactureName, - BatteryUniqueID, - BatterySerialNumber - } - - [StructLayout(LayoutKind.Sequential)] - internal struct BATTERY_QUERY_INFORMATION - { - public uint BatteryTag; - public BATTERY_QUERY_INFORMATION_LEVEL InformationLevel; - public uint AtRate; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct BATTERY_INFORMATION - { - public BatteryCapabilities Capabilities; - public byte Technology; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public char[] Chemistry; - - public uint DesignedCapacity; - public uint FullChargedCapacity; - public uint DefaultAlert1; - public uint DefaultAlert2; - public uint CriticalBias; - public uint CycleCount; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct BATTERY_WAIT_STATUS - { - public uint BatteryTag; - public uint Timeout; - public uint PowerState; - public uint LowCapacity; - public uint HighCapacity; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct BATTERY_STATUS - { - public uint PowerState; - public uint Capacity; - public uint Voltage; - public int Rate; - } - - [Flags] - internal enum NVME_DIRECTION : uint - { - NVME_FROM_HOST_TO_DEV = 1, - NVME_FROM_DEV_TO_HOST = 2, - NVME_BI_DIRECTION = NVME_FROM_DEV_TO_HOST | NVME_FROM_HOST_TO_DEV - } - - internal enum NVME_LOG_PAGES - { - NVME_LOG_PAGE_ERROR_INFO = 0x01, - NVME_LOG_PAGE_HEALTH_INFO = 0x02, - NVME_LOG_PAGE_FIRMWARE_SLOT_INFO = 0x03, - NVME_LOG_PAGE_CHANGED_NAMESPACE_LIST = 0x04, - NVME_LOG_PAGE_COMMAND_EFFECTS = 0x05, - NVME_LOG_PAGE_DEVICE_SELF_TEST = 0x06, - NVME_LOG_PAGE_TELEMETRY_HOST_INITIATED = 0x07, - NVME_LOG_PAGE_TELEMETRY_CTLR_INITIATED = 0x08, - NVME_LOG_PAGE_RESERVATION_NOTIFICATION = 0x80, - NVME_LOG_PAGE_SANITIZE_STATUS = 0x81 - } - - internal enum ATA_COMMAND : byte - { - /// - /// SMART data requested. - /// - ATA_SMART = 0xB0, - - /// - /// Identify data is requested. - /// - ATA_IDENTIFY_DEVICE = 0xEC - } - - internal enum SCSI_IOCTL_DATA - { - SCSI_IOCTL_DATA_OUT = 0, - SCSI_IOCTL_DATA_IN = 1, - SCSI_IOCTL_DATA_UNSPECIFIED = 2 - } - - internal enum SMART_FEATURES : byte - { - /// - /// Read SMART data. - /// - SMART_READ_DATA = 0xD0, - - /// - /// Read SMART thresholds. - /// obsolete - /// - READ_THRESHOLDS = 0xD1, - - /// - /// Autosave SMART data. - /// - ENABLE_DISABLE_AUTOSAVE = 0xD2, - - /// - /// Save SMART attributes. - /// - SAVE_ATTRIBUTE_VALUES = 0xD3, - - /// - /// Set SMART to offline immediately. - /// - EXECUTE_OFFLINE_DIAGS = 0xD4, - - /// - /// Read SMART log. - /// - SMART_READ_LOG = 0xD5, - - /// - /// Write SMART log. - /// - SMART_WRITE_LOG = 0xD6, - - /// - /// Write SMART thresholds. - /// obsolete - /// - WRITE_THRESHOLDS = 0xD7, - - /// - /// Enable SMART. - /// - ENABLE_SMART = 0xD8, - - /// - /// Disable SMART. - /// - DISABLE_SMART = 0xD9, - - /// - /// Get SMART status. - /// - RETURN_SMART_STATUS = 0xDA, - - /// - /// Set SMART to offline automatically. - /// - ENABLE_DISABLE_AUTO_OFFLINE = 0xDB /* obsolete */ - } - - internal enum STORAGE_BUS_TYPE - { - BusTypeUnknown = 0x00, - BusTypeScsi, - BusTypeAtapi, - BusTypeAta, - BusType1394, - BusTypeSsa, - BusTypeFibre, - BusTypeUsb, - BusTypeRAID, - BusTypeiScsi, - BusTypeSas, - BusTypeSata, - BusTypeSd, - BusTypeMmc, - BusTypeVirtual, - BusTypeFileBackedVirtual, - BusTypeSpaces, - BusTypeNvme, - BusTypeSCM, - BusTypeMax, - BusTypeMaxReserved = 0x7F - } - - internal enum STORAGE_PROPERTY_ID - { - StorageDeviceProperty = 0, - StorageAdapterProperty, - StorageDeviceIdProperty, - StorageDeviceUniqueIdProperty, - StorageDeviceWriteCacheProperty, - StorageMiniportProperty, - StorageAccessAlignmentProperty, - StorageDeviceSeekPenaltyProperty, - StorageDeviceTrimProperty, - StorageDeviceWriteAggregationProperty, - StorageDeviceDeviceTelemetryProperty, - StorageDeviceLBProvisioningProperty, - StorageDevicePowerProperty, - StorageDeviceCopyOffloadProperty, - StorageDeviceResiliencyProperty, - StorageDeviceMediumProductType, - StorageAdapterRpmbProperty, - StorageDeviceIoCapabilityProperty = 48, - StorageAdapterProtocolSpecificProperty, - StorageDeviceProtocolSpecificProperty, - StorageAdapterTemperatureProperty, - StorageDeviceTemperatureProperty, - StorageAdapterPhysicalTopologyProperty, - StorageDevicePhysicalTopologyProperty, - StorageDeviceAttributesProperty, - StorageDeviceManagementStatus, - StorageAdapterSerialNumberProperty, - StorageDeviceLocationProperty - } - - internal enum STORAGE_PROTOCOL_NVME_DATA_TYPE - { - NVMeDataTypeUnknown = 0, - NVMeDataTypeIdentify, - NVMeDataTypeLogPage, - NVMeDataTypeFeature - } - - internal enum STORAGE_PROTOCOL_NVME_PROTOCOL_DATA_REQUEST_VALUE - { - NVMeIdentifyCnsSpecificNamespace = 0, - NVMeIdentifyCnsController = 1, - NVMeIdentifyCnsActiveNamespaces = 2 - } - - internal enum STORAGE_PROTOCOL_TYPE - { - ProtocolTypeUnknown = 0x00, - ProtocolTypeScsi, - ProtocolTypeAta, - ProtocolTypeNvme, - ProtocolTypeSd, - ProtocolTypeProprietary = 0x7E, - ProtocolTypeMaxReserved = 0x7F - } - - internal enum STORAGE_QUERY_TYPE - { - PropertyStandardQuery = 0, - PropertyExistsQuery, - PropertyMaskQuery, - PropertyQueryMaxDefined - } - - [StructLayout(LayoutKind.Sequential)] - internal struct MEMORYSTATUSEX - { - public uint dwLength; - public uint dwMemoryLoad; - public ulong ullTotalPhys; - public ulong ullAvailPhys; - public ulong ullTotalPageFile; - public ulong ullAvailPageFile; - public ulong ullTotalVirtual; - public ulong ullAvailVirtual; - public ulong ullAvailExtendedVirtual; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct SMART_ATTRIBUTE - { - public byte Id; - public short Flags; - public byte CurrentValue; - public byte WorstValue; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public byte[] RawValue; - - public byte Reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - public struct SMART_THRESHOLD - { - public byte Id; - public byte Threshold; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public byte[] Reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct SENDCMDINPARAMS - { - public uint cBufferSize; - public IDEREGS irDriveRegs; - public byte bDriveNumber; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] bReserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public uint[] dwReserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public byte[] bBuffer; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct IDEREGS - { - public SMART_FEATURES bFeaturesReg; - public byte bSectorCountReg; - public byte bSectorNumberReg; - public byte bCylLowReg; - public byte bCylHighReg; - public byte bDriveHeadReg; - public ATA_COMMAND bCommandReg; - public byte bReserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct DRIVERSTATUS - { - public byte bDriverError; - public byte bIDEError; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 10)] - public byte[] Reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct SENDCMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public byte[] bBuffer; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct ATTRIBUTECMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public byte Version; - public byte Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)] - public SMART_ATTRIBUTE[] Attributes; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct THRESHOLDCMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public byte Version; - public byte Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_DRIVE_ATTRIBUTES)] - public SMART_THRESHOLD[] Thresholds; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct STATUSCMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public IDEREGS irDriveRegs; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct IDENTIFY_DATA - { - public ushort GeneralConfiguration; - public ushort NumberOfCylinders; - public ushort Reserved1; - public ushort NumberOfHeads; - public ushort UnformattedBytesPerTrack; - public ushort UnformattedBytesPerSector; - public ushort SectorsPerTrack; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public ushort[] VendorUnique; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public byte[] SerialNumber; - - public ushort BufferType; - public ushort BufferSectorSize; - public ushort NumberOfEccBytes; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] FirmwareRevision; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] - public byte[] ModelNumber; - - public byte MaximumBlockTransfer; - public byte VendorUnique2; - public ushort DoubleWordIo; - public ushort Capabilities; - public ushort Reserved2; - public byte VendorUnique3; - public byte PioCycleTimingMode; - public byte VendorUnique4; - public byte DmaCycleTimingMode; - public ushort TranslationFieldsValid; - public ushort NumberOfCurrentCylinders; - public ushort NumberOfCurrentHeads; - public ushort CurrentSectorsPerTrack; - public uint CurrentSectorCapacity; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 197)] - public ushort[] Reserved3; - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct IDENTIFYCMDOUTPARAMS - { - public uint cBufferSize; - public DRIVERSTATUS DriverStatus; - public IDENTIFY_DATA Identify; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct STORAGE_PROPERTY_QUERY - { - public STORAGE_PROPERTY_ID PropertyId; - public STORAGE_QUERY_TYPE QueryType; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] - public byte[] AdditionalParameters; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct STORAGE_DEVICE_DESCRIPTOR_HEADER - { - public uint Version; - public uint Size; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct STORAGE_DEVICE_DESCRIPTOR - { - public uint Version; - public uint Size; - public byte DeviceType; - public byte DeviceTypeModifier; - - [MarshalAs(UnmanagedType.U1)] - public bool RemovableMedia; - - [MarshalAs(UnmanagedType.U1)] - public bool CommandQueueing; - - public uint VendorIdOffset; - public uint ProductIdOffset; - public uint ProductRevisionOffset; - public uint SerialNumberOffset; - public STORAGE_BUS_TYPE BusType; - public uint RawPropertiesLength; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SRB_IO_CONTROL - { - public uint HeaderLenght; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] Signature; - - public uint Timeout; - public uint ControlCode; - public uint ReturnCode; - public uint Length; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NVME_PASS_THROUGH_IOCTL - { - public SRB_IO_CONTROL srb; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 6)] - public uint[] VendorSpecific; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public uint[] NVMeCmd; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)] - public uint[] CplEntry; - - public NVME_DIRECTION Direction; - public uint QueueId; - public uint DataBufferLen; - public uint MetaDataLen; - public uint ReturnBufferLen; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] - public byte[] DataBuffer; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SCSI_PASS_THROUGH - { - [MarshalAs(UnmanagedType.U2)] - public ushort Length; - - public byte ScsiStatus; - public byte PathId; - public byte TargetId; - public byte Lun; - public byte CdbLength; - public byte SenseInfoLength; - public byte DataIn; - public uint DataTransferLength; - public uint TimeOutValue; - public IntPtr DataBufferOffset; - public uint SenseInfoOffset; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] Cdb; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct SCSI_PASS_THROUGH_WITH_BUFFERS - { - public SCSI_PASS_THROUGH Spt; - - public uint Filler; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public byte[] SenseBuf; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] - public byte[] DataBuf; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NVME_POWER_STATE_DESC - { - /// - /// bit 0:15 Maximum Power (MP) in centiwatts - /// - public ushort MP; - - /// - /// bit 16:23 - /// - public byte Reserved0; - - /// - /// bit 24 Max Power Scale (MPS), bit 25 Non-Operational State (NOPS) - /// - public byte MPS_NOPS; - - /// - /// bit 32:63 Entry Latency (ENLAT) in microseconds - /// - public uint ENLAT; - - /// - /// bit 64:95 Exit Latency (EXLAT) in microseconds - /// - public uint EXLAT; - - /// - /// bit 96:100 Relative Read Throughput (RRT) - /// - public byte RRT; - - /// - /// bit 104:108 Relative Read Latency (RRL) - /// - public byte RRL; - - /// - /// bit 112:116 Relative Write Throughput (RWT) - /// - public byte RWT; - - /// - /// bit 120:124 Relative Write Latency (RWL) - /// - public byte RWL; - - /// - /// bit 128:143 Idle Power (IDLP) - /// - public ushort IDLP; - - /// - /// bit 150:151 Idle Power Scale (IPS) - /// - public byte IPS; - - /// - /// bit 152:159 - /// - public byte Reserved7; - - /// - /// bit 160:175 Active Power (ACTP) - /// - public ushort ACTP; - - /// - /// bit 176:178 Active Power Workload (APW), bit 182:183 Active Power Scale (APS) - /// - public byte APW_APS; - - /// - /// bit 184:255. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] - public byte[] Reserved9; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NVME_IDENTIFY_CONTROLLER_DATA - { - /// - /// byte 0:1 M - PCI Vendor ID (VID) - /// - public ushort VID; - - /// - /// byte 2:3 M - PCI Subsystem Vendor ID (SSVID) - /// - public ushort SSVID; - - /// - /// byte 4: 23 M - Serial Number (SN) - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 20)] - public byte[] SN; - - /// - /// byte 24:63 M - Model Number (MN) - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 40)] - public byte[] MN; - - /// - /// byte 64:71 M - Firmware Revision (FR) - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public byte[] FR; - - /// - /// byte 72 M - Recommended Arbitration Burst (RAB) - /// - public byte RAB; - - /// - /// byte 73:75 M - IEEE OUI Identifier (IEEE). Controller Vendor code. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] - public byte[] IEEE; - - /// - /// byte 76 O - Controller Multi-Path I/O and Namespace Sharing Capabilities (CMIC) - /// - public byte CMIC; - - /// - /// byte 77 M - Maximum Data Transfer Size (MDTS) - /// - public byte MDTS; - - /// - /// byte 78:79 M - Controller ID (CNTLID) - /// - public ushort CNTLID; - - /// - /// byte 80:83 M - Version (VER) - /// - public uint VER; - - /// - /// byte 84:87 M - RTD3 Resume Latency (RTD3R) - /// - public uint RTD3R; - - /// - /// byte 88:91 M - RTD3 Entry Latency (RTD3E) - /// - public uint RTD3E; - - /// - /// byte 92:95 M - Optional Asynchronous Events Supported (OAES) - /// - public uint OAES; - - /// - /// byte 96:239. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 144)] - public byte[] Reserved0; - - /// - /// byte 240:255. Refer to the NVMe Management Interface Specification for definition. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] ReservedForManagement; - - /// - /// byte 256:257 M - Optional Admin Command Support (OACS) - /// - public ushort OACS; - - /// - /// byte 258 M - Abort Command Limit (ACL) - /// - public byte ACL; - - /// - /// byte 259 M - Asynchronous Event Request Limit (AERL) - /// - public byte AERL; - - /// - /// byte 260 M - Firmware Updates (FRMW) - /// - public byte FRMW; - - /// - /// byte 261 M - Log Page Attributes (LPA) - /// - public byte LPA; - - /// - /// byte 262 M - Error Log Page Entries (ELPE) - /// - public byte ELPE; - - /// - /// byte 263 M - Number of Power States Support (NPSS) - /// - public byte NPSS; - - /// - /// byte 264 M - Admin Vendor Specific Command Configuration (AVSCC) - /// - public byte AVSCC; - - /// - /// byte 265 O - Autonomous Power State Transition Attributes (APSTA) - /// - public byte APSTA; - - /// - /// byte 266:267 M - Warning Composite Temperature Threshold (WCTEMP) - /// - public ushort WCTEMP; - - /// - /// byte 268:269 M - Critical Composite Temperature Threshold (CCTEMP) - /// - public ushort CCTEMP; - - /// - /// byte 270:271 O - Maximum Time for Firmware Activation (MTFA) - /// - public ushort MTFA; - - /// - /// byte 272:275 O - Host Memory Buffer Preferred Size (HMPRE) - /// - public uint HMPRE; - - /// - /// byte 276:279 O - Host Memory Buffer Minimum Size (HMMIN) - /// - public uint HMMIN; - - /// - /// byte 280:295 O - Total NVM Capacity (TNVMCAP) - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] TNVMCAP; - - /// - /// byte 296:311 O - Unallocated NVM Capacity (UNVMCAP) - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] UNVMCAP; - - /// - /// byte 312:315 O - Replay Protected Memory Block Support (RPMBS) - /// - public uint RPMBS; - - /// - /// byte 316:511 - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 196)] - public byte[] Reserved1; - - /// - /// byte 512 M - Submission Queue Entry Size (SQES) - /// - public byte SQES; - - /// - /// byte 513 M - Completion Queue Entry Size (CQES) - /// - public byte CQES; - - /// - /// byte 514:515 - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] Reserved2; - - /// - /// byte 516:519 M - Number of Namespaces (NN) - /// - public uint NN; - - /// - /// byte 520:521 M - Optional NVM Command Support (ONCS) - /// - public ushort ONCS; - - /// - /// byte 522:523 M - Fused Operation Support (FUSES) - /// - public ushort FUSES; - - /// - /// byte 524 M - Format NVM Attributes (FNA) - /// - public byte FNA; - - /// - /// byte 525 M - Volatile Write Cache (VWC) - /// - public byte VWC; - - /// - /// byte 526:527 M - Atomic Write Unit Normal (AWUN) - /// - public ushort AWUN; - - /// - /// byte 528:529 M - Atomic Write Unit Power Fail (AWUPF) - /// - public ushort AWUPF; - - /// - /// byte 530 M - NVM Vendor Specific Command Configuration (NVSCC) - /// - public byte NVSCC; - - /// - /// byte 531 - /// - public byte Reserved3; - - /// - /// byte 532:533 O - Atomic Compare and Write Unit (ACWU) - /// - public ushort ACWU; - - /// - /// byte 534:535 - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] Reserved4; - - /// - /// byte 536:539 O - SGL Support (SGLS) - /// - public uint SGLS; - - /// - /// byte 540:703 - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 164)] - public byte[] Reserved5; - - /// - /// byte 704:2047 - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1344)] - public byte[] Reserved6; - - /// - /// byte 2048:3071 Power State Descriptors - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)] - public NVME_POWER_STATE_DESC[] PDS; - - /// - /// byte 3072:4095 Vendor Specific - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1024)] - public byte[] VS; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NVME_HEALTH_INFO_LOG - { - /// - /// This field indicates critical warnings for the state of the controller. - /// Each bit corresponds to a critical warning type; multiple bits may be set. - /// - public byte CriticalWarning; - - /// - /// Composite Temperature: Contains the temperature of the overall device (controller and NVM included) in units of Kelvin. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] - public byte[] CompositeTemp; - - /// - /// Available Spare: Contains a normalized percentage (0 to 100%) of the remaining spare capacity available - /// - public byte AvailableSpare; - - /// - /// Available Spare Threshold: When the Available Spare falls below the threshold indicated in this field, - /// an asynchronous event completion may occur. The value is indicated as a normalized percentage (0 to 100%). - /// - public byte AvailableSpareThreshold; - - /// - /// Percentage Used: Contains a vendor specific estimate of the percentage of NVM subsystem life used based on - /// the actual usage and the manufacturer’s prediction of NVM life. A value of 100 indicates that the estimated endurance of - /// the NVM in the NVM subsystem has been consumed, but may not indicate an NVM subsystem failure. The value is allowed to exceed 100. - /// - public byte PercentageUsed; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 26)] - public byte[] Reserved1; - - /// - /// Data Units Read: Contains the number of 512 byte data units the host has read from the controller; - /// this value does not include metadata. This value is reported in thousands - /// (i.e., a value of 1 corresponds to 1000 units of 512 bytes read) and is rounded up. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] DataUnitRead; - - /// - /// Data Units Written: Contains the number of 512 byte data units the host has written to the controller; - /// this value does not include metadata. This value is reported in thousands - /// (i.e., a value of 1 corresponds to 1000 units of 512 bytes written) and is rounded up. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] DataUnitWritten; - - /// - /// Host Read Commands: Contains the number of read commands completed by the controller. - /// For the NVM command set, this is the number of Compare and Read commands. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] HostReadCommands; - - /// - /// Host Write Commands: Contains the number of write commands completed by the controller. - /// For the NVM command set, this is the number of Write commands. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] HostWriteCommands; - - /// - /// Controller Busy Time: Contains the amount of time the controller is busy with I/O commands. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] ControllerBusyTime; - - /// - /// Power Cycles: Contains the number of power cycles. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] PowerCycles; - - /// - /// Power On Hours: Contains the number of power-on hours. - /// This does not include time that the controller was powered and in a low power state condition. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] PowerOnHours; - - /// - /// Unsafe Shutdowns: Contains the number of unsafe shutdowns. - /// This count is incremented when a shutdown notification is not received prior to loss of power. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] UnsafeShutdowns; - - /// - /// Media Errors: Contains the number of occurrences where the controller detected an unrecoverable data integrity error. - /// Errors such as uncorrectable ECC, CRC checksum failure, or LBA tag mismatch are included in this field. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] MediaAndDataIntegrityErrors; - - /// - /// Number of Error Information Log Entries: Contains the number of Error Information log entries over the life of the controller - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)] - public byte[] NumberErrorInformationLogEntries; - - /// - /// Warning Composite Temperature Time: Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than or equal to the Warning Composite - /// Temperature Threshold. - /// - public uint WarningCompositeTemperatureTime; - - /// - /// Critical Composite Temperature Time: Contains the amount of time in minutes that the controller is operational and the Composite Temperature is greater than the Critical Composite Temperature - /// Threshold. - /// - public uint CriticalCompositeTemperatureTime; - - /// - /// Contains the current temperature reported by temperature sensor 1-8. - /// - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public ushort[] TemperatureSensor; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 296)] - internal byte[] Reserved2; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct STORAGE_PROTOCOL_SPECIFIC_DATA - { - public STORAGE_PROTOCOL_TYPE ProtocolType; - public uint DataType; - public uint ProtocolDataRequestValue; - public uint ProtocolDataRequestSubValue; - public uint ProtocolDataOffset; - public uint ProtocolDataLength; - public uint FixedProtocolReturnData; - public uint ProtocolDataRequestSubValue2; - public uint ProtocolDataRequestSubValue3; - public uint Reserved; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct STORAGE_QUERY_BUFFER - { - public STORAGE_PROPERTY_ID PropertyId; - public STORAGE_QUERY_TYPE QueryType; - public STORAGE_PROTOCOL_SPECIFIC_DATA ProtocolSpecific; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 4096)] - internal byte[] Buffer; - } - - [Flags] - internal enum MEM : uint - { - MEM_COMMIT = 0x1000, - MEM_RESERVE = 0x2000, - MEM_DECOMMIT = 0x4000, - MEM_RELEASE = 0x8000, - MEM_RESET = 0x80000, - MEM_LARGE_PAGES = 0x20000000, - MEM_PHYSICAL = 0x400000, - MEM_TOP_DOWN = 0x100000, - MEM_WRITE_WATCH = 0x200000 - } - - [Flags] - internal enum PAGE : uint - { - PAGE_EXECUTE = 0x10, - PAGE_EXECUTE_READ = 0x20, - PAGE_EXECUTE_READWRITE = 0x40, - PAGE_EXECUTE_WRITECOPY = 0x80, - PAGE_NOACCESS = 0x01, - PAGE_READONLY = 0x02, - PAGE_READWRITE = 0x04, - PAGE_WRITECOPY = 0x08, - PAGE_GUARD = 0x100, - PAGE_NOCACHE = 0x200, - PAGE_WRITECOMBINE = 0x400 - } - - [StructLayout(LayoutKind.Sequential, Pack = 1)] - internal struct IOControlCode - { - /// - /// Gets the resulting IO control code. - /// - public uint Code { get; } - - /// - /// Initializes a new instance of the struct. - /// - /// Type of the device. - /// The function. - /// The access. - public IOControlCode(uint deviceType, uint function, Access access) : this(deviceType, function, Method.Buffered, access) - { } - - /// - /// Initializes a new instance of the struct. - /// - /// Type of the device. - /// The function. - /// The method. - /// The access. - public IOControlCode(uint deviceType, uint function, Method method, Access access) - { - Code = (deviceType << 16) | ((uint)access << 14) | (function << 2) | (uint)method; - } - - public enum Method : uint - { - Buffered = 0, - InDirect = 1, - OutDirect = 2, - Neither = 3 - } - - public enum Access : uint - { - Any = 0, - Read = 1, - Write = 2 - } - } - - internal enum Provider - { - ACPI = (byte)'A' << 24 | (byte)'C' << 16 | (byte)'P' << 8 | (byte)'I', - FIRM = (byte)'F' << 24 | (byte)'I' << 16 | (byte)'R' << 8 | (byte)'M', - RSMB = (byte)'R' << 24 | (byte)'S' << 16 | (byte)'M' << 8 | (byte)'B' + Any = 0, + Read = 1, + Write = 2 } } -} + + internal enum Provider + { + ACPI = (byte)'A' << 24 | (byte)'C' << 16 | (byte)'P' << 8 | (byte)'I', + FIRM = (byte)'F' << 24 | (byte)'I' << 16 | (byte)'R' << 8 | (byte)'M', + RSMB = (byte)'R' << 24 | (byte)'S' << 16 | (byte)'M' << 8 | (byte)'B' + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/LibC.cs b/LibreHardwareMonitorLib/Interop/LibC.cs index e8a7acc..993c0b8 100644 --- a/LibreHardwareMonitorLib/Interop/LibC.cs +++ b/LibreHardwareMonitorLib/Interop/LibC.cs @@ -8,16 +8,15 @@ using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal class LibC { - internal class LibC - { - private const string DllName = "libc"; + private const string DllName = "libc"; - [DllImport(DllName)] - internal static extern int sched_getaffinity(int pid, IntPtr maskSize, ref ulong mask); + [DllImport(DllName)] + internal static extern int sched_getaffinity(int pid, IntPtr maskSize, ref ulong mask); - [DllImport(DllName)] - internal static extern int sched_setaffinity(int pid, IntPtr maskSize, ref ulong mask); - } -} + [DllImport(DllName)] + internal static extern int sched_setaffinity(int pid, IntPtr maskSize, ref ulong mask); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/NtDll.cs b/LibreHardwareMonitorLib/Interop/NtDll.cs index 9a78bc1..11a3591 100644 --- a/LibreHardwareMonitorLib/Interop/NtDll.cs +++ b/LibreHardwareMonitorLib/Interop/NtDll.cs @@ -8,75 +8,74 @@ using System.Runtime.InteropServices; // ReSharper disable InconsistentNaming -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal class NtDll { - internal class NtDll + private const string DllName = "ntdll"; + + [StructLayout(LayoutKind.Sequential)] + internal struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION { - private const string DllName = "ntdll"; - - [StructLayout(LayoutKind.Sequential)] - internal struct SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION - { - public long IdleTime; - public long KernelTime; - public long UserTime; - public long Reserved0; - public long Reserved1; - public ulong Reserved2; - } - - internal enum SYSTEM_INFORMATION_CLASS - { - SystemBasicInformation, - SystemProcessorInformation, - SystemPerformanceInformation, - SystemTimeOfDayInformation, - SystemPathInformation, - SystemProcessInformation, - SystemCallCountInformation, - SystemDeviceInformation, - SystemProcessorPerformanceInformation, - SystemFlagsInformation, - SystemCallTimeInformation, - SystemModuleInformation, - SystemLocksInformation, - SystemStackTraceInformation, - SystemPagedPoolInformation, - SystemNonPagedPoolInformation, - SystemHandleInformation, - SystemObjectInformation, - SystemPageFileInformation, - SystemVdmInstemulInformation, - SystemVdmBopInformation, - SystemFileCacheInformation, - SystemPoolTagInformation, - SystemInterruptInformation, - SystemDpcBehaviorInformation, - SystemFullMemoryInformation, - SystemLoadGdiDriverInformation, - SystemUnloadGdiDriverInformation, - SystemTimeAdjustmentInformation, - SystemSummaryMemoryInformation, - SystemNextEventIdInformation, - SystemEventIdsInformation, - SystemCrashDumpInformation, - SystemExceptionInformation, - SystemCrashDumpStateInformation, - SystemKernelDebuggerInformation, - SystemContextSwitchInformation, - SystemRegistryQuotaInformation, - SystemExtendServiceTableInformation, - SystemPrioritySeperation, - SystemPlugPlayBusInformation, - SystemDockInformation, - SystemPowerInformation, - SystemProcessorSpeedInformation, - SystemCurrentTimeZoneInformation, - SystemLookasideInformation - } - - [DllImport(DllName)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern int NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, [Out] SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] SystemInformation, int SystemInformationLength, out IntPtr ReturnLength); + public long IdleTime; + public long KernelTime; + public long UserTime; + public long Reserved0; + public long Reserved1; + public ulong Reserved2; } -} + + internal enum SYSTEM_INFORMATION_CLASS + { + SystemBasicInformation, + SystemProcessorInformation, + SystemPerformanceInformation, + SystemTimeOfDayInformation, + SystemPathInformation, + SystemProcessInformation, + SystemCallCountInformation, + SystemDeviceInformation, + SystemProcessorPerformanceInformation, + SystemFlagsInformation, + SystemCallTimeInformation, + SystemModuleInformation, + SystemLocksInformation, + SystemStackTraceInformation, + SystemPagedPoolInformation, + SystemNonPagedPoolInformation, + SystemHandleInformation, + SystemObjectInformation, + SystemPageFileInformation, + SystemVdmInstemulInformation, + SystemVdmBopInformation, + SystemFileCacheInformation, + SystemPoolTagInformation, + SystemInterruptInformation, + SystemDpcBehaviorInformation, + SystemFullMemoryInformation, + SystemLoadGdiDriverInformation, + SystemUnloadGdiDriverInformation, + SystemTimeAdjustmentInformation, + SystemSummaryMemoryInformation, + SystemNextEventIdInformation, + SystemEventIdsInformation, + SystemCrashDumpInformation, + SystemExceptionInformation, + SystemCrashDumpStateInformation, + SystemKernelDebuggerInformation, + SystemContextSwitchInformation, + SystemRegistryQuotaInformation, + SystemExtendServiceTableInformation, + SystemPrioritySeperation, + SystemPlugPlayBusInformation, + SystemDockInformation, + SystemPowerInformation, + SystemProcessorSpeedInformation, + SystemCurrentTimeZoneInformation, + SystemLookasideInformation + } + + [DllImport(DllName)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern int NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS SystemInformationClass, [Out] SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION[] SystemInformation, int SystemInformationLength, out IntPtr ReturnLength); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/NvApi.cs b/LibreHardwareMonitorLib/Interop/NvApi.cs index 8691a87..b96705a 100644 --- a/LibreHardwareMonitorLib/Interop/NvApi.cs +++ b/LibreHardwareMonitorLib/Interop/NvApi.cs @@ -2,615 +2,614 @@ using System.Runtime.InteropServices; using System.Text; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class NvApi { - internal static class NvApi + public const int MAX_CLOCKS_PER_GPU = 0x120; + public const int MAX_COOLERS_PER_GPU = 20; + public const int MAX_FAN_CONTROLLER_ITEMS = 32; + public const int MAX_FAN_COOLERS_STATUS_ITEMS = 32; + public const int MAX_GPU_PUBLIC_CLOCKS = 32; + public const int MAX_GPU_UTILIZATIONS = 8; + public const int MAX_MEMORY_VALUES_PER_GPU = 5; + public const int MAX_PHYSICAL_GPUS = 64; + public const int MAX_POWER_TOPOLOGIES = 4; + public const int MAX_THERMAL_SENSORS_PER_GPU = 3; + public const int MAX_USAGES_PER_GPU = 8; + + public const int SHORT_STRING_MAX = 64; + public const int THERMAL_SENSOR_RESERVED_COUNT = 8; + public const int THERMAL_SENSOR_TEMPERATURE_COUNT = 32; + + private const string DllName = "nvapi.dll"; + private const string DllName64 = "nvapi64.dll"; + + public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate NvAPI_EnumNvidiaDisplayHandle; + public static readonly NvAPI_EnumPhysicalGPUsDelegate NvAPI_EnumPhysicalGPUs; + public static readonly NvAPI_GetDisplayDriverVersionDelegate NvAPI_GetDisplayDriverVersion; + public static readonly NvAPI_GetPhysicalGPUsFromDisplayDelegate NvAPI_GetPhysicalGPUsFromDisplay; + public static readonly NvAPI_GPU_ClientFanCoolersGetControlDelegate NvAPI_GPU_ClientFanCoolersGetControl; + public static readonly NvAPI_GPU_ClientFanCoolersGetStatusDelegate NvAPI_GPU_ClientFanCoolersGetStatus; + public static readonly NvAPI_GPU_ClientFanCoolersSetControlDelegate NvAPI_GPU_ClientFanCoolersSetControl; + public static readonly NvAPI_GPU_ClientPowerTopologyGetStatusDelegate NvAPI_GPU_ClientPowerTopologyGetStatus; + public static readonly NvAPI_GPU_GetAllClockFrequenciesDelegate NvAPI_GPU_GetAllClockFrequencies; + public static readonly NvAPI_GPU_GetAllClocksDelegate NvAPI_GPU_GetAllClocks; + public static readonly NvAPI_GPU_GetBusIdDelegate NvAPI_GPU_GetBusId; + public static readonly NvAPI_GPU_GetCoolerSettingsDelegate NvAPI_GPU_GetCoolerSettings; + public static readonly NvAPI_GPU_GetDynamicPstatesInfoExDelegate NvAPI_GPU_GetDynamicPstatesInfoEx; + public static readonly NvAPI_GPU_GetMemoryInfoDelegate NvAPI_GPU_GetMemoryInfo; + public static readonly NvAPI_GPU_GetPCIIdentifiersDelegate NvAPI_GPU_GetPCIIdentifiers; + public static readonly NvAPI_GPU_GetTachReadingDelegate NvAPI_GPU_GetTachReading; + public static readonly NvAPI_GPU_GetThermalSettingsDelegate NvAPI_GPU_GetThermalSettings; + public static readonly NvAPI_GPU_GetUsagesDelegate NvAPI_GPU_GetUsages; + public static readonly NvAPI_GPU_SetCoolerLevelsDelegate NvAPI_GPU_SetCoolerLevels; + public static readonly NvAPI_GPU_GetThermalSensorsDelegate NvAPI_GPU_ThermalGetSensors; + + private static readonly NvAPI_GetInterfaceVersionStringDelegate _nvAPI_GetInterfaceVersionString; + private static readonly NvAPI_GPU_GetFullNameDelegate _nvAPI_GPU_GetFullName; + + static NvApi() { - public const int MAX_CLOCKS_PER_GPU = 0x120; - public const int MAX_COOLERS_PER_GPU = 20; - public const int MAX_FAN_CONTROLLER_ITEMS = 32; - public const int MAX_FAN_COOLERS_STATUS_ITEMS = 32; - public const int MAX_GPU_PUBLIC_CLOCKS = 32; - public const int MAX_GPU_UTILIZATIONS = 8; - public const int MAX_MEMORY_VALUES_PER_GPU = 5; - public const int MAX_PHYSICAL_GPUS = 64; - public const int MAX_POWER_TOPOLOGIES = 4; - public const int MAX_THERMAL_SENSORS_PER_GPU = 3; - public const int MAX_USAGES_PER_GPU = 8; + NvAPI_InitializeDelegate nvApiInitialize; - public const int SHORT_STRING_MAX = 64; - public const int THERMAL_SENSOR_RESERVED_COUNT = 8; - public const int THERMAL_SENSOR_TEMPERATURE_COUNT = 32; - - private const string DllName = "nvapi.dll"; - private const string DllName64 = "nvapi64.dll"; - - public static readonly NvAPI_EnumNvidiaDisplayHandleDelegate NvAPI_EnumNvidiaDisplayHandle; - public static readonly NvAPI_EnumPhysicalGPUsDelegate NvAPI_EnumPhysicalGPUs; - public static readonly NvAPI_GetDisplayDriverVersionDelegate NvAPI_GetDisplayDriverVersion; - public static readonly NvAPI_GetPhysicalGPUsFromDisplayDelegate NvAPI_GetPhysicalGPUsFromDisplay; - public static readonly NvAPI_GPU_ClientFanCoolersGetControlDelegate NvAPI_GPU_ClientFanCoolersGetControl; - public static readonly NvAPI_GPU_ClientFanCoolersGetStatusDelegate NvAPI_GPU_ClientFanCoolersGetStatus; - public static readonly NvAPI_GPU_ClientFanCoolersSetControlDelegate NvAPI_GPU_ClientFanCoolersSetControl; - public static readonly NvAPI_GPU_ClientPowerTopologyGetStatusDelegate NvAPI_GPU_ClientPowerTopologyGetStatus; - public static readonly NvAPI_GPU_GetAllClockFrequenciesDelegate NvAPI_GPU_GetAllClockFrequencies; - public static readonly NvAPI_GPU_GetAllClocksDelegate NvAPI_GPU_GetAllClocks; - public static readonly NvAPI_GPU_GetBusIdDelegate NvAPI_GPU_GetBusId; - public static readonly NvAPI_GPU_GetCoolerSettingsDelegate NvAPI_GPU_GetCoolerSettings; - public static readonly NvAPI_GPU_GetDynamicPstatesInfoExDelegate NvAPI_GPU_GetDynamicPstatesInfoEx; - public static readonly NvAPI_GPU_GetMemoryInfoDelegate NvAPI_GPU_GetMemoryInfo; - public static readonly NvAPI_GPU_GetPCIIdentifiersDelegate NvAPI_GPU_GetPCIIdentifiers; - public static readonly NvAPI_GPU_GetTachReadingDelegate NvAPI_GPU_GetTachReading; - public static readonly NvAPI_GPU_GetThermalSettingsDelegate NvAPI_GPU_GetThermalSettings; - public static readonly NvAPI_GPU_GetUsagesDelegate NvAPI_GPU_GetUsages; - public static readonly NvAPI_GPU_SetCoolerLevelsDelegate NvAPI_GPU_SetCoolerLevels; - public static readonly NvAPI_GPU_GetThermalSensorsDelegate NvAPI_GPU_ThermalGetSensors; - - private static readonly NvAPI_GetInterfaceVersionStringDelegate _nvAPI_GetInterfaceVersionString; - private static readonly NvAPI_GPU_GetFullNameDelegate _nvAPI_GPU_GetFullName; - - static NvApi() + try { - NvAPI_InitializeDelegate nvApiInitialize; - - try - { - if (!DllExists()) - return; - - GetDelegate(0x0150E828, out nvApiInitialize); - } - catch (Exception e) when (e is DllNotFoundException or ArgumentNullException or EntryPointNotFoundException or BadImageFormatException) - { + if (!DllExists()) return; - } - if (nvApiInitialize() == NvStatus.OK) - { - GetDelegate(0xE3640A56, out NvAPI_GPU_GetThermalSettings); - GetDelegate(0xCEEE8E9F, out _nvAPI_GPU_GetFullName); - GetDelegate(0x9ABDD40D, out NvAPI_EnumNvidiaDisplayHandle); - GetDelegate(0x34EF9506, out NvAPI_GetPhysicalGPUsFromDisplay); - GetDelegate(0xE5AC921F, out NvAPI_EnumPhysicalGPUs); - GetDelegate(0x5F608315, out NvAPI_GPU_GetTachReading); - GetDelegate(0x1BD69F49, out NvAPI_GPU_GetAllClocks); - GetDelegate(0x60DED2ED, out NvAPI_GPU_GetDynamicPstatesInfoEx); - GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages); - GetDelegate(0xDA141340, out NvAPI_GPU_GetCoolerSettings); - GetDelegate(0x891FA0AE, out NvAPI_GPU_SetCoolerLevels); - GetDelegate(0x774AA982, out NvAPI_GPU_GetMemoryInfo); - GetDelegate(0xF951A4D1, out NvAPI_GetDisplayDriverVersion); - GetDelegate(0x01053FA5, out _nvAPI_GetInterfaceVersionString); - GetDelegate(0x2DDFB66E, out NvAPI_GPU_GetPCIIdentifiers); - GetDelegate(0x1BE0B8E5, out NvAPI_GPU_GetBusId); - GetDelegate(0x35AED5E8, out NvAPI_GPU_ClientFanCoolersGetStatus); - GetDelegate(0xDCB616C3, out NvAPI_GPU_GetAllClockFrequencies); - GetDelegate(0x814B209F, out NvAPI_GPU_ClientFanCoolersGetControl); - GetDelegate(0xA58971A5, out NvAPI_GPU_ClientFanCoolersSetControl); - GetDelegate(0x0EDCF624E, out NvAPI_GPU_ClientPowerTopologyGetStatus); - GetDelegate(0x65FE3AAD, out NvAPI_GPU_ThermalGetSensors); - - IsAvailable = true; - } + GetDelegate(0x0150E828, out nvApiInitialize); } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum, ref NvDisplayHandle displayHandle); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(NvDisplayHandle displayHandle, [In, Out] ref NvDisplayDriverVersion nvDisplayDriverVersion); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetInterfaceVersionStringDelegate(StringBuilder version); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, out uint gpuCount); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_ClientFanCoolersGetControlDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolerControl control); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_ClientFanCoolersGetStatusDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolersStatus fanCoolersStatus); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_ClientFanCoolersSetControlDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolerControl control); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_ClientPowerTopologyGetStatusDelegate(NvPhysicalGpuHandle gpuHandle, ref NvPowerTopology powerTopology); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetAllClockFrequenciesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvGpuClockFrequencies clockFrequencies); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetAllClocksDelegate(NvPhysicalGpuHandle gpuHandle, ref NvClocks nvClocks); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetBusIdDelegate(NvPhysicalGpuHandle gpuHandle, out uint busId); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(NvPhysicalGpuHandle gpuHandle, NvCoolerTarget coolerTarget, ref NvCoolerSettings NvCoolerSettings); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetDynamicPstatesInfoExDelegate(NvPhysicalGpuHandle gpuHandle, ref NvDynamicPStatesInfo nvPStates); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetPCIIdentifiersDelegate(NvPhysicalGpuHandle gpuHandle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetTachReadingDelegate(NvPhysicalGpuHandle gpuHandle, out int value); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetThermalSensorsDelegate(NvPhysicalGpuHandle gpuHandle, ref NvThermalSensors nvThermalSensors); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int sensorIndex, ref NvThermalSettings NvThermalSettings); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_GetUsagesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvUsages nvUsages); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvCoolerLevels NvCoolerLevels); - - public enum NvFanControlMode : uint + catch (Exception e) when (e is DllNotFoundException or ArgumentNullException or EntryPointNotFoundException or BadImageFormatException) { - Auto = 0, - Manual = 1 + return; } - public enum NvLevelPolicy : uint + if (nvApiInitialize() == NvStatus.OK) { - None = 0, - Manual = 1, - Performance = 2, - TemperatureDiscrete = 4, - TemperatureContinuous = 8, - Silent = 16, - Auto = 32 + GetDelegate(0xE3640A56, out NvAPI_GPU_GetThermalSettings); + GetDelegate(0xCEEE8E9F, out _nvAPI_GPU_GetFullName); + GetDelegate(0x9ABDD40D, out NvAPI_EnumNvidiaDisplayHandle); + GetDelegate(0x34EF9506, out NvAPI_GetPhysicalGPUsFromDisplay); + GetDelegate(0xE5AC921F, out NvAPI_EnumPhysicalGPUs); + GetDelegate(0x5F608315, out NvAPI_GPU_GetTachReading); + GetDelegate(0x1BD69F49, out NvAPI_GPU_GetAllClocks); + GetDelegate(0x60DED2ED, out NvAPI_GPU_GetDynamicPstatesInfoEx); + GetDelegate(0x189A1FDF, out NvAPI_GPU_GetUsages); + GetDelegate(0xDA141340, out NvAPI_GPU_GetCoolerSettings); + GetDelegate(0x891FA0AE, out NvAPI_GPU_SetCoolerLevels); + GetDelegate(0x774AA982, out NvAPI_GPU_GetMemoryInfo); + GetDelegate(0xF951A4D1, out NvAPI_GetDisplayDriverVersion); + GetDelegate(0x01053FA5, out _nvAPI_GetInterfaceVersionString); + GetDelegate(0x2DDFB66E, out NvAPI_GPU_GetPCIIdentifiers); + GetDelegate(0x1BE0B8E5, out NvAPI_GPU_GetBusId); + GetDelegate(0x35AED5E8, out NvAPI_GPU_ClientFanCoolersGetStatus); + GetDelegate(0xDCB616C3, out NvAPI_GPU_GetAllClockFrequencies); + GetDelegate(0x814B209F, out NvAPI_GPU_ClientFanCoolersGetControl); + GetDelegate(0xA58971A5, out NvAPI_GPU_ClientFanCoolersSetControl); + GetDelegate(0x0EDCF624E, out NvAPI_GPU_ClientPowerTopologyGetStatus); + GetDelegate(0x65FE3AAD, out NvAPI_GPU_ThermalGetSensors); + + IsAvailable = true; } - - public enum NvPowerTopologyDomain : uint - { - Gpu = 0, - Board - } - - public enum NvUtilizationDomain - { - Gpu, // Core - FrameBuffer, // Memory Controller - VideoEngine, // Video Engine - BusInterface // Bus - } - - public static bool IsAvailable { get; } - - [DllImport(DllName, EntryPoint = "nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern IntPtr NvAPI32_QueryInterface(uint interfaceId); - - [DllImport(DllName64, EntryPoint = "nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - private static extern IntPtr NvAPI64_QueryInterface(uint interfaceId); - - public static NvStatus NvAPI_GPU_GetFullName(NvPhysicalGpuHandle gpuHandle, out string name) - { - StringBuilder builder = new(SHORT_STRING_MAX); - NvStatus status = _nvAPI_GPU_GetFullName?.Invoke(gpuHandle, builder) ?? NvStatus.FunctionNotFound; - - name = builder.ToString(); - return status; - } - - public static NvStatus NvAPI_GetInterfaceVersionString(out string version) - { - StringBuilder builder = new(SHORT_STRING_MAX); - NvStatus status = _nvAPI_GetInterfaceVersionString?.Invoke(builder) ?? NvStatus.FunctionNotFound; - - version = builder.ToString(); - return status; - } - - private static void GetDelegate(uint id, out T newDelegate) where T : class - { - IntPtr ptr = Environment.Is64BitOperatingSystem ? NvAPI64_QueryInterface(id) : NvAPI32_QueryInterface(id); - - if (ptr != IntPtr.Zero) - newDelegate = Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T; - else - newDelegate = null; - } - - public static bool DllExists() - { - IntPtr module = Kernel32.LoadLibrary(Environment.Is64BitOperatingSystem ? DllName64 : DllName); - if (module == IntPtr.Zero) - return false; - - Kernel32.FreeLibrary(module); - return true; - } - - internal static int MAKE_NVAPI_VERSION(int ver) - { - return Marshal.SizeOf() | (ver << 16); - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvFanCoolerControl - { - public uint Version; - private readonly uint _reserved; - public uint Count; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U4)] - private readonly uint[] _reserved2; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_FAN_CONTROLLER_ITEMS)] - public NvFanCoolerControlItem[] Items; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvFanCoolerControlItem - { - public uint CoolerId; - public uint Level; - public NvFanControlMode ControlMode; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U4)] - private readonly uint[] _reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvPowerTopology - { - public int Version; - public uint Count; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_POWER_TOPOLOGIES, ArraySubType = UnmanagedType.Struct)] - public NvPowerTopologyEntry[] Entries; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvPowerTopologyEntry - { - public NvPowerTopologyDomain Domain; - private readonly uint _reserved; - public uint PowerUsage; - private readonly uint _reserved1; - } - - internal enum NvStatus - { - OK = 0, - Error = -1, - LibraryNotFound = -2, - NoImplementation = -3, - ApiNotInitialized = -4, - InvalidArgument = -5, - NvidiaDeviceNotFound = -6, - EndEnumeration = -7, - InvalidHandle = -8, - IncompatibleStructVersion = -9, - HandleInvalidated = -10, - OpenGlContextNotCurrent = -11, - NoGlExpert = -12, - InstrumentationDisabled = -13, - ExpectedLogicalGpuHandle = -100, - ExpectedPhysicalGpuHandle = -101, - ExpectedDisplayHandle = -102, - InvalidCombination = -103, - NotSupported = -104, - PortIdNotFound = -105, - ExpectedUnattachedDisplayHandle = -106, - InvalidPerfLevel = -107, - DeviceBusy = -108, - NvPersistFileNotFound = -109, - PersistDataNotFound = -110, - ExpectedTvDisplay = -111, - ExpectedTvDisplayOnConnector = -112, - NoActiveSliTopology = -113, - SliRenderingModeNotAllowed = -114, - ExpectedDigitalFlatPanel = -115, - ArgumentExceedMaxSize = -116, - DeviceSwitchingNotAllowed = -117, - TestingClocksNotSupported = -118, - UnknownUnderscanConfig = -119, - TimeoutReconfiguringGpuTopo = -120, - DataNotFound = -121, - ExpectedAnalogDisplay = -122, - NoVidLink = -123, - RequiresReboot = -124, - InvalidHybridMode = -125, - MixedTargetTypes = -126, - Syswow64NotSupported = -127, - ImplicitSetGpuTopologyChangeNotAllowed = -128, - RequestUserToCloseNonMigratableApps = -129, - OutOfMemory = -130, - WasStillDrawing = -131, - FileNotFound = -132, - TooManyUniqueStateObjects = -133, - InvalidCall = -134, - D3D101LibraryNotFound = -135, - FunctionNotFound = -136 - } - - internal enum NvThermalController - { - None = 0, - GpuInternal, - Adm1032, - Max6649, - Max1617, - Lm99, - Lm89, - Lm64, - Adt7473, - SbMax6649, - VBiosEvt, - OS, - Unknown = -1 - } - - internal enum NvThermalTarget - { - None = 0, - Gpu = 1, - Memory = 2, - PowerSupply = 4, - Board = 8, - VisualComputingBoard = 9, - VisualComputingInlet = 10, - VisualComputingOutlet = 11, - All = 15, - Unknown = -1 - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvSensor - { - public NvThermalController Controller; - public uint DefaultMinTemp; - public uint DefaultMaxTemp; - public uint CurrentTemp; - public NvThermalTarget Target; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvThermalSettings - { - public uint Version; - public uint Count; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_THERMAL_SENSORS_PER_GPU)] - public NvSensor[] Sensor; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NvDisplayHandle - { - private readonly IntPtr ptr; - } - - [StructLayout(LayoutKind.Sequential)] - internal struct NvPhysicalGpuHandle - { - private readonly IntPtr ptr; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvClocks - { - public uint Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_CLOCKS_PER_GPU)] - public uint[] Clock; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvDynamicPStatesInfo - { - public uint Version; - public uint Flags; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_GPU_UTILIZATIONS)] - public NvDynamicPState[] Utilizations; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvDynamicPState - { - public bool IsPresent; - public int Percentage; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvUsages - { - public uint Version; - private readonly uint _reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] - public NvUsagesEntry[] Entries; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvUsagesEntry - { - public uint IsPresent; - public uint Percentage; - private readonly uint _reserved1; - private readonly uint _reserved2; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvCooler - { - public int Type; - public int Controller; - public int DefaultMin; - public int DefaultMax; - public int CurrentMin; - public int CurrentMax; - public int CurrentLevel; - public int DefaultPolicy; - public int CurrentPolicy; - public int Target; - public int ControlType; - public int Active; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvFanCoolersStatus - { - public uint Version; - public uint Count; - - public ulong Reserved1; - public ulong Reserved2; - public ulong Reserved3; - public ulong Reserved4; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_FAN_COOLERS_STATUS_ITEMS)] - internal NvFanCoolersStatusItem[] Items; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvFanCoolersStatusItem - { - public uint CoolerId; - public uint CurrentRpm; - public uint CurrentMinLevel; - public uint CurrentMaxLevel; - public uint CurrentLevel; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U4)] - private readonly uint[] _reserved; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvCoolerSettings - { - public uint Version; - public uint Count; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_COOLERS_PER_GPU)] - public NvCooler[] Cooler; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvLevel - { - public int Level; - public NvLevelPolicy Policy; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvCoolerLevels - { - public uint Version; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_COOLERS_PER_GPU)] - public NvLevel[] Levels; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - public struct NvThermalSensors - { - internal uint Version; - internal uint Mask; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = THERMAL_SENSOR_RESERVED_COUNT)] - internal int[] Reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = THERMAL_SENSOR_TEMPERATURE_COUNT)] - internal int[] Temperatures; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvMemoryInfo - { - public uint Version; - - public uint DedicatedVideoMemory; - - public uint AvailableDedicatedVideoMemory; - - public uint SystemVideoMemory; - - public uint SharedSystemMemory; - - public uint CurrentAvailableDedicatedVideoMemory; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvDisplayDriverVersion - { - public uint Version; - public uint DriverVersion; - public uint BldChangeListNum; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SHORT_STRING_MAX)] - public string BuildBranch; - - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SHORT_STRING_MAX)] - public string Adapter; - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvGpuClockFrequencies - { - public uint Version; - private readonly uint _reserved; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_GPU_PUBLIC_CLOCKS)] - public NvGpuClockFrequenciesDomain[] Clocks; - } - - internal enum NvGpuPublicClockId - { - Graphics = 0, - Memory = 4, - Processor = 7, - Video = 8, - Undefined = MAX_CLOCKS_PER_GPU - } - - internal enum NvGpuClockFrequenciesClockType - { - CurrentFrequency, - BaseClock, - BoostClock, - ClockTypeNumber - } - - internal enum NvCoolerTarget - { - None = 0, - Gpu, - Memory, - PowerSupply = 4, - All = 7 // This cooler cools all of the components related to its target gpu. - } - - [StructLayout(LayoutKind.Sequential, Pack = 8)] - internal struct NvGpuClockFrequenciesDomain - { - private readonly uint _isPresent; - public uint Frequency; - - public bool IsPresent => (_isPresent & 1) != 0; - } - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate NvStatus NvAPI_InitializeDelegate(); - - [UnmanagedFunctionPointer(CallingConvention.Cdecl)] - private delegate NvStatus NvAPI_GPU_GetFullNameDelegate(NvPhysicalGpuHandle gpuHandle, StringBuilder name); } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_EnumNvidiaDisplayHandleDelegate(int thisEnum, ref NvDisplayHandle displayHandle); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_EnumPhysicalGPUsDelegate([Out] NvPhysicalGpuHandle[] gpuHandles, out int gpuCount); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GetDisplayDriverVersionDelegate(NvDisplayHandle displayHandle, [In, Out] ref NvDisplayDriverVersion nvDisplayDriverVersion); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GetInterfaceVersionStringDelegate(StringBuilder version); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GetPhysicalGPUsFromDisplayDelegate(NvDisplayHandle displayHandle, [Out] NvPhysicalGpuHandle[] gpuHandles, out uint gpuCount); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_ClientFanCoolersGetControlDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolerControl control); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_ClientFanCoolersGetStatusDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolersStatus fanCoolersStatus); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_ClientFanCoolersSetControlDelegate(NvPhysicalGpuHandle gpuHandle, ref NvFanCoolerControl control); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_ClientPowerTopologyGetStatusDelegate(NvPhysicalGpuHandle gpuHandle, ref NvPowerTopology powerTopology); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetAllClockFrequenciesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvGpuClockFrequencies clockFrequencies); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetAllClocksDelegate(NvPhysicalGpuHandle gpuHandle, ref NvClocks nvClocks); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetBusIdDelegate(NvPhysicalGpuHandle gpuHandle, out uint busId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetCoolerSettingsDelegate(NvPhysicalGpuHandle gpuHandle, NvCoolerTarget coolerTarget, ref NvCoolerSettings NvCoolerSettings); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetDynamicPstatesInfoExDelegate(NvPhysicalGpuHandle gpuHandle, ref NvDynamicPStatesInfo nvPStates); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetMemoryInfoDelegate(NvDisplayHandle displayHandle, ref NvMemoryInfo nvMemoryInfo); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetPCIIdentifiersDelegate(NvPhysicalGpuHandle gpuHandle, out uint deviceId, out uint subSystemId, out uint revisionId, out uint extDeviceId); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetTachReadingDelegate(NvPhysicalGpuHandle gpuHandle, out int value); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetThermalSensorsDelegate(NvPhysicalGpuHandle gpuHandle, ref NvThermalSensors nvThermalSensors); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetThermalSettingsDelegate(NvPhysicalGpuHandle gpuHandle, int sensorIndex, ref NvThermalSettings NvThermalSettings); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_GetUsagesDelegate(NvPhysicalGpuHandle gpuHandle, ref NvUsages nvUsages); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate NvStatus NvAPI_GPU_SetCoolerLevelsDelegate(NvPhysicalGpuHandle gpuHandle, int coolerIndex, ref NvCoolerLevels NvCoolerLevels); + + public enum NvFanControlMode : uint + { + Auto = 0, + Manual = 1 + } + + public enum NvLevelPolicy : uint + { + None = 0, + Manual = 1, + Performance = 2, + TemperatureDiscrete = 4, + TemperatureContinuous = 8, + Silent = 16, + Auto = 32 + } + + public enum NvPowerTopologyDomain : uint + { + Gpu = 0, + Board + } + + public enum NvUtilizationDomain + { + Gpu, // Core + FrameBuffer, // Memory Controller + VideoEngine, // Video Engine + BusInterface // Bus + } + + public static bool IsAvailable { get; } + + [DllImport(DllName, EntryPoint = "nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static extern IntPtr NvAPI32_QueryInterface(uint interfaceId); + + [DllImport(DllName64, EntryPoint = "nvapi_QueryInterface", CallingConvention = CallingConvention.Cdecl, PreserveSig = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + private static extern IntPtr NvAPI64_QueryInterface(uint interfaceId); + + public static NvStatus NvAPI_GPU_GetFullName(NvPhysicalGpuHandle gpuHandle, out string name) + { + StringBuilder builder = new(SHORT_STRING_MAX); + NvStatus status = _nvAPI_GPU_GetFullName?.Invoke(gpuHandle, builder) ?? NvStatus.FunctionNotFound; + + name = builder.ToString(); + return status; + } + + public static NvStatus NvAPI_GetInterfaceVersionString(out string version) + { + StringBuilder builder = new(SHORT_STRING_MAX); + NvStatus status = _nvAPI_GetInterfaceVersionString?.Invoke(builder) ?? NvStatus.FunctionNotFound; + + version = builder.ToString(); + return status; + } + + private static void GetDelegate(uint id, out T newDelegate) where T : class + { + IntPtr ptr = Environment.Is64BitOperatingSystem ? NvAPI64_QueryInterface(id) : NvAPI32_QueryInterface(id); + + if (ptr != IntPtr.Zero) + newDelegate = Marshal.GetDelegateForFunctionPointer(ptr, typeof(T)) as T; + else + newDelegate = null; + } + + public static bool DllExists() + { + IntPtr module = Kernel32.LoadLibrary(Environment.Is64BitOperatingSystem ? DllName64 : DllName); + if (module == IntPtr.Zero) + return false; + + Kernel32.FreeLibrary(module); + return true; + } + + internal static int MAKE_NVAPI_VERSION(int ver) + { + return Marshal.SizeOf() | (ver << 16); + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvFanCoolerControl + { + public uint Version; + private readonly uint _reserved; + public uint Count; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U4)] + private readonly uint[] _reserved2; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_FAN_CONTROLLER_ITEMS)] + public NvFanCoolerControlItem[] Items; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvFanCoolerControlItem + { + public uint CoolerId; + public uint Level; + public NvFanControlMode ControlMode; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U4)] + private readonly uint[] _reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvPowerTopology + { + public int Version; + public uint Count; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_POWER_TOPOLOGIES, ArraySubType = UnmanagedType.Struct)] + public NvPowerTopologyEntry[] Entries; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvPowerTopologyEntry + { + public NvPowerTopologyDomain Domain; + private readonly uint _reserved; + public uint PowerUsage; + private readonly uint _reserved1; + } + + internal enum NvStatus + { + OK = 0, + Error = -1, + LibraryNotFound = -2, + NoImplementation = -3, + ApiNotInitialized = -4, + InvalidArgument = -5, + NvidiaDeviceNotFound = -6, + EndEnumeration = -7, + InvalidHandle = -8, + IncompatibleStructVersion = -9, + HandleInvalidated = -10, + OpenGlContextNotCurrent = -11, + NoGlExpert = -12, + InstrumentationDisabled = -13, + ExpectedLogicalGpuHandle = -100, + ExpectedPhysicalGpuHandle = -101, + ExpectedDisplayHandle = -102, + InvalidCombination = -103, + NotSupported = -104, + PortIdNotFound = -105, + ExpectedUnattachedDisplayHandle = -106, + InvalidPerfLevel = -107, + DeviceBusy = -108, + NvPersistFileNotFound = -109, + PersistDataNotFound = -110, + ExpectedTvDisplay = -111, + ExpectedTvDisplayOnConnector = -112, + NoActiveSliTopology = -113, + SliRenderingModeNotAllowed = -114, + ExpectedDigitalFlatPanel = -115, + ArgumentExceedMaxSize = -116, + DeviceSwitchingNotAllowed = -117, + TestingClocksNotSupported = -118, + UnknownUnderscanConfig = -119, + TimeoutReconfiguringGpuTopo = -120, + DataNotFound = -121, + ExpectedAnalogDisplay = -122, + NoVidLink = -123, + RequiresReboot = -124, + InvalidHybridMode = -125, + MixedTargetTypes = -126, + Syswow64NotSupported = -127, + ImplicitSetGpuTopologyChangeNotAllowed = -128, + RequestUserToCloseNonMigratableApps = -129, + OutOfMemory = -130, + WasStillDrawing = -131, + FileNotFound = -132, + TooManyUniqueStateObjects = -133, + InvalidCall = -134, + D3D101LibraryNotFound = -135, + FunctionNotFound = -136 + } + + internal enum NvThermalController + { + None = 0, + GpuInternal, + Adm1032, + Max6649, + Max1617, + Lm99, + Lm89, + Lm64, + Adt7473, + SbMax6649, + VBiosEvt, + OS, + Unknown = -1 + } + + internal enum NvThermalTarget + { + None = 0, + Gpu = 1, + Memory = 2, + PowerSupply = 4, + Board = 8, + VisualComputingBoard = 9, + VisualComputingInlet = 10, + VisualComputingOutlet = 11, + All = 15, + Unknown = -1 + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvSensor + { + public NvThermalController Controller; + public uint DefaultMinTemp; + public uint DefaultMaxTemp; + public uint CurrentTemp; + public NvThermalTarget Target; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvThermalSettings + { + public uint Version; + public uint Count; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_THERMAL_SENSORS_PER_GPU)] + public NvSensor[] Sensor; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NvDisplayHandle + { + private readonly IntPtr ptr; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct NvPhysicalGpuHandle + { + private readonly IntPtr ptr; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvClocks + { + public uint Version; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_CLOCKS_PER_GPU)] + public uint[] Clock; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvDynamicPStatesInfo + { + public uint Version; + public uint Flags; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_GPU_UTILIZATIONS)] + public NvDynamicPState[] Utilizations; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvDynamicPState + { + public bool IsPresent; + public int Percentage; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvUsages + { + public uint Version; + private readonly uint _reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public NvUsagesEntry[] Entries; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvUsagesEntry + { + public uint IsPresent; + public uint Percentage; + private readonly uint _reserved1; + private readonly uint _reserved2; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvCooler + { + public int Type; + public int Controller; + public int DefaultMin; + public int DefaultMax; + public int CurrentMin; + public int CurrentMax; + public int CurrentLevel; + public int DefaultPolicy; + public int CurrentPolicy; + public int Target; + public int ControlType; + public int Active; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvFanCoolersStatus + { + public uint Version; + public uint Count; + + public ulong Reserved1; + public ulong Reserved2; + public ulong Reserved3; + public ulong Reserved4; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_FAN_COOLERS_STATUS_ITEMS)] + internal NvFanCoolersStatusItem[] Items; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvFanCoolersStatusItem + { + public uint CoolerId; + public uint CurrentRpm; + public uint CurrentMinLevel; + public uint CurrentMaxLevel; + public uint CurrentLevel; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8, ArraySubType = UnmanagedType.U4)] + private readonly uint[] _reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvCoolerSettings + { + public uint Version; + public uint Count; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_COOLERS_PER_GPU)] + public NvCooler[] Cooler; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvLevel + { + public int Level; + public NvLevelPolicy Policy; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvCoolerLevels + { + public uint Version; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_COOLERS_PER_GPU)] + public NvLevel[] Levels; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + public struct NvThermalSensors + { + internal uint Version; + internal uint Mask; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = THERMAL_SENSOR_RESERVED_COUNT)] + internal int[] Reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = THERMAL_SENSOR_TEMPERATURE_COUNT)] + internal int[] Temperatures; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvMemoryInfo + { + public uint Version; + + public uint DedicatedVideoMemory; + + public uint AvailableDedicatedVideoMemory; + + public uint SystemVideoMemory; + + public uint SharedSystemMemory; + + public uint CurrentAvailableDedicatedVideoMemory; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvDisplayDriverVersion + { + public uint Version; + public uint DriverVersion; + public uint BldChangeListNum; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SHORT_STRING_MAX)] + public string BuildBranch; + + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = SHORT_STRING_MAX)] + public string Adapter; + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvGpuClockFrequencies + { + public uint Version; + private readonly uint _reserved; + + [MarshalAs(UnmanagedType.ByValArray, SizeConst = MAX_GPU_PUBLIC_CLOCKS)] + public NvGpuClockFrequenciesDomain[] Clocks; + } + + internal enum NvGpuPublicClockId + { + Graphics = 0, + Memory = 4, + Processor = 7, + Video = 8, + Undefined = MAX_CLOCKS_PER_GPU + } + + internal enum NvGpuClockFrequenciesClockType + { + CurrentFrequency, + BaseClock, + BoostClock, + ClockTypeNumber + } + + internal enum NvCoolerTarget + { + None = 0, + Gpu, + Memory, + PowerSupply = 4, + All = 7 // This cooler cools all of the components related to its target gpu. + } + + [StructLayout(LayoutKind.Sequential, Pack = 8)] + internal struct NvGpuClockFrequenciesDomain + { + private readonly uint _isPresent; + public uint Frequency; + + public bool IsPresent => (_isPresent & 1) != 0; + } + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate NvStatus NvAPI_InitializeDelegate(); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + private delegate NvStatus NvAPI_GPU_GetFullNameDelegate(NvPhysicalGpuHandle gpuHandle, StringBuilder name); } diff --git a/LibreHardwareMonitorLib/Interop/NvidiaML.cs b/LibreHardwareMonitorLib/Interop/NvidiaML.cs index b222f50..fc1ee13 100644 --- a/LibreHardwareMonitorLib/Interop/NvidiaML.cs +++ b/LibreHardwareMonitorLib/Interop/NvidiaML.cs @@ -7,437 +7,436 @@ using System; using System.IO; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal static class NvidiaML { - internal static class NvidiaML + private const string LinuxDllName = "nvidia-ml"; + private const string WindowsDllName = "nvml.dll"; + + private static readonly object _syncRoot = new(); + + private static IntPtr _windowsDll; + + private static WindowsNvmlGetHandleDelegate _windowsNvmlDeviceGetHandleByIndex; + private static WindowsNvmlGetHandleByPciBusIdDelegate _windowsNvmlDeviceGetHandleByPciBusId; + private static WindowsNvmlDeviceGetPcieThroughputDelegate _windowsNvmlDeviceGetPcieThroughputDelegate; + private static WindowsNvmlDeviceGetPciInfo _windowsNvmlDeviceGetPciInfo; + private static WindowsNvmlGetPowerUsageDelegate _windowsNvmlDeviceGetPowerUsage; + private static WindowsNvmlDelegate _windowsNvmlInit; + private static WindowsNvmlDelegate _windowsNvmlShutdown; + + public enum NvmlPcieUtilCounter { - private const string LinuxDllName = "nvidia-ml"; - private const string WindowsDllName = "nvml.dll"; + TxBytes = 0, + RxBytes = 1 + } - private static readonly object _syncRoot = new(); + public enum NvmlReturn + { + /// + /// The operation was successful + /// + Success = 0, - private static IntPtr _windowsDll; + /// + /// NvidiaML was not first initialized with nvmlInit() + /// + Uninitialized = 1, - private static WindowsNvmlGetHandleDelegate _windowsNvmlDeviceGetHandleByIndex; - private static WindowsNvmlGetHandleByPciBusIdDelegate _windowsNvmlDeviceGetHandleByPciBusId; - private static WindowsNvmlDeviceGetPcieThroughputDelegate _windowsNvmlDeviceGetPcieThroughputDelegate; - private static WindowsNvmlDeviceGetPciInfo _windowsNvmlDeviceGetPciInfo; - private static WindowsNvmlGetPowerUsageDelegate _windowsNvmlDeviceGetPowerUsage; - private static WindowsNvmlDelegate _windowsNvmlInit; - private static WindowsNvmlDelegate _windowsNvmlShutdown; + /// + /// A supplied argument is invalid + /// + InvalidArgument = 2, - public enum NvmlPcieUtilCounter + /// + /// The requested operation is not available on target device + /// + NotSupported = 3, + + /// + /// The current user does not have permission for operation + /// + NoPermission = 4, + + /// + /// A query to find an object was unsuccessful + /// + NotFound = 6, + + /// + /// An input argument is not large enough + /// + InsufficientSize = 7, + + /// + /// A device's external power cables are not properly attached + /// + InsufficientPower = 8, + + /// + /// NVIDIA driver is not loaded + /// + DriverNotLoaded = 9, + + /// + /// User provided timeout passed + /// + TimeOut = 10, + + /// + /// NVIDIA Kernel detected an interrupt issue with a GPU + /// + IRQIssue = 11, + + /// + /// NvidiaML Shared Library couldn't be found or loaded + /// + LibraryNotFound = 12, + + /// + /// Local version of NvidiaML doesn't implement this function + /// + FunctionNotFound = 13, + + /// + /// infoROM is corrupted + /// + CorruptedInfoRom = 14, + + /// + /// The GPU has fallen off the bus or has otherwise become inaccessible + /// + GpuIsLost = 15, + + /// + /// The GPU requires a reset before it can be used again + /// + ResetRequired = 16, + + /// + /// The GPU control device has been blocked by the operating system/cgroups + /// + OperatingSystem = 17, + + /// + /// RM detects a driver/library version mismatch + /// + LibRmVersionMismatch = 18, + + /// + /// An operation cannot be performed because the GPU is currently in use + /// + InUse = 19, + + /// + /// An public driver error occurred + /// + Unknown = 999 + } + + public static bool IsAvailable { get; private set; } + + public static bool Initialize() + { + lock (_syncRoot) { - TxBytes = 0, - RxBytes = 1 - } - - public enum NvmlReturn - { - /// - /// The operation was successful - /// - Success = 0, - - /// - /// NvidiaML was not first initialized with nvmlInit() - /// - Uninitialized = 1, - - /// - /// A supplied argument is invalid - /// - InvalidArgument = 2, - - /// - /// The requested operation is not available on target device - /// - NotSupported = 3, - - /// - /// The current user does not have permission for operation - /// - NoPermission = 4, - - /// - /// A query to find an object was unsuccessful - /// - NotFound = 6, - - /// - /// An input argument is not large enough - /// - InsufficientSize = 7, - - /// - /// A device's external power cables are not properly attached - /// - InsufficientPower = 8, - - /// - /// NVIDIA driver is not loaded - /// - DriverNotLoaded = 9, - - /// - /// User provided timeout passed - /// - TimeOut = 10, - - /// - /// NVIDIA Kernel detected an interrupt issue with a GPU - /// - IRQIssue = 11, - - /// - /// NvidiaML Shared Library couldn't be found or loaded - /// - LibraryNotFound = 12, - - /// - /// Local version of NvidiaML doesn't implement this function - /// - FunctionNotFound = 13, - - /// - /// infoROM is corrupted - /// - CorruptedInfoRom = 14, - - /// - /// The GPU has fallen off the bus or has otherwise become inaccessible - /// - GpuIsLost = 15, - - /// - /// The GPU requires a reset before it can be used again - /// - ResetRequired = 16, - - /// - /// The GPU control device has been blocked by the operating system/cgroups - /// - OperatingSystem = 17, - - /// - /// RM detects a driver/library version mismatch - /// - LibRmVersionMismatch = 18, - - /// - /// An operation cannot be performed because the GPU is currently in use - /// - InUse = 19, - - /// - /// An public driver error occurred - /// - Unknown = 999 - } - - public static bool IsAvailable { get; private set; } - - public static bool Initialize() - { - lock (_syncRoot) + if (IsAvailable) { - if (IsAvailable) - { - return true; - } + return true; + } - if (Software.OperatingSystem.IsUnix) + if (Software.OperatingSystem.IsUnix) + { + try + { + IsAvailable = nvmlInit() == NvmlReturn.Success; + } + catch (DllNotFoundException) + { } + catch (EntryPointNotFoundException) { try { - IsAvailable = nvmlInit() == NvmlReturn.Success; + IsAvailable = nvmlInitLegacy() == NvmlReturn.Success; } - catch (DllNotFoundException) - { } catch (EntryPointNotFoundException) - { - try - { - IsAvailable = nvmlInitLegacy() == NvmlReturn.Success; - } - catch (EntryPointNotFoundException) - { } - } + { } } - else if (IsNvmlCompatibleWindowsVersion()) + } + else if (IsNvmlCompatibleWindowsVersion()) + { + // Attempt to load the Nvidia Management Library from the + // windows standard search order for applications. This will + // help installations that either have the library in + // %windir%/system32 or provide their own library + _windowsDll = Kernel32.LoadLibrary(WindowsDllName); + + // If there is no dll in the path, then attempt to load it + // from program files + if (_windowsDll == IntPtr.Zero) { - // Attempt to load the Nvidia Management Library from the - // windows standard search order for applications. This will - // help installations that either have the library in - // %windir%/system32 or provide their own library - _windowsDll = Kernel32.LoadLibrary(WindowsDllName); + string programFilesDirectory = Environment.ExpandEnvironmentVariables("%ProgramW6432%"); + string dllPath = Path.Combine(programFilesDirectory, @"NVIDIA Corporation\NVSMI", WindowsDllName); - // If there is no dll in the path, then attempt to load it - // from program files - if (_windowsDll == IntPtr.Zero) - { - string programFilesDirectory = Environment.ExpandEnvironmentVariables("%ProgramW6432%"); - string dllPath = Path.Combine(programFilesDirectory, @"NVIDIA Corporation\NVSMI", WindowsDllName); - - _windowsDll = Kernel32.LoadLibrary(dllPath); - } - - IsAvailable = (_windowsDll != IntPtr.Zero) && InitialiseDelegates() && (_windowsNvmlInit() == NvmlReturn.Success); + _windowsDll = Kernel32.LoadLibrary(dllPath); } - return IsAvailable; + IsAvailable = (_windowsDll != IntPtr.Zero) && InitialiseDelegates() && (_windowsNvmlInit() == NvmlReturn.Success); } + + return IsAvailable; } + } - private static bool IsNvmlCompatibleWindowsVersion() + private static bool IsNvmlCompatibleWindowsVersion() + { + return Software.OperatingSystem.Is64Bit && ((Environment.OSVersion.Version.Major > 6) || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1)); + } + + private static bool InitialiseDelegates() + { + IntPtr nvmlInit = Kernel32.GetProcAddress(_windowsDll, "nvmlInit_v2"); + + if (nvmlInit != IntPtr.Zero) { - return Software.OperatingSystem.Is64Bit && ((Environment.OSVersion.Version.Major > 6) || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor >= 1)); + _windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate)); } - - private static bool InitialiseDelegates() + else { - IntPtr nvmlInit = Kernel32.GetProcAddress(_windowsDll, "nvmlInit_v2"); - + nvmlInit = Kernel32.GetProcAddress(_windowsDll, "nvmlInit"); if (nvmlInit != IntPtr.Zero) - { _windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate)); - } - else - { - nvmlInit = Kernel32.GetProcAddress(_windowsDll, "nvmlInit"); - if (nvmlInit != IntPtr.Zero) - _windowsNvmlInit = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlInit, typeof(WindowsNvmlDelegate)); - else - return false; - } - - IntPtr nvmlShutdown = Kernel32.GetProcAddress(_windowsDll, "nvmlShutdown"); - if (nvmlShutdown != IntPtr.Zero) - _windowsNvmlShutdown = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlShutdown, typeof(WindowsNvmlDelegate)); else return false; + } - IntPtr nvmlGetHandle = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex_v2"); + IntPtr nvmlShutdown = Kernel32.GetProcAddress(_windowsDll, "nvmlShutdown"); + if (nvmlShutdown != IntPtr.Zero) + _windowsNvmlShutdown = (WindowsNvmlDelegate)Marshal.GetDelegateForFunctionPointer(nvmlShutdown, typeof(WindowsNvmlDelegate)); + else + return false; + + IntPtr nvmlGetHandle = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex_v2"); + if (nvmlGetHandle != IntPtr.Zero) + _windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate)); + else + { + nvmlGetHandle = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex"); if (nvmlGetHandle != IntPtr.Zero) _windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate)); - else - { - nvmlGetHandle = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByIndex"); - if (nvmlGetHandle != IntPtr.Zero) - _windowsNvmlDeviceGetHandleByIndex = (WindowsNvmlGetHandleDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandle, typeof(WindowsNvmlGetHandleDelegate)); - else - return false; - } - - IntPtr nvmlGetPowerUsage = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPowerUsage"); - if (nvmlGetPowerUsage != IntPtr.Zero) - _windowsNvmlDeviceGetPowerUsage = (WindowsNvmlGetPowerUsageDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPowerUsage, typeof(WindowsNvmlGetPowerUsageDelegate)); else return false; - - IntPtr nvmlGetPcieThroughput = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPcieThroughput"); - if (nvmlGetPcieThroughput != IntPtr.Zero) - _windowsNvmlDeviceGetPcieThroughputDelegate = (WindowsNvmlDeviceGetPcieThroughputDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPcieThroughput, typeof(WindowsNvmlDeviceGetPcieThroughputDelegate)); - else - return false; - - IntPtr nvmlGetHandlePciBus = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByPciBusId_v2"); - if (nvmlGetHandlePciBus != IntPtr.Zero) - _windowsNvmlDeviceGetHandleByPciBusId = (WindowsNvmlGetHandleByPciBusIdDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandlePciBus, typeof(WindowsNvmlGetHandleByPciBusIdDelegate)); - else - return false; - - IntPtr nvmlDeviceGetPciInfo = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPciInfo_v2"); - if (nvmlDeviceGetPciInfo != IntPtr.Zero) - _windowsNvmlDeviceGetPciInfo = (WindowsNvmlDeviceGetPciInfo)Marshal.GetDelegateForFunctionPointer(nvmlDeviceGetPciInfo, typeof(WindowsNvmlDeviceGetPciInfo)); - else - return false; - - return true; } - public static void Close() - { - lock (_syncRoot) - { - if (IsAvailable) - { - if (Software.OperatingSystem.IsUnix) - { - nvmlShutdown(); - } - else if (_windowsDll != IntPtr.Zero) - { - _windowsNvmlShutdown(); - Kernel32.FreeLibrary(_windowsDll); - } + IntPtr nvmlGetPowerUsage = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPowerUsage"); + if (nvmlGetPowerUsage != IntPtr.Zero) + _windowsNvmlDeviceGetPowerUsage = (WindowsNvmlGetPowerUsageDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPowerUsage, typeof(WindowsNvmlGetPowerUsageDelegate)); + else + return false; - IsAvailable = false; - } - } - } + IntPtr nvmlGetPcieThroughput = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPcieThroughput"); + if (nvmlGetPcieThroughput != IntPtr.Zero) + _windowsNvmlDeviceGetPcieThroughputDelegate = (WindowsNvmlDeviceGetPcieThroughputDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetPcieThroughput, typeof(WindowsNvmlDeviceGetPcieThroughputDelegate)); + else + return false; - public static NvmlDevice? NvmlDeviceGetHandleByIndex(int index) + IntPtr nvmlGetHandlePciBus = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetHandleByPciBusId_v2"); + if (nvmlGetHandlePciBus != IntPtr.Zero) + _windowsNvmlDeviceGetHandleByPciBusId = (WindowsNvmlGetHandleByPciBusIdDelegate)Marshal.GetDelegateForFunctionPointer(nvmlGetHandlePciBus, typeof(WindowsNvmlGetHandleByPciBusIdDelegate)); + else + return false; + + IntPtr nvmlDeviceGetPciInfo = Kernel32.GetProcAddress(_windowsDll, "nvmlDeviceGetPciInfo_v2"); + if (nvmlDeviceGetPciInfo != IntPtr.Zero) + _windowsNvmlDeviceGetPciInfo = (WindowsNvmlDeviceGetPciInfo)Marshal.GetDelegateForFunctionPointer(nvmlDeviceGetPciInfo, typeof(WindowsNvmlDeviceGetPciInfo)); + else + return false; + + return true; + } + + public static void Close() + { + lock (_syncRoot) { if (IsAvailable) { - NvmlDevice nvmlDevice; if (Software.OperatingSystem.IsUnix) { - try - { - if (nvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; - } - catch (EntryPointNotFoundException) - { - if (nvmlDeviceGetHandleByIndexLegacy(index, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; - } + nvmlShutdown(); } - else if (_windowsNvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; - } - - return null; - } - - public static NvmlDevice? NvmlDeviceGetHandleByPciBusId(string pciBusId) - { - if (IsAvailable) - { - NvmlDevice nvmlDevice; - if (Software.OperatingSystem.IsUnix) + else if (_windowsDll != IntPtr.Zero) { - if (nvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; + _windowsNvmlShutdown(); + Kernel32.FreeLibrary(_windowsDll); } - else if (_windowsNvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) - return nvmlDevice; + + IsAvailable = false; } - - return null; - } - - public static int? NvmlDeviceGetPowerUsage(NvmlDevice nvmlDevice) - { - if (IsAvailable) - { - int powerUsage; - if (Software.OperatingSystem.IsUnix) - { - if (nvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) - return powerUsage; - } - else if (_windowsNvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) - return powerUsage; - } - - return null; - } - - public static uint? NvmlDeviceGetPcieThroughput(NvmlDevice nvmlDevice, NvmlPcieUtilCounter counter) - { - if (IsAvailable) - { - uint pcieThroughput; - if (Software.OperatingSystem.IsUnix) - { - if (nvmlDeviceGetPcieThroughput(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) - return pcieThroughput; - } - else if (_windowsNvmlDeviceGetPcieThroughputDelegate(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) - return pcieThroughput; - } - - return null; - } - - public static NvmlPciInfo? NvmlDeviceGetPciInfo(NvmlDevice nvmlDevice) - { - if (IsAvailable) - { - var pci = new NvmlPciInfo(); - - if (Software.OperatingSystem.IsUnix) - { - if (nvmlDeviceGetPciInfo(nvmlDevice, ref pci) == NvmlReturn.Success) - return pci; - } - else if (_windowsNvmlDeviceGetPciInfo(nvmlDevice, ref pci) == NvmlReturn.Success) - return pci; - } - - return null; - } - - [DllImport(LinuxDllName, EntryPoint = "nvmlInit_v2", ExactSpelling = true)] - private static extern NvmlReturn nvmlInit(); - - [DllImport(LinuxDllName, EntryPoint = "nvmlInit", ExactSpelling = true)] - private static extern NvmlReturn nvmlInitLegacy(); - - [DllImport(LinuxDllName, EntryPoint = "nvmlShutdown", ExactSpelling = true)] - private static extern NvmlReturn nvmlShutdown(); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex_v2", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetHandleByIndex(int index, out NvmlDevice device); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByPciBusId_v2", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetHandleByPciBusId([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetHandleByIndexLegacy(int index, out NvmlDevice device); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPowerUsage", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetPowerUsage(NvmlDevice device, out int power); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPcieThroughput", ExactSpelling = true)] - private static extern NvmlReturn nvmlDeviceGetPcieThroughput(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); - - [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPciInfo_v2")] - private static extern NvmlReturn nvmlDeviceGetPciInfo(NvmlDevice device, ref NvmlPciInfo pci); - - private delegate NvmlReturn WindowsNvmlDelegate(); - - private delegate NvmlReturn WindowsNvmlGetHandleDelegate(int index, out NvmlDevice device); - - private delegate NvmlReturn WindowsNvmlGetHandleByPciBusIdDelegate([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); - - private delegate NvmlReturn WindowsNvmlGetPowerUsageDelegate(NvmlDevice device, out int power); - - private delegate NvmlReturn WindowsNvmlDeviceGetPcieThroughputDelegate(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); - - private delegate NvmlReturn WindowsNvmlDeviceGetPciInfo(NvmlDevice device, ref NvmlPciInfo pci); - - [StructLayout(LayoutKind.Sequential)] - public struct NvmlDevice - { - public IntPtr Handle; - } - - [StructLayout(LayoutKind.Sequential)] - public struct NvmlPciInfo - { - [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] - public string busId; - - public uint domain; - - public uint bus; - - public uint device; - - public ushort pciVendorId; - - public ushort pciDeviceId; - - public uint pciSubSystemId; - - public uint reserved0; - public uint reserved1; - public uint reserved2; - public uint reserved3; } } -} + + public static NvmlDevice? NvmlDeviceGetHandleByIndex(int index) + { + if (IsAvailable) + { + NvmlDevice nvmlDevice; + if (Software.OperatingSystem.IsUnix) + { + try + { + if (nvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + catch (EntryPointNotFoundException) + { + if (nvmlDeviceGetHandleByIndexLegacy(index, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + } + else if (_windowsNvmlDeviceGetHandleByIndex(index, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + + return null; + } + + public static NvmlDevice? NvmlDeviceGetHandleByPciBusId(string pciBusId) + { + if (IsAvailable) + { + NvmlDevice nvmlDevice; + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + else if (_windowsNvmlDeviceGetHandleByPciBusId(pciBusId, out nvmlDevice) == NvmlReturn.Success) + return nvmlDevice; + } + + return null; + } + + public static int? NvmlDeviceGetPowerUsage(NvmlDevice nvmlDevice) + { + if (IsAvailable) + { + int powerUsage; + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) + return powerUsage; + } + else if (_windowsNvmlDeviceGetPowerUsage(nvmlDevice, out powerUsage) == NvmlReturn.Success) + return powerUsage; + } + + return null; + } + + public static uint? NvmlDeviceGetPcieThroughput(NvmlDevice nvmlDevice, NvmlPcieUtilCounter counter) + { + if (IsAvailable) + { + uint pcieThroughput; + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetPcieThroughput(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) + return pcieThroughput; + } + else if (_windowsNvmlDeviceGetPcieThroughputDelegate(nvmlDevice, counter, out pcieThroughput) == NvmlReturn.Success) + return pcieThroughput; + } + + return null; + } + + public static NvmlPciInfo? NvmlDeviceGetPciInfo(NvmlDevice nvmlDevice) + { + if (IsAvailable) + { + var pci = new NvmlPciInfo(); + + if (Software.OperatingSystem.IsUnix) + { + if (nvmlDeviceGetPciInfo(nvmlDevice, ref pci) == NvmlReturn.Success) + return pci; + } + else if (_windowsNvmlDeviceGetPciInfo(nvmlDevice, ref pci) == NvmlReturn.Success) + return pci; + } + + return null; + } + + [DllImport(LinuxDllName, EntryPoint = "nvmlInit_v2", ExactSpelling = true)] + private static extern NvmlReturn nvmlInit(); + + [DllImport(LinuxDllName, EntryPoint = "nvmlInit", ExactSpelling = true)] + private static extern NvmlReturn nvmlInitLegacy(); + + [DllImport(LinuxDllName, EntryPoint = "nvmlShutdown", ExactSpelling = true)] + private static extern NvmlReturn nvmlShutdown(); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex_v2", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetHandleByIndex(int index, out NvmlDevice device); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByPciBusId_v2", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetHandleByPciBusId([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetHandleByIndex", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetHandleByIndexLegacy(int index, out NvmlDevice device); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPowerUsage", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetPowerUsage(NvmlDevice device, out int power); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPcieThroughput", ExactSpelling = true)] + private static extern NvmlReturn nvmlDeviceGetPcieThroughput(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); + + [DllImport(LinuxDllName, EntryPoint = "nvmlDeviceGetPciInfo_v2")] + private static extern NvmlReturn nvmlDeviceGetPciInfo(NvmlDevice device, ref NvmlPciInfo pci); + + private delegate NvmlReturn WindowsNvmlDelegate(); + + private delegate NvmlReturn WindowsNvmlGetHandleDelegate(int index, out NvmlDevice device); + + private delegate NvmlReturn WindowsNvmlGetHandleByPciBusIdDelegate([MarshalAs(UnmanagedType.LPStr)] string pciBusId, out NvmlDevice device); + + private delegate NvmlReturn WindowsNvmlGetPowerUsageDelegate(NvmlDevice device, out int power); + + private delegate NvmlReturn WindowsNvmlDeviceGetPcieThroughputDelegate(NvmlDevice device, NvmlPcieUtilCounter counter, out uint value); + + private delegate NvmlReturn WindowsNvmlDeviceGetPciInfo(NvmlDevice device, ref NvmlPciInfo pci); + + [StructLayout(LayoutKind.Sequential)] + public struct NvmlDevice + { + public IntPtr Handle; + } + + [StructLayout(LayoutKind.Sequential)] + public struct NvmlPciInfo + { + [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] + public string busId; + + public uint domain; + + public uint bus; + + public uint device; + + public ushort pciVendorId; + + public ushort pciDeviceId; + + public uint pciSubSystemId; + + public uint reserved0; + public uint reserved1; + public uint reserved2; + public uint reserved3; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/Ring0.cs b/LibreHardwareMonitorLib/Interop/Ring0.cs index 87ae8bd..1cdafe9 100644 --- a/LibreHardwareMonitorLib/Interop/Ring0.cs +++ b/LibreHardwareMonitorLib/Interop/Ring0.cs @@ -6,24 +6,23 @@ // ReSharper disable InconsistentNaming // ReSharper disable IdentifierTypo -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +/// +/// Driver with access at kernel level. +/// +internal static class Ring0 { - /// - /// Driver with access at kernel level. - /// - internal static class Ring0 - { - public const uint INVALID_PCI_ADDRESS = 0xFFFFFFFF; + public const uint INVALID_PCI_ADDRESS = 0xFFFFFFFF; - private const uint OLS_TYPE = 40000; + private const uint OLS_TYPE = 40000; - public static readonly Kernel32.IOControlCode IOCTL_OLS_GET_REFCOUNT = new(OLS_TYPE, 0x801, Kernel32.IOControlCode.Access.Any); - public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_MSR = new(OLS_TYPE, 0x821, Kernel32.IOControlCode.Access.Any); - public static readonly Kernel32.IOControlCode IOCTL_OLS_WRITE_MSR = new(OLS_TYPE, 0x822, Kernel32.IOControlCode.Access.Any); - public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_IO_PORT_BYTE = new(OLS_TYPE, 0x833, Kernel32.IOControlCode.Access.Read); - public static readonly Kernel32.IOControlCode IOCTL_OLS_WRITE_IO_PORT_BYTE = new(OLS_TYPE, 0x836, Kernel32.IOControlCode.Access.Write); - public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_PCI_CONFIG = new(OLS_TYPE, 0x851, Kernel32.IOControlCode.Access.Read); - public static readonly Kernel32.IOControlCode IOCTL_OLS_WRITE_PCI_CONFIG = new(OLS_TYPE, 0x852, Kernel32.IOControlCode.Access.Write); - public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_MEMORY = new(OLS_TYPE, 0x841, Kernel32.IOControlCode.Access.Read); - } -} + public static readonly Kernel32.IOControlCode IOCTL_OLS_GET_REFCOUNT = new(OLS_TYPE, 0x801, Kernel32.IOControlCode.Access.Any); + public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_MSR = new(OLS_TYPE, 0x821, Kernel32.IOControlCode.Access.Any); + public static readonly Kernel32.IOControlCode IOCTL_OLS_WRITE_MSR = new(OLS_TYPE, 0x822, Kernel32.IOControlCode.Access.Any); + public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_IO_PORT_BYTE = new(OLS_TYPE, 0x833, Kernel32.IOControlCode.Access.Read); + public static readonly Kernel32.IOControlCode IOCTL_OLS_WRITE_IO_PORT_BYTE = new(OLS_TYPE, 0x836, Kernel32.IOControlCode.Access.Write); + public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_PCI_CONFIG = new(OLS_TYPE, 0x851, Kernel32.IOControlCode.Access.Read); + public static readonly Kernel32.IOControlCode IOCTL_OLS_WRITE_PCI_CONFIG = new(OLS_TYPE, 0x852, Kernel32.IOControlCode.Access.Write); + public static readonly Kernel32.IOControlCode IOCTL_OLS_READ_MEMORY = new(OLS_TYPE, 0x841, Kernel32.IOControlCode.Access.Read); +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/SetupApi.cs b/LibreHardwareMonitorLib/Interop/SetupApi.cs index a8e2048..56c4f0c 100644 --- a/LibreHardwareMonitorLib/Interop/SetupApi.cs +++ b/LibreHardwareMonitorLib/Interop/SetupApi.cs @@ -6,53 +6,52 @@ using System; using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +internal class SetupApi { - internal class SetupApi + internal const int DIGCF_DEVICEINTERFACE = 0x00000010; + internal const int DIGCF_PRESENT = 0x00000002; + internal const int ERROR_INSUFFICIENT_BUFFER = 122; + internal const int ERROR_NO_MORE_ITEMS = 259; + + private const string DllName = "SetupAPI.dll"; + internal static Guid GUID_DEVICE_BATTERY = new(0x72631e54, 0x78A4, 0x11d0, 0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a); + internal static readonly IntPtr INVALID_HANDLE_VALUE = new(-1); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + internal static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetupDiEnumDeviceInterfaces + (IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref Guid InterfaceClassGuid, uint MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); + + [DllImport(DllName, SetLastError = true, EntryPoint = "SetupDiGetDeviceInterfaceDetailW", CharSet = CharSet.Unicode)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetupDiGetDeviceInterfaceDetail + ( + IntPtr DeviceInfoSet, + in SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, + [Out, Optional] IntPtr DeviceInterfaceDetailData, + uint DeviceInterfaceDetailDataSize, + out uint RequiredSize, + IntPtr DeviceInfoData = default); + + [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] + [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] + [return: MarshalAs(UnmanagedType.Bool)] + internal static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); + + [StructLayout(LayoutKind.Sequential)] + internal struct SP_DEVICE_INTERFACE_DATA { - internal const int DIGCF_DEVICEINTERFACE = 0x00000010; - internal const int DIGCF_PRESENT = 0x00000002; - internal const int ERROR_INSUFFICIENT_BUFFER = 122; - internal const int ERROR_NO_MORE_ITEMS = 259; - - private const string DllName = "SetupAPI.dll"; - internal static Guid GUID_DEVICE_BATTERY = new(0x72631e54, 0x78A4, 0x11d0, 0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a); - internal static readonly IntPtr INVALID_HANDLE_VALUE = new(-1); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - internal static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetupDiEnumDeviceInterfaces - (IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref Guid InterfaceClassGuid, uint MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData); - - [DllImport(DllName, SetLastError = true, EntryPoint = "SetupDiGetDeviceInterfaceDetailW", CharSet = CharSet.Unicode)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetupDiGetDeviceInterfaceDetail - ( - IntPtr DeviceInfoSet, - in SP_DEVICE_INTERFACE_DATA DeviceInterfaceData, - [Out, Optional] IntPtr DeviceInterfaceDetailData, - uint DeviceInterfaceDetailDataSize, - out uint RequiredSize, - IntPtr DeviceInfoData = default); - - [DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)] - [DefaultDllImportSearchPaths(DllImportSearchPath.System32)] - [return: MarshalAs(UnmanagedType.Bool)] - internal static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet); - - [StructLayout(LayoutKind.Sequential)] - internal struct SP_DEVICE_INTERFACE_DATA - { - public uint cbSize; - public Guid InterfaceClassGuid; - public uint Flags; - public IntPtr Reserved; - } + public uint cbSize; + public Guid InterfaceClassGuid; + public uint Flags; + public IntPtr Reserved; } -} +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Interop/WinNt.cs b/LibreHardwareMonitorLib/Interop/WinNt.cs index 8e78304..642427a 100644 --- a/LibreHardwareMonitorLib/Interop/WinNt.cs +++ b/LibreHardwareMonitorLib/Interop/WinNt.cs @@ -8,39 +8,38 @@ using System.Runtime.InteropServices; -namespace LibreHardwareMonitor.Interop +namespace LibreHardwareMonitor.Interop; + +/// +/// Contains Win32 definitions for Windows NT. +/// +internal static class WinNt { + internal const int STATUS_SUCCESS = 0; + /// - /// Contains Win32 definitions for Windows NT. + /// Describes a local identifier for an adapter. /// - internal static class WinNt + [StructLayout(LayoutKind.Sequential)] + internal struct LUID { - internal const int STATUS_SUCCESS = 0; - - /// - /// Describes a local identifier for an adapter. - /// - [StructLayout(LayoutKind.Sequential)] - internal struct LUID - { - public readonly uint LowPart; - public readonly int HighPart; - } - - /// - /// Represents a 64-bit signed integer value. - /// - [StructLayout(LayoutKind.Explicit, Size = 8)] - internal struct LARGE_INTEGER - { - [FieldOffset(0)] - public long QuadPart; - - [FieldOffset(0)] - public uint LowPart; - - [FieldOffset(4)] - public int HighPart; - } + public readonly uint LowPart; + public readonly int HighPart; } -} + + /// + /// Represents a 64-bit signed integer value. + /// + [StructLayout(LayoutKind.Explicit, Size = 8)] + internal struct LARGE_INTEGER + { + [FieldOffset(0)] + public long QuadPart; + + [FieldOffset(0)] + public uint LowPart; + + [FieldOffset(4)] + public int HighPart; + } +} \ No newline at end of file diff --git a/LibreHardwareMonitorLib/Software/OperatingSystem.cs b/LibreHardwareMonitorLib/Software/OperatingSystem.cs index 5b91135..d1ec00c 100644 --- a/LibreHardwareMonitorLib/Software/OperatingSystem.cs +++ b/LibreHardwareMonitorLib/Software/OperatingSystem.cs @@ -6,34 +6,33 @@ using System; -namespace LibreHardwareMonitor.Software +namespace LibreHardwareMonitor.Software; + +/// +/// Contains basic information about the operating system. +/// +public static class OperatingSystem { /// - /// Contains basic information about the operating system. + /// Statically checks if the current system and . /// - public static class OperatingSystem + static OperatingSystem() { - /// - /// Statically checks if the current system and . - /// - static OperatingSystem() - { - // The operating system doesn't change during execution so let's query it just one time. - PlatformID platform = Environment.OSVersion.Platform; - IsUnix = platform is PlatformID.Unix or PlatformID.MacOSX; + // The operating system doesn't change during execution so let's query it just one time. + PlatformID platform = Environment.OSVersion.Platform; + IsUnix = platform is PlatformID.Unix or PlatformID.MacOSX; - if (Environment.Is64BitOperatingSystem) - Is64Bit = true; - } - - /// - /// Gets information about whether the current system is 64 bit. - /// - public static bool Is64Bit { get; } - - /// - /// Gets information about whether the current system is Unix based. - /// - public static bool IsUnix { get; } + if (Environment.Is64BitOperatingSystem) + Is64Bit = true; } -} + + /// + /// Gets information about whether the current system is 64 bit. + /// + public static bool Is64Bit { get; } + + /// + /// Gets information about whether the current system is Unix based. + /// + public static bool IsUnix { get; } +} \ No newline at end of file