From 330e93ea648bfa79e441ab19b55e0fb2da0e70ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20M=C3=B6ller?= Date: Sun, 19 Jun 2011 12:41:18 +0000 Subject: [PATCH] Added support for saving and restoring the sensor history for the last 24h. The sensor history is now saved in a reduced format (duplicate values are removed, gaps are marked with a NAN sensor value. --- Collections/RingCollection.cs | 235 ++++++++++++++++++++++++++++++ GUI/MainForm.cs | 5 +- GUI/PlotPanel.cs | 37 +++-- GUI/UserRadioGroup.cs | 2 +- Hardware/ATI/ATIGPU.cs | 3 +- Hardware/CPU/AMD10CPU.cs | 3 +- Hardware/CPU/GenericCPU.cs | 4 - Hardware/HDD/HDD.cs | 3 +- Hardware/Hardware.cs | 7 + Hardware/Heatmaster/Heatmaster.cs | 3 +- Hardware/IHardware.cs | 2 +- Hardware/Mainboard/Mainboard.cs | 6 +- Hardware/Nvidia/NvidiaGroup.cs | 9 +- Hardware/Sensor.cs | 79 ++++++++-- Hardware/TBalancer/TBalancer.cs | 3 +- OpenHardwareMonitorLib.csproj | 1 + 16 files changed, 356 insertions(+), 46 deletions(-) create mode 100644 Collections/RingCollection.cs diff --git a/Collections/RingCollection.cs b/Collections/RingCollection.cs new file mode 100644 index 0000000..be480a9 --- /dev/null +++ b/Collections/RingCollection.cs @@ -0,0 +1,235 @@ +/* + + Version: MPL 1.1/GPL 2.0/LGPL 2.1 + + The contents of this file are subject to the Mozilla Public License Version + 1.1 (the "License"); you may not use this file except in compliance with + the License. You may obtain a copy of the License at + + http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS IS" basis, + WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + for the specific language governing rights and limitations under the License. + + The Original Code is the Open Hardware Monitor code. + + The Initial Developer of the Original Code is + Michael Möller . + Portions created by the Initial Developer are Copyright (C) 2011 + the Initial Developer. All Rights Reserved. + + Contributor(s): + + Alternatively, the contents of this file may be used under the terms of + either the GNU General Public License Version 2 or later (the "GPL"), or + the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + in which case the provisions of the GPL or the LGPL are applicable instead + of those above. If you wish to allow use of your version of this file only + under the terms of either the GPL or the LGPL, and not to allow others to + use your version of this file under the terms of the MPL, indicate your + decision by deleting the provisions above and replace them with the notice + and other provisions required by the GPL or the LGPL. If you do not delete + the provisions above, a recipient may use your version of this file under + the terms of any one of the MPL, the GPL or the LGPL. + +*/ + +using System; +using System.Collections; +using System.Collections.Generic; + +namespace OpenHardwareMonitor.Collections { + public class RingCollection : IEnumerable { + + private T[] array; + + // first item of collection + private int head; + + // index after the last item of the collection + private int tail; + + // number of items in the collection + private int size; + + public RingCollection() : this(0) { } + + public RingCollection(int capacity) { + if (capacity < 0) + throw new ArgumentOutOfRangeException("capacity"); + this.array = new T[capacity]; + this.head = 0; + this.tail = 0; + this.size = 0; + } + + public int Capacity { + get { + return array.Length; + } + set { + T[] newArray = new T[value]; + if (size > 0) { + if (head < tail) { + Array.Copy(array, head, newArray, 0, size); + } else { + Array.Copy(array, head, newArray, 0, array.Length - head); + Array.Copy(array, 0, newArray, array.Length - head, tail); + } + } + this.array = newArray; + this.head = 0; + this.tail = size == value ? 0 : size; + } + } + + public void Clear() { + + // remove potential references + if (head < tail) { + Array.Clear(array, head, size); + } else { + Array.Clear(array, 0, tail); + Array.Clear(array, head, array.Length - head); + } + + this.head = 0; + this.tail = 0; + this.size = 0; + } + + public void Append(T item) { + if (size == array.Length) { + int newCapacity = array.Length * 3 / 2; + if (newCapacity < array.Length + 8) + newCapacity = array.Length + 8; + Capacity = newCapacity; + } + + array[tail] = item; + tail = tail + 1 == array.Length ? 0 : tail + 1; + size++; + } + + public T Remove() { + if (size == 0) + throw new InvalidOperationException(); + + T result = array[head]; + array[head] = default(T); + head = head + 1 == array.Length ? 0 : head + 1; + size--; + + return result; + } + + public int Count { + get { + return size; + } + } + + public T this[int index] { + get { + if (index < 0 || index >= size) + throw new IndexOutOfRangeException(); + int i = head + index; + if (i >= array.Length) + i -= array.Length; + return array[i]; + } + set { + if (index < 0 || index >= size) + throw new IndexOutOfRangeException(); + int i = head + index; + if (i >= array.Length) + i -= array.Length; + array[i] = value; + } + } + + public T First { + get { + if (size == 0) + throw new InvalidOperationException(); + return array[head]; + } + set { + if (size == 0) + throw new InvalidOperationException(); + array[head] = value; + } + } + + public T Last { + get { + if (size == 0) + throw new InvalidOperationException(); + return array[tail == 0 ? array.Length - 1 : tail - 1]; + } + set { + if (size == 0) + throw new InvalidOperationException(); + array[tail == 0 ? array.Length - 1 : tail - 1] = value; + } + } + + IEnumerator IEnumerable.GetEnumerator() { + return new RingCollection.Enumerator(this); + } + + IEnumerator IEnumerable.GetEnumerator() { + return new RingCollection.Enumerator(this); + } + + private struct Enumerator : IEnumerator, IEnumerator { + + private RingCollection collection; + private int index; + + public Enumerator(RingCollection collection) { + this.collection = collection; + this.index = -1; + } + + public void Dispose() { + this.index = -2; + } + + public void Reset() { + this.index = -1; + } + + public T Current { + get { + if (index < 0) + throw new InvalidOperationException(); + return collection[index]; + } + } + + object IEnumerator.Current { + get { + if (index < 0) + throw new InvalidOperationException(); + return collection[index]; + } + } + + public bool MoveNext() { + if (index == -2) + return false; + + index++; + + if (index == collection.size) { + index = -2; + return false; + } + + return true; + } + } + } +} diff --git a/GUI/MainForm.cs b/GUI/MainForm.cs index 9a62f82..8c32bcf 100644 --- a/GUI/MainForm.cs +++ b/GUI/MainForm.cs @@ -501,12 +501,11 @@ namespace OpenHardwareMonitor.GUI { } private void MainForm_FormClosed(object sender, FormClosedEventArgs e) { - Visible = false; - SaveConfiguration(); - + Visible = false; systemTray.IsMainIconEnabled = false; timer.Enabled = false; computer.Close(); + SaveConfiguration(); systemTray.Dispose(); } diff --git a/GUI/PlotPanel.cs b/GUI/PlotPanel.cs index d8b49bc..a6f37c9 100644 --- a/GUI/PlotPanel.cs +++ b/GUI/PlotPanel.cs @@ -16,7 +16,7 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 2009-2010 + Portions created by the Initial Developer are Copyright (C) 2009-2011 the Initial Developer. All Rights Reserved. Contributor(s): @@ -88,10 +88,12 @@ namespace OpenHardwareMonitor.GUI { foreach (ISensor sensor in temperatures) { IEnumerable values = sensor.Values; foreach (SensorValue value in values) { - if (!minTempNullable.HasValue || minTempNullable > value.Value) - minTempNullable = value.Value; - if (!maxTempNullable.HasValue || maxTempNullable < value.Value) - maxTempNullable = value.Value; + if (!float.IsNaN(value.Value)) { + if (!minTempNullable.HasValue || minTempNullable > value.Value) + minTempNullable = value.Value; + if (!maxTempNullable.HasValue || maxTempNullable < value.Value) + maxTempNullable = value.Value; + } } } if (!minTempNullable.HasValue) { @@ -140,6 +142,10 @@ namespace OpenHardwareMonitor.GUI { deltaTime += 2; while (deltaTime + 5 < maxTime && deltaTime < 100) deltaTime += 5; + while (deltaTime + 50 < maxTime && deltaTime < 1000) + deltaTime += 50; + while (deltaTime + 100 < maxTime && deltaTime < 10000) + deltaTime += 100; List grid = new List(countTime + 1); for (int i = 0; i <= countTime; i++) { @@ -149,7 +155,6 @@ namespace OpenHardwareMonitor.GUI { } protected override void OnPaint(PaintEventArgs e) { - now = DateTime.Now - new TimeSpan(0, 0, 4); List timeGrid = GetTimeGrid(); @@ -196,14 +201,18 @@ namespace OpenHardwareMonitor.GUI { IEnumerable values = sensor.Values; PointF last = new PointF(); bool first = true; - foreach (SensorValue value in values) { - PointF point = new PointF( - x0 + w - w * (float)(now - value.Time).TotalMinutes / deltaTime, - y0 + h - h * (value.Value - tempGrid[0]) / deltaTemp); - if (!first) - g.DrawLine(pen, last, point); - last = point; - first = false; + foreach (SensorValue v in values) { + if (!float.IsNaN(v.Value)) { + PointF point = new PointF( + x0 + w - w * (float)(now - v.Time).TotalMinutes / deltaTime, + y0 + h - h * (v.Value - tempGrid[0]) / deltaTemp); + if (!first) + g.DrawLine(pen, last, point); + last = point; + first = false; + } else { + first = true; + } } } } diff --git a/GUI/UserRadioGroup.cs b/GUI/UserRadioGroup.cs index 8ec9245..086ee7b 100644 --- a/GUI/UserRadioGroup.cs +++ b/GUI/UserRadioGroup.cs @@ -16,7 +16,7 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 20011 + Portions created by the Initial Developer are Copyright (C) 2011 the Initial Developer. All Rights Reserved. Contributor(s): diff --git a/Hardware/ATI/ATIGPU.cs b/Hardware/ATI/ATIGPU.cs index 5a2154f..a1977cb 100644 --- a/Hardware/ATI/ATIGPU.cs +++ b/Hardware/ATI/ATIGPU.cs @@ -208,12 +208,13 @@ namespace OpenHardwareMonitor.Hardware.ATI { } } - public void Close() { + public override void Close() { this.fanControl.ControlModeChanged -= ControlModeChanged; this.fanControl.SoftwareControlValueChanged -= SoftwareControlValueChanged; RestoreDefaultFanSpeed(); + base.Close(); } } } diff --git a/Hardware/CPU/AMD10CPU.cs b/Hardware/CPU/AMD10CPU.cs index 2760fbd..f45fe6c 100644 --- a/Hardware/CPU/AMD10CPU.cs +++ b/Hardware/CPU/AMD10CPU.cs @@ -348,10 +348,11 @@ namespace OpenHardwareMonitor.Hardware.CPU { } } - public override void Close() { + public override void Close() { if (temperatureStream != null) { temperatureStream.Close(); } + base.Close(); } } } diff --git a/Hardware/CPU/GenericCPU.cs b/Hardware/CPU/GenericCPU.cs index 65e7617..280d893 100644 --- a/Hardware/CPU/GenericCPU.cs +++ b/Hardware/CPU/GenericCPU.cs @@ -333,9 +333,5 @@ namespace OpenHardwareMonitor.Hardware.CPU { totalLoad.Value = cpuLoad.GetTotalLoad(); } } - - public virtual void Close() { - - } } } diff --git a/Hardware/HDD/HDD.cs b/Hardware/HDD/HDD.cs index 1d6f728..7e53e4f 100644 --- a/Hardware/HDD/HDD.cs +++ b/Hardware/HDD/HDD.cs @@ -123,8 +123,9 @@ namespace OpenHardwareMonitor.Hardware.HDD { count++; count %= UPDATE_DIVIDER; } - public void Close() { + public override void Close() { SMART.CloseHandle(handle); + base.Close(); } public override void Traverse(IVisitor visitor) { diff --git a/Hardware/Hardware.cs b/Hardware/Hardware.cs index 38bc296..a4db74b 100644 --- a/Hardware/Hardware.cs +++ b/Hardware/Hardware.cs @@ -113,6 +113,13 @@ namespace OpenHardwareMonitor.Hardware { public abstract void Update(); + public event HardwareEventHandler Closing; + + public virtual void Close() { + if (Closing != null) + Closing(this); + } + public void Accept(IVisitor visitor) { if (visitor == null) throw new ArgumentNullException("visitor"); diff --git a/Hardware/Heatmaster/Heatmaster.cs b/Hardware/Heatmaster/Heatmaster.cs index cc0aa14..65be904 100644 --- a/Hardware/Heatmaster/Heatmaster.cs +++ b/Hardware/Heatmaster/Heatmaster.cs @@ -285,10 +285,11 @@ namespace OpenHardwareMonitor.Hardware.Heatmaster { return r.ToString(); } - public void Close() { + public override void Close() { serialPort.Close(); serialPort.Dispose(); serialPort = null; + base.Close(); } public void Dispose() { diff --git a/Hardware/IHardware.cs b/Hardware/IHardware.cs index d4a361f..29ef442 100644 --- a/Hardware/IHardware.cs +++ b/Hardware/IHardware.cs @@ -38,7 +38,7 @@ namespace OpenHardwareMonitor.Hardware { public delegate void SensorEventHandler(ISensor sensor); - + public enum HardwareType { Mainboard, SuperIO, diff --git a/Hardware/Mainboard/Mainboard.cs b/Hardware/Mainboard/Mainboard.cs index 5aad387..2152283 100644 --- a/Hardware/Mainboard/Mainboard.cs +++ b/Hardware/Mainboard/Mainboard.cs @@ -47,7 +47,7 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { private readonly ISettings settings; private readonly LPCIO lpcio; private readonly LMSensors lmSensors; - private readonly IHardware[] superIOHardware; + private readonly Hardware[] superIOHardware; public Mainboard(ISettings settings) { this.settings = settings; @@ -80,7 +80,7 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { superIO = lpcio.SuperIO; } - superIOHardware = new IHardware[superIO.Length]; + superIOHardware = new Hardware[superIO.Length]; for (int i = 0; i < superIO.Length; i++) superIOHardware[i] = new SuperIOHardware(this, superIO[i], smbios.Board != null ? smbios.Board.Manufacturer : @@ -132,6 +132,8 @@ namespace OpenHardwareMonitor.Hardware.Mainboard { public void Close() { if (lmSensors != null) lmSensors.Close(); + foreach (Hardware hardware in superIOHardware) + hardware.Close(); } public IHardware[] SubHardware { diff --git a/Hardware/Nvidia/NvidiaGroup.cs b/Hardware/Nvidia/NvidiaGroup.cs index 6c8317f..d70a813 100644 --- a/Hardware/Nvidia/NvidiaGroup.cs +++ b/Hardware/Nvidia/NvidiaGroup.cs @@ -16,7 +16,7 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 2009-2010 + Portions created by the Initial Developer are Copyright (C) 2009-2011 the Initial Developer. All Rights Reserved. Contributor(s): @@ -43,7 +43,7 @@ namespace OpenHardwareMonitor.Hardware.Nvidia { internal class NvidiaGroup : IGroup { - private readonly List hardware = new List(); + private readonly List hardware = new List(); private readonly StringBuilder report = new StringBuilder(); public NvidiaGroup(ISettings settings) { @@ -125,6 +125,9 @@ namespace OpenHardwareMonitor.Hardware.Nvidia { return report.ToString(); } - public void Close() { } + public void Close() { + foreach (Hardware gpu in hardware) + gpu.Close(); + } } } diff --git a/Hardware/Sensor.cs b/Hardware/Sensor.cs index b54f477..9c8e175 100644 --- a/Hardware/Sensor.cs +++ b/Hardware/Sensor.cs @@ -16,7 +16,7 @@ The Initial Developer of the Original Code is Michael Möller . - Portions created by the Initial Developer are Copyright (C) 2009-2010 + Portions created by the Initial Developer are Copyright (C) 2009-2011 the Initial Developer. All Rights Reserved. Contributor(s): @@ -38,6 +38,8 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; +using System.IO.Compression; using OpenHardwareMonitor.Collections; namespace OpenHardwareMonitor.Hardware { @@ -49,33 +51,31 @@ namespace OpenHardwareMonitor.Hardware { private readonly int index; private readonly bool defaultHidden; private readonly SensorType sensorType; - private readonly IHardware hardware; + private readonly Hardware hardware; private readonly ReadOnlyArray parameters; private float? currentValue; private float? minValue; private float? maxValue; - private readonly Queue values = - new Queue(MAX_MINUTES * 15); + private readonly RingCollection + values = new RingCollection(); private readonly ISettings settings; private IControl control; private float sum; private int count; - - private const int MAX_MINUTES = 120; public Sensor(string name, int index, SensorType sensorType, - IHardware hardware, ISettings settings) : + Hardware hardware, ISettings settings) : this(name, index, sensorType, hardware, null, settings) { } public Sensor(string name, int index, SensorType sensorType, - IHardware hardware, ParameterDescription[] parameterDescriptions, + Hardware hardware, ParameterDescription[] parameterDescriptions, ISettings settings) : this(name, index, false, sensorType, hardware, parameterDescriptions, settings) { } public Sensor(string name, int index, bool defaultHidden, - SensorType sensorType, IHardware hardware, + SensorType sensorType, Hardware hardware, ParameterDescription[] parameterDescriptions, ISettings settings) { this.index = index; @@ -92,6 +92,59 @@ namespace OpenHardwareMonitor.Hardware { this.defaultName = name; this.name = settings.GetValue( new Identifier(Identifier, "name").ToString(), name); + + GetSensorValuesFromSettings(); + + hardware.Closing += delegate(IHardware h) { + SetSensorValuesToSettings(); + }; + } + + private void SetSensorValuesToSettings() { + using (MemoryStream m = new MemoryStream()) { + using (GZipStream c = new GZipStream(m, CompressionMode.Compress)) + using (BinaryWriter writer = new BinaryWriter(c)) { + foreach (SensorValue sensorValue in values) { + writer.Write(sensorValue.Time.ToBinary()); + writer.Write(sensorValue.Value); + } + } + settings.SetValue(new Identifier(Identifier, "values").ToString(), + Convert.ToBase64String(m.ToArray())); + } + } + + private void GetSensorValuesFromSettings() { + string s = settings.GetValue( + new Identifier(Identifier, "values").ToString(), null); + + byte[] array = null; + try { + array = Convert.FromBase64String(s); + using (MemoryStream m = new MemoryStream(array)) + using (GZipStream c = new GZipStream(m, CompressionMode.Decompress)) + using (BinaryReader reader = new BinaryReader(c)) { + try { + while (true) { + DateTime time = DateTime.FromBinary(reader.ReadInt64()); + float value = reader.ReadSingle(); + AppendValue(value, time); + } + } catch (EndOfStreamException) { } + } + } catch { } + if (values.Count > 0) + AppendValue(float.NaN, DateTime.Now); + } + + private void AppendValue(float value, DateTime time) { + if (values.Count >= 2 && values.Last.Value == value && + values[values.Count - 2].Value == value) { + values.Last = new SensorValue(value, time); + return; + } + + values.Append(new SensorValue(value, time)); } public IHardware Hardware { @@ -140,15 +193,15 @@ namespace OpenHardwareMonitor.Hardware { return currentValue; } set { - while (values.Count > 0 && - (DateTime.Now - values.Peek().Time).TotalMinutes > MAX_MINUTES) - values.Dequeue(); + DateTime now = DateTime.Now; + while (values.Count > 0 && (now - values.First.Time).TotalDays > 1) + values.Remove(); if (value.HasValue) { sum += value.Value; count++; if (count == 4) { - values.Enqueue(new SensorValue(sum / count, DateTime.Now)); + AppendValue(sum / count, now); sum = 0; count = 0; } diff --git a/Hardware/TBalancer/TBalancer.cs b/Hardware/TBalancer/TBalancer.cs index 88b5901..c112821 100644 --- a/Hardware/TBalancer/TBalancer.cs +++ b/Hardware/TBalancer/TBalancer.cs @@ -340,8 +340,9 @@ namespace OpenHardwareMonitor.Hardware.TBalancer { alternativeRequest.BeginInvoke(null, null); } - public void Close() { + public override void Close() { FTD2XX.FT_Close(handle); + base.Close(); } } diff --git a/OpenHardwareMonitorLib.csproj b/OpenHardwareMonitorLib.csproj index a1976e4..237476c 100644 --- a/OpenHardwareMonitorLib.csproj +++ b/OpenHardwareMonitorLib.csproj @@ -56,6 +56,7 @@ +