Hardware/HDD/AbstractHarddrive.cs
author moel.mich
Sun, 08 Jul 2012 15:24:44 +0000
changeset 358 7962499f9cd6
parent 344 3145aadca3d2
child 369 5077ed7ddca8
permissions -rw-r--r--
Added support for SSDs with a controller from Micron.
moel@324
     1
/*
moel@324
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@324
     6
 
moel@344
     7
  Copyright (C) 2009-2012 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	Copyright (C) 2010 Paul Werelds
moel@344
     9
  Copyright (C) 2011 Roland Reinl <roland-reinl@gmx.de>
moel@344
    10
	
moel@324
    11
*/
moel@324
    12
moel@324
    13
using System;
moel@324
    14
using System.Collections.Generic;
moel@324
    15
using System.Globalization;
moel@324
    16
using System.Text;
moel@324
    17
using OpenHardwareMonitor.Collections;
moel@324
    18
moel@324
    19
namespace OpenHardwareMonitor.Hardware.HDD {
moel@324
    20
  internal abstract class AbstractHarddrive : Hardware {
moel@324
    21
moel@324
    22
    private const int UPDATE_DIVIDER = 30; // update only every 30s
moel@324
    23
moel@324
    24
    // array of all harddrive types, matching type is searched in this order
moel@324
    25
    private static Type[] hddTypes = {       
moel@324
    26
      typeof(SSDPlextor),
moel@324
    27
      typeof(SSDIntel),
moel@324
    28
      typeof(SSDSandforce),
moel@324
    29
      typeof(SSDIndilinx),
moel@328
    30
      typeof(SSDSamsung),
moel@358
    31
      typeof(SSDMicron),
moel@324
    32
      typeof(GenericHarddisk)
moel@324
    33
    };
moel@324
    34
moel@325
    35
    private string firmwareRevision;
moel@324
    36
    private readonly ISmart smart;
moel@324
    37
moel@324
    38
    private readonly IntPtr handle;
moel@324
    39
    private readonly int index;
moel@324
    40
    private int count;
moel@324
    41
moel@324
    42
    private IList<SmartAttribute> smartAttributes;
moel@324
    43
    private IDictionary<SmartAttribute, Sensor> sensors;
moel@324
    44
moel@325
    45
    protected AbstractHarddrive(ISmart smart, string name, 
moel@325
    46
      string firmwareRevision, int index, 
moel@324
    47
      IEnumerable<SmartAttribute> smartAttributes, ISettings settings) 
moel@324
    48
      : base(name, new Identifier("hdd",
moel@324
    49
        index.ToString(CultureInfo.InvariantCulture)), settings)
moel@324
    50
    {
moel@325
    51
      this.firmwareRevision = firmwareRevision;
moel@324
    52
      this.smart = smart;
moel@324
    53
      handle = smart.OpenDrive(index);
moel@324
    54
moel@324
    55
      smart.EnableSmart(handle, index);
moel@324
    56
moel@324
    57
      this.index = index;
moel@324
    58
      this.count = 0;
moel@324
    59
moel@324
    60
      this.smartAttributes = new List<SmartAttribute>(smartAttributes);
moel@324
    61
moel@324
    62
      CreateSensors();
moel@324
    63
    }
moel@324
    64
moel@324
    65
    public static AbstractHarddrive CreateInstance(ISmart smart, 
moel@324
    66
      int driveIndex, ISettings settings) 
moel@324
    67
    {
moel@324
    68
      IntPtr deviceHandle = smart.OpenDrive(driveIndex);
moel@324
    69
moel@324
    70
      if (deviceHandle == smart.InvalidHandle) 
moel@324
    71
        return null;
moel@324
    72
moel@325
    73
      string name;
moel@325
    74
      string firmwareRevision;
moel@325
    75
      bool nameValid = smart.ReadNameAndFirmwareRevision(deviceHandle, 
moel@325
    76
        driveIndex, out name, out firmwareRevision);
moel@324
    77
      bool smartEnabled = smart.EnableSmart(deviceHandle, driveIndex);
moel@324
    78
moel@324
    79
      DriveAttributeValue[] values = {};
moel@324
    80
      if (smartEnabled)
moel@324
    81
        values = smart.ReadSmartData(deviceHandle, driveIndex);
moel@324
    82
moel@324
    83
      smart.CloseHandle(deviceHandle);
moel@324
    84
moel@325
    85
      if (!nameValid || string.IsNullOrEmpty(name)) 
moel@324
    86
        return null;
moel@324
    87
moel@324
    88
      foreach (Type type in hddTypes) {
moel@324
    89
        // get the array of name prefixes for the current type
moel@324
    90
        NamePrefixAttribute[] namePrefixes = type.GetCustomAttributes(
moel@324
    91
          typeof(NamePrefixAttribute), true) as NamePrefixAttribute[];
moel@324
    92
moel@324
    93
        // get the array of the required SMART attributes for the current type
moel@324
    94
        RequireSmartAttribute[] requiredAttributes = type.GetCustomAttributes(
moel@324
    95
          typeof(RequireSmartAttribute), true) as RequireSmartAttribute[];
moel@324
    96
moel@324
    97
        // check if all required attributes are present
moel@324
    98
        bool allRequiredAttributesFound = true;
moel@324
    99
        foreach (var requireAttribute in requiredAttributes) {
moel@324
   100
          bool adttributeFound = false;
moel@324
   101
          foreach (DriveAttributeValue value in values) {
moel@324
   102
            if (value.Identifier == requireAttribute.AttributeId) {
moel@324
   103
              adttributeFound = true;
moel@324
   104
              break;
moel@324
   105
            }
moel@324
   106
          }
moel@324
   107
          if (!adttributeFound) {
moel@324
   108
            allRequiredAttributesFound = false;
moel@324
   109
            break;
moel@324
   110
          }
moel@324
   111
        }
moel@324
   112
moel@324
   113
        // if an attribute is missing, then try the next type
moel@324
   114
        if (!allRequiredAttributesFound)
moel@324
   115
          continue;        
moel@324
   116
moel@324
   117
        // check if there is a matching name prefix for this type
moel@324
   118
        foreach (NamePrefixAttribute prefix in namePrefixes) {
moel@324
   119
          if (name.StartsWith(prefix.Prefix, StringComparison.InvariantCulture)) 
moel@325
   120
            return Activator.CreateInstance(type, smart, name, firmwareRevision,
moel@325
   121
              driveIndex, settings) as AbstractHarddrive;
moel@324
   122
        }
moel@324
   123
      }
moel@324
   124
moel@324
   125
      // no matching type has been found
moel@324
   126
      return null;
moel@324
   127
    }
moel@324
   128
moel@324
   129
    private void CreateSensors() {
moel@324
   130
      sensors = new Dictionary<SmartAttribute, Sensor>();
moel@324
   131
moel@324
   132
      IList<Pair<SensorType, int>> sensorTypeAndChannels = 
moel@324
   133
        new List<Pair<SensorType, int>>();
moel@324
   134
moel@324
   135
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   136
moel@324
   137
      foreach (SmartAttribute attribute in smartAttributes) {
moel@324
   138
        if (!attribute.SensorType.HasValue) 
moel@324
   139
          continue;
moel@324
   140
moel@324
   141
        bool found = false;
moel@324
   142
        foreach (DriveAttributeValue value in values) {
moel@324
   143
          if (value.Identifier == attribute.Identifier) {
moel@324
   144
            found = true;
moel@324
   145
            break;
moel@324
   146
          }
moel@324
   147
        }
moel@324
   148
        if (!found)
moel@324
   149
          continue;
moel@324
   150
moel@324
   151
        Pair<SensorType, int> pair = new Pair<SensorType, int>(
moel@324
   152
          attribute.SensorType.Value, attribute.SensorChannel);
moel@324
   153
moel@324
   154
        if (!sensorTypeAndChannels.Contains(pair)) {
moel@324
   155
          Sensor sensor = new Sensor(attribute.Name, 
moel@340
   156
            attribute.SensorChannel, attribute.DefaultHiddenSensor, 
moel@340
   157
            attribute.SensorType.Value, this, null, settings);
moel@324
   158
moel@324
   159
          sensors.Add(attribute, sensor);
moel@339
   160
          ActivateSensor(sensor);
moel@324
   161
          sensorTypeAndChannels.Add(pair);
moel@324
   162
        }     
moel@324
   163
      }
moel@324
   164
    }
moel@324
   165
moel@324
   166
    public override HardwareType HardwareType {
moel@324
   167
      get { return HardwareType.HDD; }
moel@324
   168
    }
moel@324
   169
moel@339
   170
    public virtual void UpdateAdditionalSensors(DriveAttributeValue[] values) {}
moel@324
   171
moel@324
   172
    public override void Update() {
moel@324
   173
      if (count == 0) {
moel@324
   174
        DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   175
moel@324
   176
        foreach (KeyValuePair<SmartAttribute, Sensor> keyValuePair in sensors) {
moel@324
   177
          SmartAttribute attribute = keyValuePair.Key;          
moel@324
   178
          foreach (DriveAttributeValue value in values) {
moel@324
   179
            if (value.Identifier == attribute.Identifier) {
moel@324
   180
              Sensor sensor = keyValuePair.Value;
moel@324
   181
              sensor.Value = attribute.ConvertValue(value);
moel@324
   182
            }
moel@324
   183
          }
moel@339
   184
        }
moel@339
   185
moel@339
   186
        UpdateAdditionalSensors(values);
moel@324
   187
      }
moel@324
   188
moel@324
   189
      count++; 
moel@324
   190
      count %= UPDATE_DIVIDER; 
moel@324
   191
    }
moel@324
   192
moel@324
   193
    public override string GetReport() {
moel@324
   194
      StringBuilder r = new StringBuilder();
moel@324
   195
      DriveAttributeValue[] values = smart.ReadSmartData(handle, index);
moel@324
   196
      DriveThresholdValue[] thresholds = 
moel@324
   197
        smart.ReadSmartThresholds(handle, index);
moel@324
   198
moel@324
   199
      if (values.Length > 0) {
moel@324
   200
        r.AppendLine(this.GetType().Name);
moel@324
   201
        r.AppendLine();
moel@324
   202
        r.AppendLine("Drive name: " + name);
moel@325
   203
        r.AppendLine("Firmware version: " + firmwareRevision);
moel@324
   204
        r.AppendLine();
moel@324
   205
        r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   206
          " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   207
          ("ID").PadRight(3),
moel@328
   208
          ("Description").PadRight(35),
moel@324
   209
          ("Raw Value").PadRight(13),
moel@324
   210
          ("Worst").PadRight(6),
moel@324
   211
          ("Value").PadRight(6),
moel@324
   212
          ("Thres").PadRight(6),
moel@324
   213
          ("Physical").PadRight(8),
moel@324
   214
          Environment.NewLine);
moel@324
   215
moel@324
   216
        foreach (DriveAttributeValue value in values) {
moel@324
   217
          if (value.Identifier == 0x00) 
moel@324
   218
            break;
moel@324
   219
moel@324
   220
          byte? threshold = null;
moel@324
   221
          foreach (DriveThresholdValue t in thresholds) {
moel@324
   222
            if (t.Identifier == value.Identifier) {
moel@324
   223
              threshold = t.Threshold;
moel@324
   224
            }
moel@324
   225
          }
moel@324
   226
moel@324
   227
          string description = "Unknown";
moel@324
   228
          float? physical = null;
moel@324
   229
          foreach (SmartAttribute a in smartAttributes) {
moel@324
   230
            if (a.Identifier == value.Identifier) {
moel@324
   231
              description = a.Name;
moel@324
   232
              if (a.HasRawValueConversion | a.SensorType.HasValue)
moel@324
   233
                physical = a.ConvertValue(value);
moel@324
   234
              else
moel@324
   235
                physical = null;
moel@324
   236
            }
moel@324
   237
          }
moel@324
   238
moel@324
   239
          string raw = BitConverter.ToString(value.RawValue);
moel@324
   240
          r.AppendFormat(CultureInfo.InvariantCulture, 
moel@324
   241
            " {0}{1}{2}{3}{4}{5}{6}{7}",
moel@324
   242
            value.Identifier.ToString("X2").PadRight(3),
moel@328
   243
            description.PadRight(35),
moel@324
   244
            raw.Replace("-", "").PadRight(13),
moel@324
   245
            value.WorstValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   246
            value.AttrValue.ToString(CultureInfo.InvariantCulture).PadRight(6),
moel@324
   247
            (threshold.HasValue ? threshold.Value.ToString(
moel@324
   248
              CultureInfo.InvariantCulture) : "-").PadRight(6),
moel@324
   249
            (physical.HasValue ? physical.Value.ToString(
moel@324
   250
              CultureInfo.InvariantCulture) : "-").PadRight(8),
moel@324
   251
            Environment.NewLine);
moel@324
   252
        }
moel@324
   253
        r.AppendLine();
moel@324
   254
      }
moel@324
   255
moel@324
   256
      return r.ToString();
moel@324
   257
    }
moel@324
   258
moel@324
   259
    protected static float RawToInt(byte[] raw, byte value) {
moel@324
   260
      return (raw[3] << 24) | (raw[2] << 16) | (raw[1] << 8) | raw[0];
moel@324
   261
    }
moel@324
   262
moel@324
   263
    public override void Close() {
moel@324
   264
      smart.CloseHandle(handle);
moel@324
   265
      base.Close();
moel@324
   266
    }
moel@324
   267
moel@324
   268
    public override void Traverse(IVisitor visitor) {
moel@324
   269
      foreach (ISensor sensor in Sensors)
moel@324
   270
        sensor.Accept(visitor);
moel@324
   271
    }
moel@324
   272
  }
moel@324
   273
}