* Workaround for page changing on DDR5 systems with SPD Write Protection active has been implemented in new version of RAMSPDToolkit. Code for LHM has been adjusted accordingly. Added more sensors (timings). * Move abbreviation of timings to start of string. * Simplify names for timings. * Update version. * Remove extra padding.
289 lines
9.1 KiB
C#
289 lines
9.1 KiB
C#
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
|
|
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
// Copyright (C) LibreHardwareMonitor and Contributors.
|
|
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
|
|
// All Rights Reserved.
|
|
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Globalization;
|
|
using System.Text;
|
|
using LibreHardwareMonitor.Hardware;
|
|
using LibreHardwareMonitor.Utilities;
|
|
|
|
namespace LibreHardwareMonitor.UI;
|
|
|
|
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)
|
|
{
|
|
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.Timing:
|
|
Format = "{0:F3} ns";
|
|
break;
|
|
case SensorType.Energy:
|
|
Format = "{0:F0} mWh";
|
|
break;
|
|
case SensorType.Noise:
|
|
Format = "{0:F0} dBA";
|
|
break;
|
|
case SensorType.Conductivity:
|
|
Format = "{0:F1} µS/cm";
|
|
break;
|
|
case SensorType.Humidity:
|
|
Format = "{0:F0} %";
|
|
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);
|
|
}
|
|
|
|
public event EventHandler PlotSelectionChanged;
|
|
|
|
public string Format { get; set; } = "";
|
|
|
|
public override bool IsVisible
|
|
{
|
|
get { return base.IsVisible; }
|
|
set
|
|
{
|
|
base.IsVisible = value;
|
|
_settings.SetValue(new Identifier(Sensor.Identifier, "hidden").ToString(), !value);
|
|
}
|
|
}
|
|
|
|
public string Max
|
|
{
|
|
get { return ValueToString(Sensor.Max); }
|
|
}
|
|
|
|
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)
|
|
{
|
|
if (value.HasValue)
|
|
{
|
|
switch (Sensor.SensorType)
|
|
{
|
|
case SensorType.Temperature when _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit:
|
|
{
|
|
return $"{value * 1.8 + 32:F1} °F";
|
|
}
|
|
case SensorType.Throughput:
|
|
{
|
|
string result;
|
|
switch (Sensor.Name)
|
|
{
|
|
case "Connection Speed":
|
|
{
|
|
switch (value)
|
|
{
|
|
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;
|
|
}
|
|
default:
|
|
{
|
|
const int _1MB = 1048576;
|
|
|
|
result = value < _1MB ? $"{value / 1024:F1} KB/s" : $"{value / _1MB:F1} MB/s";
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
case SensorType.TimeSpan:
|
|
{
|
|
return value.HasValue ? string.Format(Format, TimeSpan.FromSeconds(value.Value)) : "-";
|
|
}
|
|
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)
|
|
{
|
|
if (obj == null)
|
|
return false;
|
|
|
|
if (!(obj is SensorNode s))
|
|
return false;
|
|
|
|
|
|
return (Sensor == s.Sensor);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return Sensor.GetHashCode();
|
|
}
|
|
}
|