Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Sun, 01 Jan 2012 15:46:42 +0000
changeset 326 a41745e3828d
parent 324 c6ee430d6995
child 328 f837f9f0973e
permissions -rw-r--r--
Added a context menu to the plot which allows the user to configure the time window for plotting.
moel@324
     1
/*
moel@324
     2
  
moel@324
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@324
     4
moel@324
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@324
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@324
     7
  the License. You may obtain a copy of the License at
moel@324
     8
 
moel@324
     9
  http://www.mozilla.org/MPL/
moel@324
    10
moel@324
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@324
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@324
    13
  for the specific language governing rights and limitations under the License.
moel@324
    14
moel@324
    15
  The Original Code is the Open Hardware Monitor code.
moel@324
    16
moel@324
    17
  The Initial Developer of the Original Code is 
moel@324
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@325
    19
  Portions created by the Initial Developer are Copyright (C) 2009-2012
moel@324
    20
  the Initial Developer. All Rights Reserved.
moel@324
    21
moel@324
    22
  Contributor(s): 
moel@324
    23
    Paul Werelds
moel@324
    24
    Roland Reinl <roland-reinl@gmx.de>
moel@324
    25
moel@324
    26
  Alternatively, the contents of this file may be used under the terms of
moel@324
    27
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@324
    28
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@324
    29
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@324
    30
  of those above. If you wish to allow use of your version of this file only
moel@324
    31
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@324
    32
  use your version of this file under the terms of the MPL, indicate your
moel@324
    33
  decision by deleting the provisions above and replace them with the notice
moel@324
    34
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@324
    35
  the provisions above, a recipient may use your version of this file under
moel@324
    36
  the terms of any one of the MPL, the GPL or the LGPL.
moel@324
    37
 
moel@324
    38
*/
moel@324
    39
moel@324
    40
using System;
moel@324
    41
using System.Collections.Generic;
moel@324
    42
using System.Globalization;
moel@324
    43
using System.Text;
moel@324
    44
using OpenHardwareMonitor.Collections;
moel@324
    45
moel@324
    46
