Hardware/Sensor.cs
author moel.mich
Sat, 31 Dec 2011 17:31:04 +0000
changeset 324 c6ee430d6995
parent 298 96263190189a
child 344 3145aadca3d2
permissions -rw-r--r--
Modified and extended version of the patch v4 by Roland Reinl (see Issue 256). Main differences to the original patch: DeviceIoControl refactorings removed, SmartAttribute is now descriptive only and does not hold any state, report is written as one 80 columns table, sensors are created only for meaningful values and without duplicates (remaining life, temperatures, host writes and reads). Also the current implementation should really preserve all the functionality of the old system. Additionally there is now a simple SMART devices emulation class (DebugSmart) that can be used in place of WindowsSmart for testing with reported data.
moel@1
     1
/*
moel@1
     2
  
moel@1
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@1
     4
moel@1
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@1
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@1
     7
  the License. You may obtain a copy of the License at
moel@1
     8
 
moel@1
     9
  http://www.mozilla.org/MPL/
moel@1
    10
moel@1
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@1
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@1
    13
  for the specific language governing rights and limitations under the License.
moel@1
    14
moel@1
    15
  The Original Code is the Open Hardware Monitor code.
moel@1
    16
moel@1
    17
  The Initial Developer of the Original Code is 
moel@1
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@298
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2011
moel@1
    20
  the Initial Developer. All Rights Reserved.
moel@1
    21
moel@1
    22
  Contributor(s):
moel@1
    23
moel@1
    24
  Alternatively, the contents of this file may be used under the terms of
moel@1
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@1
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@1
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@1
    28
  of those above. If you wish to allow use of your version of this file only
moel@1
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@1
    30
  use your version of this file under the terms of the MPL, indicate your
moel@1
    31
  decision by deleting the provisions above and replace them with the notice
moel@1
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@1
    33
  the provisions above, a recipient may use your version of this file under
moel@1
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@1
    35
 
moel@1
    36
*/
moel@1
    37
moel@1
    38
using System;
moel@1
    39
using System.Collections.Generic;
moel@166
    40
using System.Globalization;
moel@298
    41
using System.IO;
moel@298
    42
using System.IO.Compression;
moel@165
    43
using OpenHardwareMonitor.Collections;
moel@1
    44
moel@1
    45
