diff --git a/GUI/HardwareTypeImage.cs b/GUI/HardwareTypeImage.cs index 057353a..056b81a 100644 --- a/GUI/HardwareTypeImage.cs +++ b/GUI/HardwareTypeImage.cs @@ -59,6 +59,9 @@ namespace OpenHardwareMonitor.GUI { case HardwareType.RAM: image = Utilities.EmbeddedResources.GetImage("ram.png"); break; + case HardwareType.Aquacomputer: + image = Utilities.EmbeddedResources.GetImage("acicon.png"); + break; default: image = new Bitmap(1, 1); break; diff --git a/GUI/PlotPanel.cs b/GUI/PlotPanel.cs index c7cbbb3..49054be 100644 --- a/GUI/PlotPanel.cs +++ b/GUI/PlotPanel.cs @@ -150,6 +150,7 @@ namespace OpenHardwareMonitor.GUI { units.Add(SensorType.Factor, "1"); units.Add(SensorType.Power, "W"); units.Add(SensorType.Data, "GB"); + units.Add(SensorType.Frequency, "Hz"); foreach (SensorType type in Enum.GetValues(typeof(SensorType))) { var axis = new LinearAxis(); diff --git a/GUI/SensorGadget.cs b/GUI/SensorGadget.cs index e773864..c0d8833 100644 --- a/GUI/SensorGadget.cs +++ b/GUI/SensorGadget.cs @@ -558,6 +558,9 @@ namespace OpenHardwareMonitor.GUI { case SensorType.Clock: format = "{0:F0} MHz"; break; + case SensorType.Frequency: + format = "{0:F0} Hz"; + break; case SensorType.Temperature: format = "{0:F1} °C"; break; diff --git a/GUI/SensorNode.cs b/GUI/SensorNode.cs index 7038329..655dfa5 100644 --- a/GUI/SensorNode.cs +++ b/GUI/SensorNode.cs @@ -54,6 +54,7 @@ namespace OpenHardwareMonitor.GUI { 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; } bool hidden = settings.GetValue(new Identifier(sensor.Identifier, diff --git a/GUI/TypeNode.cs b/GUI/TypeNode.cs index b57d58b..0fc5110 100644 --- a/GUI/TypeNode.cs +++ b/GUI/TypeNode.cs @@ -69,6 +69,10 @@ namespace OpenHardwareMonitor.GUI { this.Image = Utilities.EmbeddedResources.GetImage("factor.png"); this.Text = "Factors"; break; + case SensorType.Frequency: + this.Image = Utilities.EmbeddedResources.GetImage("clock.png"); + this.Text = "Frequencys"; + break; } NodeAdded += new NodeEventHandler(TypeNode_NodeAdded); diff --git a/Hardware/Aquacomputer/AquacomputerGroup.cs b/Hardware/Aquacomputer/AquacomputerGroup.cs new file mode 100644 index 0000000..0a2581e --- /dev/null +++ b/Hardware/Aquacomputer/AquacomputerGroup.cs @@ -0,0 +1,68 @@ +using HidLibrary; +using System; +using System.Collections.Generic; +using System.Text; + +namespace OpenHardwareMonitor.Hardware.Aquacomputer +{ + public class AquacomputerGroup : IGroup + { + private readonly List _hardware = new List(); + private readonly StringBuilder _report = new StringBuilder(); + + public AquacomputerGroup(ISettings settings) + { + _report.AppendLine($"Aquacomputer Hardware"); + _report.AppendLine(); + + foreach (HidDevice dev in HidDevices.Enumerate(0x0c70)) + { + byte[] productNameBytes; + dev.ReadProduct(out productNameBytes); + string ProductName = UnicodeEncoding.Unicode.GetString(productNameBytes).Replace("\0", string.Empty); + ProductName = ProductName.Substring(0,1).ToUpper() + ProductName.Substring(1); + + switch (dev.Attributes.ProductId) + { + case 0xf0b6: + { + var device = new AquastreamXT(dev, settings); + _report.AppendLine($"Device name: {ProductName}"); + _report.AppendLine($"Device variant: {device.Variant}"); + _report.AppendLine($"Firmware version: {device.FirmwareVersion}"); + _report.AppendLine($"{device.Status}"); + _report.AppendLine(); + _hardware.Add(device); + break; + } + default: + { + _report.AppendLine($"Unknown Hardware PID: {dev.Attributes.ProductHexId} Name: {ProductName}"); + _report.AppendLine(); + break; + } + } + } + if (_hardware.Count == 0) + { + _report.AppendLine("No Aquacomputer Hardware found."); + _report.AppendLine(); + } + } + + public IHardware[] Hardware => _hardware.ToArray(); + + public void Close() + { + foreach (Hardware h in _hardware) + { + h.Close(); + } + } + + public string GetReport() + { + return _report.ToString(); + } + } +} diff --git a/Hardware/Aquacomputer/AquastreamXT.cs b/Hardware/Aquacomputer/AquastreamXT.cs new file mode 100644 index 0000000..1648062 --- /dev/null +++ b/Hardware/Aquacomputer/AquastreamXT.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Text; +using HidLibrary; + +namespace OpenHardwareMonitor.Hardware.Aquacomputer +{ + /* + * TODO: + * Check tested and fix unknown variables in Update() + * Check if property "Variant" is valid interpreted + * Implement Fan Control in SetControl() + */ + internal class AquastreamXT : Hardware + { + [Flags] + enum PumpAlarms : byte + { + ALARM_SENSOR1 = 1, + ALARM_SENSOR2 = 2, + ALARM_PUMP = 4, + ALARM_FAN = 8, + ALARM_FLOW = 16, + ALARM_FAN_SHORT = 32, + ALARM_FAN_TEMP90 = 64, + ALARM_FAN_TEMP70 = 128 + } + + [Flags] + enum PumpMode : byte + { + MODE_PUMP_ADV = 1, + MODE_FAN_AMP = 2, + MODE_FAN_CONTROLLER = 4 + } + + #region USB + private HidDevice device; + private byte[] rawData; + public UInt16 FirmwareVersion { get; private set; } + #endregion + + private readonly Sensor _fanControl, _pumpPower, _pumpFlow; + private readonly Sensor[] _rpmSensors = new Sensor[2]; + private readonly Sensor[] _temperatures = new Sensor[3]; + private readonly Sensor[] _voltages = new Sensor[2]; + private readonly Sensor[] _frequencies = new Sensor[2]; + + public AquastreamXT(HidDevice dev, ISettings settings) : base("Aquastream XT", new Identifier(dev.DevicePath), settings) + { + device = dev; + + do + { + device.ReadFeatureData(out rawData, 0x4); + } while (rawData[0] != 0x4); + + Name = $"Aquastream XT {Variant}"; + FirmwareVersion = BitConverter.ToUInt16(rawData, 50); + + _temperatures[0] = new Sensor("External Fan VRM", 0, SensorType.Temperature, this, new ParameterDescription[0], settings); + ActivateSensor(_temperatures[0]); + _temperatures[1] = new Sensor("External", 1, SensorType.Temperature, this, new ParameterDescription[0], settings); + ActivateSensor(_temperatures[1]); + _temperatures[2] = new Sensor("Internal Water", 2, SensorType.Temperature, this, new ParameterDescription[0], settings); + ActivateSensor(_temperatures[2]); + + _voltages[0] = new Sensor("External Fan", 1, SensorType.Voltage, this, new ParameterDescription[0], settings); + ActivateSensor(_voltages[0]); + _voltages[1] = new Sensor("Pump", 2, SensorType.Voltage, this, new ParameterDescription[0], settings); + ActivateSensor(_voltages[1]); + + _pumpPower = new Sensor("Pump", 0, SensorType.Power, this, new ParameterDescription[0], settings); + ActivateSensor(_pumpPower); + + _pumpFlow = new Sensor("Pump", 0, SensorType.Flow, this, new ParameterDescription[0], settings); + ActivateSensor(_pumpFlow); + + _rpmSensors[0] = new Sensor("External Fan", 0, SensorType.Fan, this, new ParameterDescription[0], settings); + ActivateSensor(_rpmSensors[0]); + _rpmSensors[1] = new Sensor("Pump", 1, SensorType.Fan, this, new ParameterDescription[0], settings); + ActivateSensor(_rpmSensors[1]); + + _fanControl = new Sensor("External Fan", 0, SensorType.Control, this, new ParameterDescription[0], settings); + Control control = new Control(_fanControl, settings, 0, 100); + control.ControlModeChanged += (cc) => { + switch (cc.ControlMode) + { + case ControlMode.Undefined: + return; + case ControlMode.Default: + SetControl(null); + break; + case ControlMode.Software: + SetControl((byte)(cc.SoftwareValue * 2.55)); + break; + default: + return; + } + }; + control.SoftwareControlValueChanged += (cc) => { + if (cc.ControlMode == ControlMode.Software) + SetControl((byte)(cc.SoftwareValue * 2.55)); + }; + + switch (control.ControlMode) + { + case ControlMode.Undefined: + break; + case ControlMode.Default: + SetControl(null); + break; + case ControlMode.Software: + SetControl((byte)(control.SoftwareValue * 2.55)); + break; + default: + break; + } + _fanControl.Control = control; + ActivateSensor(_fanControl); + + _frequencies[0] = new Sensor("Pump Frequency", 0, SensorType.Frequency, this, new ParameterDescription[0], settings); + ActivateSensor(_frequencies[0]); + _frequencies[1] = new Sensor("Pump MaxFrequency", 1, SensorType.Frequency, this, new ParameterDescription[0], settings); + ActivateSensor(_frequencies[1]); + } + + //TODO: Implement Fan Control + private void SetControl(byte? v) + { + throw new NotImplementedException(); + } + + //TODO: Check if valid + public string Variant + { + get + { + PumpMode mode = (PumpMode)rawData[33]; + + if (mode.HasFlag(PumpMode.MODE_PUMP_ADV)) + return "Ultra + Internal Flow Sensor"; + else if (mode.HasFlag(PumpMode.MODE_FAN_CONTROLLER)) + return "Ultra"; + else if (mode.HasFlag(PumpMode.MODE_FAN_AMP)) + return "Advanced"; + else + return "Standard"; + } + } + + public override HardwareType HardwareType + { + get + { + return HardwareType.Aquacomputer; + } + } + + public string Status { + get { + FirmwareVersion = BitConverter.ToUInt16(rawData, 50); + + if (FirmwareVersion < 1008) + { + return $"Status: Untested Firmware Version {FirmwareVersion}! Please consider Updating to Version 1018"; + } + return "Status: OK"; + } + } + + public override void Close() + { + device.CloseDevice(); + base.Close(); + } + + //TODO: Check tested and fix unknown variables + public override void Update() + { + device.ReadFeatureData(out rawData, 0x4); + + 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 + } + } +} diff --git a/Hardware/Computer.cs b/Hardware/Computer.cs index 8a77c90..71b697b 100644 --- a/Hardware/Computer.cs +++ b/Hardware/Computer.cs @@ -101,6 +101,7 @@ namespace OpenHardwareMonitor.Hardware { if (fanControllerEnabled) { Add(new TBalancer.TBalancerGroup(settings)); Add(new Heatmaster.HeatmasterGroup(settings)); + Add(new Aquacomputer.AquacomputerGroup(settings)); } if (hddEnabled) @@ -181,9 +182,11 @@ namespace OpenHardwareMonitor.Hardware { if (value) { Add(new TBalancer.TBalancerGroup(settings)); Add(new Heatmaster.HeatmasterGroup(settings)); + Add(new Aquacomputer.AquacomputerGroup(settings)); } else { RemoveType(); RemoveType(); + RemoveType(); } } fanControllerEnabled = value; diff --git a/Hardware/IHardware.cs b/Hardware/IHardware.cs index a816e04..c9ce79e 100644 --- a/Hardware/IHardware.cs +++ b/Hardware/IHardware.cs @@ -15,6 +15,7 @@ namespace OpenHardwareMonitor.Hardware { public enum HardwareType { Mainboard, SuperIO, + Aquacomputer, CPU, RAM, GpuNvidia, diff --git a/Hardware/ISensor.cs b/Hardware/ISensor.cs index e157949..cf431e8 100644 --- a/Hardware/ISensor.cs +++ b/Hardware/ISensor.cs @@ -19,6 +19,7 @@ namespace OpenHardwareMonitor.Hardware { Clock, // MHz Temperature, // °C Load, // % + Frequency, // Hz Fan, // RPM Flow, // L/h Control, // % diff --git a/OpenHardwareMonitor.csproj b/OpenHardwareMonitor.csproj index e74d263..09fc055 100644 --- a/OpenHardwareMonitor.csproj +++ b/OpenHardwareMonitor.csproj @@ -304,6 +304,9 @@ + + + diff --git a/OpenHardwareMonitorLib.csproj b/OpenHardwareMonitorLib.csproj index 295cb5b..c631360 100644 --- a/OpenHardwareMonitorLib.csproj +++ b/OpenHardwareMonitorLib.csproj @@ -28,6 +28,8 @@ + + @@ -135,6 +137,7 @@ + \ No newline at end of file diff --git a/Resources/acicon.png b/Resources/acicon.png new file mode 100644 index 0000000..26ae763 Binary files /dev/null and b/Resources/acicon.png differ diff --git a/Utilities/HttpServer.cs b/Utilities/HttpServer.cs index f32a968..4192b1e 100644 --- a/Utilities/HttpServer.cs +++ b/Utilities/HttpServer.cs @@ -475,6 +475,8 @@ namespace OpenHardwareMonitor.Utilities { return "bigng.png"; case HardwareType.RAM: return "ram.png"; + case HardwareType.Aquacomputer: + return "acicon.png"; default: return "cpu.png"; }