Hardware/Sensor.cs
author moel.mich
Tue, 17 Jul 2012 16:12:07 +0000
changeset 365 a8a8ff22d959
parent 358 7962499f9cd6
child 376 df64b56ece65
permissions -rw-r--r--
Improved the data compression for storing the recorded sensor values in the config file.
     1 /*
     2  
     3   This Source Code Form is subject to the terms of the Mozilla Public
     4   License, v. 2.0. If a copy of the MPL was not distributed with this
     5   file, You can obtain one at http://mozilla.org/MPL/2.0/.
     6  
     7   Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
     8 	
     9 */
    10 
    11 using System;
    12 using System.Collections.Generic;
    13 using System.Globalization;
    14 using System.IO;
    15 using System.IO.Compression;
    16 using OpenHardwareMonitor.Collections;
    17 
    18 namespace OpenHardwareMonitor.Hardware {
    19 
    20   internal class Sensor : ISensor {
    21 
    22     private readonly string defaultName;
    23     private string name;
    24     private readonly int index;
    25     private readonly bool defaultHidden;
    26     private readonly SensorType sensorType;
    27     private readonly Hardware hardware;
    28     private readonly ReadOnlyArray<IParameter> parameters;
    29     private float? currentValue;
    30     private float? minValue;
    31     private float? maxValue;
    32     private readonly RingCollection<SensorValue> 
    33       values = new RingCollection<SensorValue>();
    34     private readonly ISettings settings;
    35     private IControl control;
    36     
    37     private float sum;
    38     private int count;
    39    
    40     public Sensor(string name, int index, SensorType sensorType,
    41       Hardware hardware, ISettings settings) : 
    42       this(name, index, sensorType, hardware, null, settings) { }
    43 
    44     public Sensor(string name, int index, SensorType sensorType,
    45       Hardware hardware, ParameterDescription[] parameterDescriptions, 
    46       ISettings settings) :
    47       this(name, index, false, sensorType, hardware,
    48         parameterDescriptions, settings) { }
    49 
    50     public Sensor(string name, int index, bool defaultHidden, 
    51       SensorType sensorType, Hardware hardware, 
    52       ParameterDescription[] parameterDescriptions, ISettings settings) 
    53     {           
    54       this.index = index;
    55       this.defaultHidden = defaultHidden;
    56       this.sensorType = sensorType;
    57       this.hardware = hardware;
    58       Parameter[] parameters = new Parameter[parameterDescriptions == null ?
    59         0 : parameterDescriptions.Length];
    60       for (int i = 0; i < parameters.Length; i++ ) 
    61         parameters[i] = new Parameter(parameterDescriptions[i], this, settings);
    62       this.parameters = parameters;
    63 
    64       this.settings = settings;
    65       this.defaultName = name; 
    66       this.name = settings.GetValue(
    67         new Identifier(Identifier, "name").ToString(), name);
    68 
    69       GetSensorValuesFromSettings();      
    70 
    71       hardware.Closing += delegate(IHardware h) {
    72         SetSensorValuesToSettings();
    73       };
    74     }
    75 
    76     private void SetSensorValuesToSettings() {
    77       using (MemoryStream m = new MemoryStream()) {
    78         using (GZipStream c = new GZipStream(m, CompressionMode.Compress))
    79         using (BufferedStream b = new BufferedStream(c, 65536))
    80         using (BinaryWriter writer = new BinaryWriter(b)) {
    81           long t = 0;
    82           foreach (SensorValue sensorValue in values) {
    83             long v = sensorValue.Time.ToBinary();
    84             writer.Write(v - t);
    85             t = v;
    86             writer.Write(sensorValue.Value);
    87           }
    88           writer.Flush();
    89         }
    90         settings.SetValue(new Identifier(Identifier, "values").ToString(),
    91           Convert.ToBase64String(m.ToArray()));
    92       }
    93     }
    94 
    95     private void GetSensorValuesFromSettings() {
    96       string name = new Identifier(Identifier, "values").ToString();
    97       string s = settings.GetValue(name, null);
    98 
    99       try {
   100         byte[] array = Convert.FromBase64String(s);
   101         s = null;
   102         using (MemoryStream m = new MemoryStream(array))
   103         using (GZipStream c = new GZipStream(m, CompressionMode.Decompress))
   104         using (BinaryReader reader = new BinaryReader(c)) {
   105           try {
   106             long t = 0;
   107             while (true) {
   108               t += reader.ReadInt64();
   109               DateTime time = DateTime.FromBinary(t);              
   110               float value = reader.ReadSingle();
   111               AppendValue(value, time);
   112             }
   113           } catch (EndOfStreamException) { }
   114         }
   115       } catch { }
   116       if (values.Count > 0)
   117         AppendValue(float.NaN, DateTime.UtcNow);
   118 
   119       // remove the value string from the settings to reduce memory usage
   120       settings.Remove(name);
   121     }
   122 
   123     private void AppendValue(float value, DateTime time) {
   124       if (values.Count >= 2 && values.Last.Value == value && 
   125         values[values.Count - 2].Value == value) {
   126         values.Last = new SensorValue(value, time);
   127         return;
   128       } 
   129 
   130       values.Append(new SensorValue(value, time));
   131     }
   132 
   133     public IHardware Hardware {
   134       get { return hardware; }
   135     }
   136 
   137     public SensorType SensorType {
   138       get { return sensorType; }
   139     }
   140 
   141     public Identifier Identifier {
   142       get {
   143         return new Identifier(hardware.Identifier,
   144           sensorType.ToString().ToLowerInvariant(),
   145           index.ToString(CultureInfo.InvariantCulture));
   146       }
   147     }
   148 
   149     public string Name {
   150       get { 
   151         return name; 
   152       }
   153       set {
   154         if (!string.IsNullOrEmpty(value)) 
   155           name = value;          
   156         else 
   157           name = defaultName;
   158         settings.SetValue(new Identifier(Identifier, "name").ToString(), name);
   159       }
   160     }
   161 
   162     public int Index {
   163       get { return index; }
   164     }
   165 
   166     public bool IsDefaultHidden {
   167       get { return defaultHidden; }
   168     }
   169 
   170     public IReadOnlyArray<IParameter> Parameters {
   171       get { return parameters; }
   172     }
   173 
   174     public float? Value {
   175       get { 
   176         return currentValue; 
   177       }
   178       set {
   179         DateTime now = DateTime.UtcNow;
   180         while (values.Count > 0 && (now - values.First.Time).TotalDays > 1)
   181           values.Remove();
   182 
   183         if (value.HasValue) {
   184           sum += value.Value;
   185           count++;
   186           if (count == 4) {
   187             AppendValue(sum / count, now);
   188             sum = 0;
   189             count = 0;
   190           }
   191         }
   192 
   193         this.currentValue = value;
   194         if (minValue > value || !minValue.HasValue)
   195           minValue = value;
   196         if (maxValue < value || !maxValue.HasValue)
   197           maxValue = value;
   198       }
   199     }
   200 
   201     public float? Min { get { return minValue; } }
   202     public float? Max { get { return maxValue; } }
   203 
   204     public void ResetMin() {
   205       minValue = null;
   206     }
   207 
   208     public void ResetMax() {
   209       maxValue = null;
   210     }
   211 
   212     public IEnumerable<SensorValue> Values {
   213       get { return values; }
   214     }    
   215 
   216     public void Accept(IVisitor visitor) {
   217       if (visitor == null)
   218         throw new ArgumentNullException("visitor");
   219       visitor.VisitSensor(this);
   220     }
   221 
   222     public void Traverse(IVisitor visitor) {
   223       foreach (IParameter parameter in parameters)
   224         parameter.Accept(visitor);
   225     }
   226 
   227     public IControl Control {
   228       get {
   229         return control;
   230       }
   231       internal set {
   232         this.control = value;
   233       }
   234     }
   235   }
   236 }