namespace OpenHardwareMonitor.Hardware {
moel@1
    46
moel@165
    47
  internal class Sensor : ISensor {
moel@1
    48
moel@195
    49
    private readonly string defaultName;
moel@1
    50
    private string name;
moel@195
    51
    private readonly int index;
moel@195
    52
    private readonly bool defaultHidden;
moel@195
    53
    private readonly SensorType sensorType;
moel@298
    54
    private readonly Hardware hardware;
moel@195
    55
    private readonly ReadOnlyArray<IParameter> parameters;
moel@167
    56
    private float? currentValue;
moel@167
    57
    private float? minValue;
moel@167
    58
    private float? maxValue;
moel@298
    59
    private readonly RingCollection<SensorValue> 
moel@298
    60
      values = new RingCollection<SensorValue>();
moel@195
    61
    private readonly ISettings settings;
moel@247
    62
    private IControl control;
moel@1
    63
    
moel@195
    64
    private float sum;
moel@195
    65
    private int count;
moel@28
    66
   
moel@1
    67
    public Sensor(string name, int index, SensorType sensorType,
moel@298
    68
      Hardware hardware, ISettings settings) : 
moel@165
    69
      this(name, index, sensorType, hardware, null, settings) { }
moel@1
    70
moel@134
    71
    public Sensor(string name, int index, SensorType sensorType,
moel@298
    72
      Hardware hardware, ParameterDescription[] parameterDescriptions, 
moel@165
    73
      ISettings settings) :
moel@134
    74
      this(name, index, false, sensorType, hardware,
moel@165
    75
        parameterDescriptions, settings) { }
moel@63
    76
moel@109
    77
    public Sensor(string name, int index, bool defaultHidden, 
moel@298
    78
      SensorType sensorType, Hardware hardware, 
moel@165
    79
      ParameterDescription[] parameterDescriptions, ISettings settings) 
moel@165
    80
    {           
moel@1
    81
      this.index = index;
moel@109
    82
      this.defaultHidden = defaultHidden;
moel@1
    83
      this.sensorType = sensorType;
moel@1
    84
      this.hardware = hardware;
moel@109
    85
      Parameter[] parameters = new Parameter[parameterDescriptions == null ?
moel@109
    86
        0 : parameterDescriptions.Length];
moel@63
    87
      for (int i = 0; i < parameters.Length; i++ ) 
moel@165
    88
        parameters[i] = new Parameter(parameterDescriptions[i], this, settings);
moel@63
    89
      this.parameters = parameters;
moel@63
    90
moel@165
    91
      this.settings = settings;
moel@165
    92
      this.defaultName = name; 
moel@166
    93
      this.name = settings.GetValue(
moel@165
    94
        new Identifier(Identifier, "name").ToString(), name);
moel@298
    95
moel@298
    96
      GetSensorValuesFromSettings();
moel@298
    97
moel@298
    98
      hardware.Closing += delegate(IHardware h) {
moel@298
    99
        SetSensorValuesToSettings();
moel@298
   100
      };
moel@298
   101
    }
moel@298
   102
moel@298
   103
    private void SetSensorValuesToSettings() {
moel@298
   104
      using (MemoryStream m = new MemoryStream()) {
moel@298
   105
        using (GZipStream c = new GZipStream(m, CompressionMode.Compress))
moel@298
   106
        using (BinaryWriter writer = new BinaryWriter(c)) {
moel@298
   107
          foreach (SensorValue sensorValue in values) {
moel@298
   108
            writer.Write(sensorValue.Time.ToBinary());
moel@298
   109
            writer.Write(sensorValue.Value);
moel@298
   110
          }
moel@298
   111
        }
moel@298
   112
        settings.SetValue(new Identifier(Identifier, "values").ToString(),
moel@298
   113
           Convert.ToBase64String(m.ToArray()));
moel@298
   114
      }
moel@298
   115
    }
moel@298
   116
moel@298
   117
    private void GetSensorValuesFromSettings() {
moel@298
   118
      string s = settings.GetValue(
moel@298
   119
        new Identifier(Identifier, "values").ToString(), null);
moel@298
   120
moel@298
   121
      byte[] array = null;
moel@298
   122
      try {
moel@298
   123
        array = Convert.FromBase64String(s);
moel@298
   124
        using (MemoryStream m = new MemoryStream(array))
moel@298
   125
        using (GZipStream c = new GZipStream(m, CompressionMode.Decompress))
moel@298
   126
        using (BinaryReader reader = new BinaryReader(c)) {
moel@298
   127
          try {
moel@298
   128
            while (true) {
moel@298
   129
              DateTime time = DateTime.FromBinary(reader.ReadInt64());
moel@298
   130
              float value = reader.ReadSingle();
moel@298
   131
              AppendValue(value, time);
moel@298
   132
            }
moel@298
   133
          } catch (EndOfStreamException) { }
moel@298
   134
        }
moel@298
   135
      } catch { }
moel@298
   136
      if (values.Count > 0)
moel@314
   137
        AppendValue(float.NaN, DateTime.UtcNow);
moel@298
   138
    }
moel@298
   139
moel@298
   140
    private void AppendValue(float value, DateTime time) {
moel@298
   141
      if (values.Count >= 2 && values.Last.Value == value && 
moel@298
   142
        values[values.Count - 2].Value == value) {
moel@298
   143
        values.Last = new SensorValue(value, time);
moel@298
   144
        return;
moel@298
   145
      } 
moel@298
   146
moel@298
   147
      values.Append(new SensorValue(value, time));
moel@1
   148
    }
moel@1
   149
moel@28
   150
    public IHardware Hardware {
moel@28
   151
      get { return hardware; }
moel@28
   152
    }
moel@28
   153
moel@1
   154
    public SensorType SensorType {
moel@1
   155
      get { return sensorType; }
moel@1
   156
    }
moel@1
   157
moel@109
   158
    public Identifier Identifier {
moel@28
   159
      get {
moel@166
   160
        return new Identifier(hardware.Identifier,
moel@166
   161
          sensorType.ToString().ToLowerInvariant(),
moel@166
   162
          index.ToString(CultureInfo.InvariantCulture));
moel@28
   163
      }
moel@28
   164
    }
moel@28
   165
moel@1
   166
    public string Name {
moel@1
   167
      get { 
moel@1
   168
        return name; 
moel@1
   169
      }
moel@1
   170
      set {
moel@167
   171
        if (!string.IsNullOrEmpty(value)) 
moel@1
   172
          name = value;          
moel@1
   173
        else 
moel@1
   174
          name = defaultName;
moel@166
   175
        settings.SetValue(new Identifier(Identifier, "name").ToString(), name);
moel@1
   176
      }
moel@1
   177
    }
moel@1
   178
moel@1
   179
    public int Index {
moel@1
   180
      get { return index; }
moel@1
   181
    }
moel@1
   182
moel@109
   183
    public bool IsDefaultHidden {
moel@109
   184
      get { return defaultHidden; }
moel@109
   185
    }
moel@109
   186
moel@63
   187
    public IReadOnlyArray<IParameter> Parameters {
moel@63
   188
      get { return parameters; }
moel@63
   189
    }
moel@63
   190
moel@1
   191
    public float? Value {
moel@1
   192
      get { 
moel@167
   193
        return currentValue; 
moel@1
   194
      }
moel@1
   195
      set {
moel@314
   196
        DateTime now = DateTime.UtcNow;
moel@298
   197
        while (values.Count > 0 && (now - values.First.Time).TotalDays > 1)
moel@298
   198
          values.Remove();
moel@1
   199
moel@1
   200
        if (value.HasValue) {
moel@1
   201
          sum += value.Value;
moel@1
   202
          count++;
moel@1
   203
          if (count == 4) {
moel@298
   204
            AppendValue(sum / count, now);
moel@1
   205
            sum = 0;
moel@1
   206
            count = 0;
moel@1
   207
          }
moel@1
   208
        }
moel@1
   209
moel@167
   210
        this.currentValue = value;
moel@167
   211
        if (minValue > value || !minValue.HasValue)
moel@167
   212
          minValue = value;
moel@167
   213
        if (maxValue < value || !maxValue.HasValue)
moel@167
   214
          maxValue = value;
moel@1
   215
      }
moel@1
   216
    }
moel@1
   217
moel@167
   218
    public float? Min { get { return minValue; } }
moel@167
   219
    public float? Max { get { return maxValue; } }
moel@1
   220
moel@151
   221
    public void ResetMin() {
moel@167
   222
      minValue = null;
moel@151
   223
    }
moel@151
   224
moel@151
   225
    public void ResetMax() {
moel@167
   226
      maxValue = null;
moel@151
   227
    }
moel@151
   228
moel@159
   229
    public IEnumerable<SensorValue> Values {
moel@159
   230
      get { return values; }
moel@159
   231
    }    
moel@110
   232
moel@110
   233
    public void Accept(IVisitor visitor) {
moel@167
   234
      if (visitor == null)
moel@167
   235
        throw new ArgumentNullException("visitor");
moel@167
   236
      visitor.VisitSensor(this);
moel@110
   237
    }
moel@110
   238
moel@110
   239
    public void Traverse(IVisitor visitor) {
moel@110
   240
      foreach (IParameter parameter in parameters)
moel@110
   241
        parameter.Accept(visitor);
moel@110
   242
    }
moel@247
   243
moel@247
   244
    public IControl Control {
moel@247
   245
      get {
moel@247
   246
        return control;
moel@247
   247
      }
moel@247
   248
      internal set {
moel@247
   249
        this.control = value;
moel@247
   250
      }
moel@247
   251
    }
moel@1
   252
  }
moel@1
   253
}