namespace OpenHardwareMonitor.Hardware.HDD {
moel@324
    47
  internal abstract class AbstractHarddrive : Hardware {
moel@324
    48
moel@324
    49
    private const int UPDATE_DIVIDER = 30; // update only every 30s
moel@324
    50
moel@324
    51
    // array of all harddrive types, matching type is searched in this order
moel@324
    52
    private static Type[] hddTypes = {       
moel@324
    53
      typeof(SSDPlextor),
moel@324
    54
      typeof(SSDIntel),
moel@324
    55
      typeof(SSDSandforce),
moel@324
    56
      typeof(SSDIndilinx),
moel@324
    57
      typeof(GenericHarddisk)
moel@324
    58
    };
moel@324
    59
moel@325
    60
    private string firmwareRevision;
moel@324
    61
    private readonly ISmart smart;
moel@324
    62
moel@324
    63
    private readonly IntPtr handle;
moel@324
    64
    private readonly int index;
moel@324
    65
    private int count;
moel@324
    66
moel@324
    67
    private IList<SmartAttribute> smartAttributes;
moel@324
    68
    private IDictionary<SmartAttribute, Sensor> sensors;
moel@324
    69
moel@325
    70
    protected AbstractHarddrive(ISmart smart, string name, 
moel@325
    71
      string firmwareRevision, int index, 
moel@324
    72
      IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
moel@324
    73
      : base(name, new Identifier("hdd",
moel@324
    74
        index.ToString(CultureInfo.InvariantCulture)), settings)
moel@324
    75
    {
moel@325
    76
      this.firmwareRevision = firmwareRevision;
moel@324
    77
      this.smart = smart;
moel@324
    78
      handle = smart.OpenDrive(index);
moel@324
    79
moel@324
    80
      smart.EnableSmart(handle, index);
moel@324
    81
moel@324
    82
      this.index = index;
moel@324
    83
      this.count = 0;
moel@324
    84
moel@324
    85
      this.smartAttributes = new List<SmartAttribute>(smartAttributes);
moel@324
    86
moel@324
    87
      CreateSensors();
moel@324
    88
    }
moel@324
    89
moel@324
    90
    public static AbstractHarddrive CreateInstance(ISmart smart, 
moel@324
    91
      int driveIndex, ISettings settings) 
moel@324
    92
    {
moel@324
    93
      IntPtr deviceHandle = smart.OpenDrive(driveIndex);
moel@324
    94
moel@324
    95
      if (deviceHandle == smart.InvalidHandle) 
moel@324
    96
        return null;
moel@324
    97
moel@325
    98
      string name;
moel@325
    99
      string firmwareRevision;
moel@325
   100
      bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
moel@325
   101
        driveIndex, out name, out firmwareRevision);
moel@324
   102
      bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
moel@324
   103
moel@324
   104
      DriveAttributeValue[] values = {};
moel@324
   105
      if (smartEnabled)
moel@324
   106
        values = smart.ReadSmartData(deviceHandle, driveIndex);
moel@324
   107
moel@324
   108
      smart.CloseHandle(deviceHandle);
moel@324
   109
moel@325
   110
      if (!nameValid || string.IsNullOrEmpty(name)) 
moel@324
   111
        return null;
moel@324
   112
moel@324
   113
      foreach (Type type in hddTypes) {
moel@324
   114
        // get the array of name prefixes for the current type
moel@324
   115
        NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
moel@324
   116
          typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
moel@324
   117
moel@324
   118
        // get the array of the required SMART attributes for the current type
moel@324
   119
        RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
moel@324
   120
          typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
moel@324
   121
moel@324
   122
        // check if all required attributes are present
moel@324
   123
        bool allRequiredAttributesFound = true;
moel@324
   124
        foreach (var requireAttribute in requiredAttributes) {
moel@324
   125
          bool adttributeFound = false;
moel@324
   126
          foreach (DriveAttributeValue value in values) {
moel@324
   127
            if (value.Identifier == requireAttribute.AttributeId) {
moel@324
   128
              adttributeFound = true;
moel@324
   129
              break;
moel@324
   130
            }
moel@324
   131
          }
moel@324
   132
          if (!adttributeFound) {
moel@324
   133
            allRequiredAttributesFound = false;
moel@324
   134
            break;
moel@324
   135
          }
moel@324
   136
        }
moel@324
   137
moel@324
   138
        // if an attribute is missing, then try the next type
moel@324
   139
        if (!allRequiredAttributesFound)
moel@324
   140
          continue;        
moel@324
   141
moel@324
   142
        // check if there is a matching name prefix for this type
moel@324
   143
        foreach (NamePrefixAttribute prefix in namePrefixes) {
moel@324
   144
          if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
moel@325
   145
            return Activator.CreateInstance(type, smart, name, firmwareRevision,
moel@325
   146
              driveIndex, settings) as AbstractHarddrive;
moel@324
   147
        }
moel@324
   148
      }
moel@324
   149
moel@324
   150
      // no matching type has been found
moel@324
   151
      return null;
moel@324
   152
    }
moel@324
   153
moel@324
   154
    private void CreateSensors() {
moel@324
   155
      sensors = new Dictionary<SmartAttribute, Sensor>();
moel@324
   156
moel@324
   157
      IList<Pair<SensorType, int>> sensorTypeAndChannels = 
moel@324
   158
        new List<Pair<SensorType, int>>();
moel@324
   159
moel@324
   160
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   161
moel@324
   162
      foreach (SmartAttribute attribute in smartAttributes) {
moel@324
   163
        if (!attribute.SensorType.HasValue) 
moel@324
   164
          continue;
moel@324
   165
moel@324
   166
        bool found = false;
moel@324
   167
        foreach (DriveAttributeValue value in values) {
moel@324
   168
          if (value.Identifier == attribute.Identifier) {
moel@324
   169
            found = true;
moel@324
   170
            break;
moel@324
   171
          }
moel@324
   172
        }
moel@324
   173
        if (!found)
moel@324
   174
          continue;
moel@324
   175
moel@324
   176
        Pair<SensorType, int> pair = new Pair<SensorType, int>(
moel@324
   177
          attribute.SensorType.Value, attribute.SensorChannel);
moel@324
   178
moel@324
   179
        if (!sensorTypeAndChannels.Contains(pair)) {
moel@324
   180
          Sensor sensor = new Sensor(attribute.Name, 
moel@324
   181
            attribute.SensorChannel, attribute.SensorType.Value, this, 
moel@324
   182
            settings);
moel@324
   183
moel@324
   184
          sensors.Add(attribute, sensor);
moel@324
   185
          sensorTypeAndChannels.Add(pair);
moel@324
   186
        }     
moel@324
   187
      }
moel@324
   188
    }
moel@324
   189
moel@324
   190
    public override HardwareType HardwareType {
moel@324
   191
      get { return HardwareType.HDD; }
moel@324
   192
    }
moel@324
   193
moel@324
   194
    public override ISensor[] Sensors {
moel@324
   195
      get {
moel@324
   196
        Sensor[] array = new Sensor[sensors.Count];
moel@324
   197
        sensors.Values.CopyTo(array, 0);
moel@324
   198
        return array;
moel@324
   199
      }
moel@324
   200
    }
moel@324
   201
moel@324
   202
    public override void Update() {
moel@324
   203
      if (count == 0) {
moel@324
   204
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   205
moel@324
   206
        foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
moel@324
   207
          SmartAttribute attribute = keyValuePair.Key;          
moel@324
   208
          foreach (DriveAttributeValue value in values) {
moel@324
   209
            if (value.Identifier == attribute.Identifier) {
moel@324
   210
              Sensor sensor = keyValuePair.Value;
moel@324
   211
              sensor.Value = attribute.ConvertValue(value);
moel@324
   212
            }
moel@324
   213
          }
moel@324
   214
        }        
moel@324
   215
      }
moel@324
   216
moel@324
   217
      count++; 
moel@324
   218
      count %= UPDATE_DIVIDER; 
moel@324
   219
    }
moel@324
   220
moel@324
   221
    public override string GetReport() {
moel@324
   222
      StringBuilder r = new StringBuilder();
moel@324
   223
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   224
      DriveThresholdValue[] thresholds = 
moel@324
   225
        smart.ReadSmartThresholds(handle, index);
moel@324
   226
moel@324
   227
      if (values.Length > 0) {
moel@324
   228
        r.AppendLine(this.GetType().Name);
moel@324
   229
        r.AppendLine();
moel@324
   230
        r.AppendLine("Drive name: " + name);
moel@325
   231
        r.AppendLine("Firmware version: " + firmwareRevision);
moel@324
   232
        r.AppendLine();
moel@324
   233
        r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   234
          " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   235
          ("ID").PadRight(3),
moel@324
   236
          ("Description").PadRight(32),
moel@324
   237
          ("Raw Value").PadRight(13),
moel@324
   238
          ("Worst").PadRight(6),
moel@324
   239
          ("Value").PadRight(6),
moel@324
   240
          ("Thres").PadRight(6),
moel@324
   241
          ("Physical").PadRight(8),
moel@324
   242
          Environment.NewLine);
moel@324
   243
moel@324
   244
        foreach (DriveAttributeValue value in values) {
moel@324
   245
          if (value.Identifier == 0x00) 
moel@324
   246
            break;
moel@324
   247
moel@324
   248
          byte? threshold = null;
moel@324
   249
          foreach (DriveThresholdValue t in thresholds) {
moel@324
   250
            if (t.Identifier == value.Identifier) {
moel@324
   251
              threshold = t.Threshold;
moel@324
   252
            }
moel@324
   253
          }
moel@324
   254
moel@324
   255
          string description = "Unknown";
moel@324
   256
          float? physical = null;
moel@324
   257
          foreach (SmartAttribute a in smartAttributes) {
moel@324
   258
            if (a.Identifier == value.Identifier) {
moel@324
   259
              description = a.Name;
moel@324
   260
              if (a.HasRawValueConversion | a.SensorType.HasValue)
moel@324
   261
                physical = a.ConvertValue(value);
moel@324
   262
              else
moel@324
   263
                physical = null;
moel@324
   264
            }
moel@324
   265
          }
moel@324
   266
moel@324
   267
          string raw = BitConverter.ToString(value.RawValue);
moel@324
   268
          r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   269
            " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   270
            value.Identifier.ToString("X2").PadRight(3),
moel@324
   271
            description.PadRight(32),
moel@324
   272
            raw.Replace("-", "").PadRight(13),
moel@324
   273
            value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   274
            value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   275
            (threshold.HasValue ? threshold.Value.ToString(
moel@324
   276
              CultureInfo.InvariantCulture) : "-").PadRight(6),
moel@324
   277
            (physical.HasValue ? physical.Value.ToString(
moel@324
   278
              CultureInfo.InvariantCulture) : "-").PadRight(8),
moel@324
   279
            Environment.NewLine);
moel@324
   280
        }
moel@324
   281
        r.AppendLine();
moel@324
   282
      }
moel@324
   283
moel@324
   284
      return r.ToString();
moel@324
   285
    }
moel@324
   286
moel@324
   287
    protected static float RawToInt(byte[] raw, byte value) {
moel@324
   288
      return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
moel@324
   289
    }
moel@324
   290
moel@324
   291
    public override void Close() {
moel@324
   292
      smart.CloseHandle(handle);
moel@324
   293
      base.Close();
moel@324
   294
    }
moel@324
   295
moel@324
   296
    public override void Traverse(IVisitor visitor) {
moel@324
   297
      foreach (ISensor sensor in Sensors)
moel@324
   298
        sensor.Accept(visitor);
moel@324
   299
    }
moel@324
   300
  }
moel@324
   301
}